summaryrefslogtreecommitdiff
path: root/src/actions.c
diff options
context:
space:
mode:
authorShawn <sabetts@juicebox>2008-11-01 10:29:44 -0700
committerShawn <sabetts@juicebox>2008-11-01 10:29:44 -0700
commit75207d2e878250c2717174a22cc828c0aba5ba76 (patch)
tree3d81a201bb346e364c770367833ee52b15067601 /src/actions.c
parentc0bee97912e5caf256441dbdc531f38fbe06d780 (diff)
downloadratpoison-75207d2e878250c2717174a22cc828c0aba5ba76.zip
fix (i hope) the tmpwm race condition and the bug that sometimes keys don't work after tmpwm
the race condition is fixed by spinning in a loop with a special error handler until it is confirmed that the root event selections were successfully. Existing windows don't get their top level keys grabbed, so after the windows are synced up, grab the top level keys on all windows.
Diffstat (limited to 'src/actions.c')
-rw-r--r--src/actions.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/src/actions.c b/src/actions.c
index 120d106..136d114 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -27,6 +27,7 @@
#include <time.h>
#include <errno.h>
#include <signal.h>
+#include <X11/Xproto.h>
#include "ratpoison.h"
@@ -4594,6 +4595,19 @@ sync_wins (rp_screen *s)
}
+static int tmpwm_error_raised = 0;
+
+static int
+tmpwm_error_handler (Display *d, XErrorEvent *e)
+{
+ if (e->request_code == X_ChangeWindowAttributes && e->error_code == BadAccess)
+ {
+ PRINT_DEBUG (("failed to grab root properties\n"));
+ tmpwm_error_raised++;
+ }
+ return 0;
+}
+
/* Temporarily give control over to another window manager, reclaiming */
/* control when that WM terminates. */
cmdret *
@@ -4605,6 +4619,7 @@ cmd_tmpwm (int interactive, struct cmdarg **args)
int status;
int pid;
int i;
+ int (*old_handler)(Display *, XErrorEvent *);
push_frame_undo (current_screen()); /* fdump to stack */
@@ -4648,28 +4663,37 @@ cmd_tmpwm (int interactive, struct cmdarg **args)
disabled, so check for them. */
check_child_procs();
- /* This xsync seems to be needed. Otherwise, the following code dies
- because X thinks another WM is running. */
- XSync (dpy, False);
+ /* Enable the event selection on the root window. We need to loop
+ until we don't get an X error. This is due to a race between the
+ X server cleaning up after the temporary wm and ratpoison
+ grabbing events. */
+ old_handler = XSetErrorHandler (tmpwm_error_handler);
+ do {
+ tmpwm_error_raised = 0;
+ for (i=0; i<num_screens; i++)
+ {
+ XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num),
+ PropertyChangeMask | ColormapChangeMask
+ | SubstructureRedirectMask | SubstructureNotifyMask
+ | StructureNotifyMask);
+ XSync (dpy, False);
+ }
+ } while (tmpwm_error_raised);
+ XSetErrorHandler (old_handler);
- /* Enable the event selection on the root window. */
+ /* Map the key windows. */
for (i=0; i<num_screens; i++)
- {
- XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num),
- PropertyChangeMask | ColormapChangeMask
- | SubstructureRedirectMask | SubstructureNotifyMask
- | StructureNotifyMask);
- /* Map its key window */
- XMapWindow (dpy, screens[i].key_window);
- }
- XSync (dpy, False);
+ XMapWindow (dpy, screens[i].key_window);
/* Sort through all the windows in each group and pick out the ones
that are unmapped or destroyed. */
for (i=0; i<num_screens; i++)
- {
- sync_wins (&screens[i]);
- }
+ sync_wins (&screens[i]);
+
+ /* At this point, new windows have the top level keys grabbed but
+ existing windows don't. So grab them on all windows just to be
+ sure. */
+ grab_keys_all_wins();
/* If no window has focus, give the key_window focus. */
if (current_window())