+}
+
+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);
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static void event_process(const XEvent *ec, gpointer data)
+{
+ Window window;
+ ObGroup *group = NULL;
+ ObClient *client = NULL;
+ ObDock *dock = NULL;
+ ObDockApp *dockapp = NULL;
+ ObWindow *obwin = NULL;
+ XEvent ee, *e;
+ ObEventData *ed = data;
+
+ /* make a copy we can mangle */
+ ee = *ec;
+ e = ⅇ
+
+ window = event_get_window(e);
+ if (!(e->type == PropertyNotify &&
+ (group = g_hash_table_lookup(group_map, &window))))
+ if ((obwin = g_hash_table_lookup(window_map, &window))) {
+ switch (obwin->type) {
+ case Window_Dock:
+ dock = WINDOW_AS_DOCK(obwin);
+ break;
+ case Window_DockApp:
+ dockapp = WINDOW_AS_DOCKAPP(obwin);
+ break;
+ case Window_Client:
+ client = WINDOW_AS_CLIENT(obwin);
+ break;
+ case Window_Menu:
+ case Window_Internal:
+ /* not to be used for events */
+ g_assert_not_reached();
+ break;
+ }
+ }