+ /* if more event types are anticipated, get their timestamp
+ explicitly */
+ break;
+ }
+
+ if (t > event_lasttime)
+ event_lasttime = t;
+}
+
+#define STRIP_MODS(s) \
+ s &= ~(LockMask | NumLockMask | ScrollLockMask), \
+ /* kill off the Button1Mask etc, only want the modifiers */ \
+ s &= (ControlMask | ShiftMask | Mod1Mask | \
+ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
+
+static void event_hack_mods(XEvent *e)
+{
+#ifdef XKB
+ XkbStateRec xkb_state;
+#endif
+ KeyCode *kp;
+ gint i, k;
+
+ switch (e->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ STRIP_MODS(e->xbutton.state);
+ break;
+ case KeyPress:
+ STRIP_MODS(e->xkey.state);
+ break;
+ case KeyRelease:
+ STRIP_MODS(e->xkey.state);
+ /* remove from the state the mask of the modifier being released, if
+ it is a modifier key being released (this is a little ugly..) */
+#ifdef XKB
+ if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) {
+ e->xkey.state = xkb_state.compat_state;
+ break;
+ }
+#endif
+ kp = modmap->modifiermap;
+ for (i = 0; i < mask_table_size; ++i) {
+ for (k = 0; k < modmap->max_keypermod; ++k) {
+ if (*kp == e->xkey.keycode) { /* found the keycode */
+ /* remove the mask for it */
+ e->xkey.state &= ~mask_table[i];
+ /* cause the first loop to break; */
+ i = mask_table_size;
+ break; /* get outta here! */
+ }
+ ++kp;
+ }
+ }
+ break;
+ case MotionNotify:
+ STRIP_MODS(e->xmotion.state);
+ /* compress events */
+ {
+ XEvent ce;
+ while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
+ e->type, &ce)) {
+ e->xmotion.x_root = ce.xmotion.x_root;
+ e->xmotion.y_root = ce.xmotion.y_root;
+ }
+ }
+ break;
+ }
+}
+
+static gboolean event_ignore(XEvent *e, ObClient *client)
+{
+ switch(e->type) {
+ case EnterNotify:
+ case LeaveNotify:
+ if (e->xcrossing.detail == NotifyInferior)
+ return TRUE;
+ break;
+ case FocusIn:
+ /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut
+ because of RevertToPointerRoot. If the focus ends up reverting to
+ pointer root on a workspace change, then the FocusIn event that we
+ want will be of type NotifyAncestor. This situation does not occur
+ for FocusOut, so it is safely ignored there.
+ */
+ if (INVALID_FOCUSIN(e) ||
+ client == NULL) {
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
+ e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
+#endif
+ /* says a client was not found for the event (or a valid FocusIn
+ event was not found.
+ */
+ e->xfocus.window = None;
+ return TRUE;
+ }
+
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window,
+ e->xfocus.mode, e->xfocus.detail);
+#endif
+ break;
+ case FocusOut:
+ if (INVALID_FOCUSOUT(e)) {
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n",
+ e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
+#endif
+ return TRUE;
+ }
+
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusOut on %lx mode %d detail %d\n",
+ e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
+#endif
+ {
+ XEvent fe;
+ gboolean fallback = TRUE;
+
+ while (TRUE) {
+ if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window,
+ FocusOut, &fe))
+ if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
+ break;
+ if (fe.type == FocusOut) {
+#ifdef DEBUG_FOCUS
+ ob_debug("found pending FocusOut\n");
+#endif
+ if (!INVALID_FOCUSOUT(&fe)) {
+ /* if there is a VALID FocusOut still coming, don't
+ fallback focus yet, we'll deal with it then */
+ XPutBackEvent(ob_display, &fe);
+ fallback = FALSE;
+ break;
+ }
+ } else {
+#ifdef DEBUG_FOCUS
+ ob_debug("found pending FocusIn\n");
+#endif
+ /* is the focused window getting a FocusOut/In back to
+ itself?
+ */
+ if (fe.xfocus.window == e->xfocus.window &&
+ !event_ignore(&fe, client)) {
+ /*
+ if focus_client is not set, then we can't do
+ this. we need the FocusIn. This happens in the
+ case when the set_focus_client(NULL) in the
+ focus_fallback function fires and then
+ focus_fallback picks the currently focused
+ window (such as on a SendToDesktop-esque action.
+ */
+ if (focus_client) {
+#ifdef DEBUG_FOCUS
+ ob_debug("focused window got an Out/In back to "
+ "itself IGNORED both\n");
+#endif
+ return TRUE;
+ } else {
+ event_process(&fe, NULL);
+#ifdef DEBUG_FOCUS
+ ob_debug("focused window got an Out/In back to "
+ "itself but focus_client was null "
+ "IGNORED just the Out\n");
+#endif
+ return TRUE;
+ }
+ }
+
+ {
+ ObEventData d;
+
+ /* once all the FocusOut's have been dealt with, if
+ there is a FocusIn still left and it is valid, then
+ use it */
+ event_process(&fe, &d);
+ if (!d.ignored) {
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusIn was OK, so don't fallback\n");
+#endif
+ fallback = FALSE;
+ break;
+ }
+ }
+ }
+ }
+ if (fallback) {
+#ifdef DEBUG_FOCUS
+ ob_debug("no valid FocusIn and no FocusOut events found, "
+ "falling back\n");
+#endif
+ focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
+ }
+ }