super correct enter event ignoring that will only ignore what it has to, yay?
authorDana Jansens <danakj@orodu.net>
Fri, 18 May 2007 00:11:01 +0000 (00:11 +0000)
committerDana Jansens <danakj@orodu.net>
Fri, 18 May 2007 00:11:01 +0000 (00:11 +0000)
openbox/action.c
openbox/client.c
openbox/client_menu.c
openbox/event.c
openbox/event.h
openbox/focus.c
openbox/popup.c
openbox/screen.c

index 0a2d2b6..2fd0372 100644 (file)
@@ -46,8 +46,8 @@ static void client_action_end(union ActionData *data)
 {
     if (config_focus_follow)
         if (data->any.context != OB_FRAME_CONTEXT_CLIENT) {
-            if (!data->any.button) {
-                event_ignore_queued_enters();
+            if (!data->any.button && data->any.c) {
+                event_ignore_enters_leaving_window(data->any.c);
             } else {
                 ObClient *c;
 
index b0482fa..34af084 100644 (file)
@@ -565,7 +565,7 @@ void client_unmanage(ObClient *self)
 
     /* ignore enter events from the unmap so it doesnt mess with the
        focus */
-    event_ignore_queued_enters();
+    event_ignore_enters_leaving_window(self);
 
     mouse_grab_for_client(self, FALSE);
 
index 6fa744c..db00265 100644 (file)
@@ -119,19 +119,15 @@ static void client_menu_execute(ObMenuEntry *e, ObMenuFrame *f,
         break;
     case CLIENT_RESTORE:
         client_maximize(c, FALSE, 0);
-        event_ignore_queued_enters();
         break;
     case CLIENT_MAXIMIZE:
         client_maximize(c, TRUE, 0);
-        event_ignore_queued_enters();
         break;
     case CLIENT_SHADE:
         client_shade(c, !c->shaded);
-        event_ignore_queued_enters();
         break;
     case CLIENT_DECORATE:
         client_set_undecorated(c, !c->undecorated);
-        event_ignore_queued_enters();
         break;
     case CLIENT_MOVE:
         /* this needs to grab the keyboard so hide the menu */
@@ -158,6 +154,10 @@ static void client_menu_execute(ObMenuEntry *e, ObMenuFrame *f,
         g_assert_not_reached();
     }
 
+    /* we have to ignore all queued enters because the menu has a grab, and the
+       so the cursor isnt considered inside the client's window */
+    event_ignore_all_queued_enters();
+
     /* update the menu cuz stuff can have changed */
     if (f) {
         client_menu_update(f, NULL);
@@ -217,7 +217,9 @@ static void layer_menu_execute(ObMenuEntry *e, ObMenuFrame *f,
         g_assert_not_reached();
     }
 
-    event_ignore_queued_enters();
+    /* we have to ignore all queued enters because the menu has a grab, and the
+       so the cursor isnt considered inside the client's window */
+    event_ignore_all_queued_enters();
 
     /* update the menu cuz stuff can have changed */
     if (f) {
index 99fa955..383b260 100644 (file)
@@ -85,6 +85,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e);
 static void event_handle_client(ObClient *c, XEvent *e);
 static void event_handle_user_time_window_clients(GSList *l, XEvent *e);
 static void event_handle_user_input(ObClient *client, XEvent *e);
+static gboolean is_enter_focus_event_ignored(XEvent *e);
 
 static void focus_delay_dest(gpointer data);
 static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
@@ -96,7 +97,11 @@ static gboolean menu_hide_delay_func(gpointer data);
 /* The time for the current event being processed */
 Time event_curtime = CurrentTime;
 
+#define NUM_IGNORE_SERIALS 20
+
 static guint ignore_enter_focus = 0;
+/*! This is a 0 terminated list of ignored serials */
+static gulong ignore_enter_serials[NUM_IGNORE_SERIALS+1] = {0};
 static gboolean menu_can_hide;
 static gboolean focus_left_screen = FALSE;
 
@@ -883,7 +888,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                corresponding enter events. Pretend like the animating window
                doesn't even exist..! */
             if (frame_iconify_animating(client->frame))
-                event_ignore_queued_enters();
+                event_ignore_enters_leaving_window(client);
 
             ob_debug_type(OB_DEBUG_FOCUS,
                           "%sNotify mode %d detail %d on %lx\n",
@@ -911,10 +916,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
     {
         gboolean nofocus = FALSE;
 
-        if (ignore_enter_focus) {
-            ignore_enter_focus--;
+        if (is_enter_focus_event_ignored(e))
             nofocus = TRUE;
-        }
 
         con = frame_context(client, e->xcrossing.window,
                             e->xcrossing.x, e->xcrossing.y);
@@ -1084,7 +1087,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             client_configure(client, x, y, w, h, FALSE, TRUE);
 
             /* ignore enter events caused by these like ob actions do */
-            event_ignore_queued_enters();
+            event_ignore_enters_leaving_window(client);
         }
         break;
     }
@@ -1180,7 +1183,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                              e->xclient.data.l[1], e->xclient.data.l[2]);
 
             /* ignore enter events caused by these like ob actions do */
-            event_ignore_queued_enters();
+            event_ignore_enters_leaving_window(client);
         } else if (msgtype == prop_atoms.net_close_window) {
             ob_debug("net_close_window for 0x%lx\n", client->window);
             client_close(client);
@@ -1268,7 +1271,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             client_configure(client, x, y, w, h, FALSE, TRUE);
 
             /* ignore enter events caused by these like ob actions do */
-            event_ignore_queued_enters();
+            event_ignore_enters_leaving_window(client);
         } else if (msgtype == prop_atoms.net_restack_window) {
             if (e->xclient.data.l[0] != 2) {
                 ob_debug_type(OB_DEBUG_APP_BUGS,
@@ -1717,30 +1720,90 @@ void event_halt_focus_delay()
     ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
 }
 
+struct ObLookForEnters
+{
+    ObClient *c;
+    gulong looking_for_enter;
+};
+
 static Bool event_look_for_enters(Display *d, XEvent *e, XPointer arg)
 {
-    guint *count = (guint*)arg;
-    if (e->type == EnterNotify) {
+    struct ObLookForEnters *lfe = (struct ObLookForEnters*)arg;
+
+    if (lfe->c != NULL && e->type == LeaveNotify) {
+        if (g_hash_table_lookup(window_map, &e->xany.window) == lfe->c)
+            /* found an event leaving this window */
+            lfe->looking_for_enter = e->xany.serial;
+    } else if (e->type == EnterNotify &&
+               (lfe->c == NULL || e->xany.serial == lfe->looking_for_enter))
+    {
         ObWindow *win;
-            
-        win = g_hash_table_lookup(window_map, &e->xany.window);
-        if (win && WINDOW_IS_CLIENT(win))
-            ++(*count);
+        gint i;
+        gboolean ignored = FALSE;
+
+        /* make sure the serial isn't already being ignored */
+        for (i = 0; ignore_enter_serials[i] != 0 && !ignored; ++i) {
+            if (ignore_enter_serials[i] == e->xany.serial)
+                ignored = TRUE;
+        }
+
+        if (!ignored) {
+            /* found an enter for that leave, ignore it if it's going to
+               another window */
+            win = g_hash_table_lookup(window_map, &e->xany.window);
+            if (win && WINDOW_IS_CLIENT(win))
+                ++ignore_enter_focus;
+        }
+
+        /* add it to the ignored list if there is room */
+        if (i < NUM_IGNORE_SERIALS) {
+            ignore_enter_serials[i] = e->xany.serial;
+            ignore_enter_serials[i+1] = 0;
+        }
     }
     return False; /* don't disrupt the queue order, just count them */
 }
 
-void event_ignore_queued_enters()
+void event_ignore_all_queued_enters()
 {
+    event_ignore_enters_leaving_window(NULL);
+}
+
+void event_ignore_enters_leaving_window(ObClient *c)
+{
+    struct ObLookForEnters lfe;
     XEvent e;
-                
+
     XSync(ob_display, FALSE);
 
     /* count the events without disrupting them */
     ignore_enter_focus = 0;
-    XCheckIfEvent(ob_display, &e, event_look_for_enters,
-                  (XPointer)&ignore_enter_focus);
+    lfe.c = c;
+    lfe.looking_for_enter = 0;
+    XCheckIfEvent(ob_display, &e, event_look_for_enters, (XPointer)&lfe);
+
+}
+
+static gboolean is_enter_focus_event_ignored(XEvent *e)
+{
+    g_assert(e->type == EnterNotify);
 
+    if (ignore_enter_focus) {
+        gint i;
+
+        --ignore_enter_focus;
+
+        /* remove the serial */
+        for (i = 0; ignore_enter_serials[i] != 0; ++i) {
+            if (ignore_enter_serials[i] == e->xany.serial) {
+                for (; ignore_enter_serials[i+1] != 0; ++i)
+                    ignore_enter_serials[i] = ignore_enter_serials[i+1];
+                ignore_enter_serials[i] = 0;
+            }
+        }
+        return TRUE;
+    }
+    return FALSE;
 }
 
 gboolean event_time_after(Time t1, Time t2)
index 4fdf292..f794039 100644 (file)
@@ -39,9 +39,13 @@ void event_shutdown(gboolean reconfig);
   follows mouse */
 void event_enter_client(struct _ObClient *client);
 
-/*! Request that any queued EnterNotify events not be used for distributing
-  focus */
-void event_ignore_queued_enters();
+/*! Make mouse focus not move if the mouse leaves this client from what
+  has just transpired. */
+void event_ignore_enters_leaving_window(struct _ObClient *c);
+
+/*! Make mouse focus not move at all from the stuff that has happened up
+  till now. */
+void event_ignore_all_queued_enters();
 
 /* Halts any focus delay in progress, use this when the user is selecting a
    window for focus */
index 301e5dd..e88b688 100644 (file)
@@ -425,7 +425,7 @@ void focus_cycle_draw_indicator()
         XUnmapWindow(ob_display, focus_indicator.bottom.win);
 
         /* kill enter events cause by this unmapping */
-        event_ignore_queued_enters();
+        event_ignore_all_queued_enters();
     } else {
         /*
           if (focus_cycle_target)
index 91c1849..2768ee2 100644 (file)
@@ -269,7 +269,7 @@ void popup_hide(ObPopup *self)
         self->mapped = FALSE;
 
         /* kill enter events cause by this unmapping */
-        event_ignore_queued_enters();
+        event_ignore_all_queued_enters();
     } else if (self->delay_mapped) {
         ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
         self->delay_mapped = FALSE;
index a72bd7e..6551da8 100644 (file)
@@ -523,7 +523,7 @@ void screen_set_desktop(guint num, gboolean dofocus)
         }
     }
 
-    event_ignore_queued_enters();
+    event_ignore_all_queued_enters();
 
     if (event_curtime != CurrentTime)
         screen_desktop_user_time = event_curtime;