$OpenBSD: patch-src_handlers_c,v 1.7 2012/01/25 10:29:30 dcoppa Exp $

Bugfix: respect WM_HINTS.input for WM_TAKE_FOCUS clients. This fixes
problems with some Qt apps
(upstream git commit 2d14ced024416e2074b57290bf7dade7d08899e5)

Bugfix: only ignore EnterNotify events after UnmapNotifies from
managed windows. This fixes some focus follows mouse problems
(upstream git commit 47fd15649ad63f3becef8870276e51c6214300fc)

Bugfix: force a new sequence number after UnmapNotify. This fixes
the problem where legitimate EnterNotify arrived with the same
sequence as the UnmapNotify and was ignored
(upstream git commit 7a4d8ed6ed67c4d0d958458f58e4db1598c9cd75)

--- src/handlers.c.orig	Mon Jan 23 09:50:24 2012
+++ src/handlers.c	Mon Jan 23 09:51:06 2012
@@ -457,23 +457,9 @@ static int handle_screen_change(xcb_generic_event_t *e
  * now, so we better clean up before.
  *
  */
-static int handle_unmap_notify_event(xcb_unmap_notify_event_t *event) {
-    /* If the client (as opposed to i3) destroyed or unmapped a window, an
-     * EnterNotify event will follow (indistinguishable from an EnterNotify
-     * event caused by moving your mouse), causing i3 to set focus to whichever
-     * window is now visible.
-     *
-     * In a complex stacked or tabbed layout (take two v-split containers in a
-     * tabbed container), when the bottom window in tab2 is closed, the bottom
-     * window of tab1 is visible instead. X11 will thus send an EnterNotify
-     * event for the bottom window of tab1, while the focus should be set to
-     * the remaining window of tab2.
-     *
-     * Therefore, we ignore all EnterNotify events which have the same sequence
-     * as an UnmapNotify event. */
-    add_ignore_event(event->sequence, XCB_ENTER_NOTIFY);
-
+static void handle_unmap_notify_event(xcb_unmap_notify_event_t *event) {
     DLOG("UnmapNotify for 0x%08x (received from 0x%08x), serial %d\n", event->window, event->event, event->sequence);
+    xcb_get_input_focus_cookie_t cookie;
     Con *con = con_by_window_id(event->window);
     if (con == NULL) {
         /* This could also be an UnmapNotify for the frame. We need to
@@ -481,63 +467,52 @@ static int handle_unmap_notify_event(xcb_unmap_notify_
         con = con_by_frame_id(event->window);
         if (con == NULL) {
             LOG("Not a managed window, ignoring UnmapNotify event\n");
-            return 1;
+            return;
         }
+
         if (con->ignore_unmap > 0)
             con->ignore_unmap--;
+        /* See the end of this function. */
+        cookie = xcb_get_input_focus(conn);
         DLOG("ignore_unmap = %d for frame of container %p\n", con->ignore_unmap, con);
-        return 1;
+        goto ignore_end;
     }
 
+    /* See the end of this function. */
+    cookie = xcb_get_input_focus(conn);
+
     if (con->ignore_unmap > 0) {
         DLOG("ignore_unmap = %d, dec\n", con->ignore_unmap);
         con->ignore_unmap--;
-        return 1;
+        goto ignore_end;
     }
 
     tree_close(con, DONT_KILL_WINDOW, false, false);
     tree_render();
     x_push_changes(croot);
-    return 1;
 
-#if 0
-        if (client == NULL) {
-                DLOG("not a managed window. Ignoring.\n");
+ignore_end:
+    /* If the client (as opposed to i3) destroyed or unmapped a window, an
+     * EnterNotify event will follow (indistinguishable from an EnterNotify
+     * event caused by moving your mouse), causing i3 to set focus to whichever
+     * window is now visible.
+     *
+     * In a complex stacked or tabbed layout (take two v-split containers in a
+     * tabbed container), when the bottom window in tab2 is closed, the bottom
+     * window of tab1 is visible instead. X11 will thus send an EnterNotify
+     * event for the bottom window of tab1, while the focus should be set to
+     * the remaining window of tab2.
+     *
+     * Therefore, we ignore all EnterNotify events which have the same sequence
+     * as an UnmapNotify event. */
+    add_ignore_event(event->sequence, XCB_ENTER_NOTIFY);
 
-                /* This was most likely the destroyed frame of a client which is
-                 * currently being unmapped, so we add this sequence (again!) to
-                 * the ignore list (enter_notify events will get sent for both,
-                 * the child and its frame). */
-                add_ignore_event(event->sequence);
-
-                return 0;
-        }
-#endif
-
-
-#if 0
-        /* Let’s see how many clients there are left on the workspace to delete it if it’s empty */
-        bool workspace_empty = SLIST_EMPTY(&(client->workspace->focus_stack));
-        bool workspace_focused = (c_ws == client->workspace);
-        Client *to_focus = (!workspace_empty ? SLIST_FIRST(&(client->workspace->focus_stack)) : NULL);
-
-        /* If this workspace is currently visible, we don’t delete it */
-        if (workspace_is_visible(client->workspace))
-                workspace_empty = false;
-
-        if (workspace_empty) {
-                client->workspace->output = NULL;
-                ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}");
-        }
-
-        /* Remove the urgency flag if set */
-        client->urgent = false;
-        workspace_update_urgent_flag(client->workspace);
-
-        render_layout(conn);
-#endif
-
-        return 1;
+    /* Since we just ignored the sequence of this UnmapNotify, we want to make
+     * sure that following events use a different sequence. When putting xterm
+     * into fullscreen and moving the pointer to a different window, without
+     * using GetInputFocus, subsequent (legitimate) EnterNotify events arrived
+     * with the same sequence and thus were ignored (see ticket #609). */
+    free(xcb_get_input_focus_reply(conn, cookie, NULL));
 }
 
 /*
@@ -549,7 +524,7 @@ static int handle_unmap_notify_event(xcb_unmap_notify_
  * important fields in the event data structure).
  *
  */
-static int handle_destroy_notify_event(xcb_destroy_notify_event_t *event) {
+static void handle_destroy_notify_event(xcb_destroy_notify_event_t *event) {
     DLOG("destroy notify for 0x%08x, 0x%08x\n", event->event, event->window);
 
     xcb_unmap_notify_event_t unmap;
@@ -557,7 +532,7 @@ static int handle_destroy_notify_event(xcb_destroy_not
     unmap.event = event->event;
     unmap.window = event->window;
 
-    return handle_unmap_notify_event(&unmap);
+    handle_unmap_notify_event(&unmap);
 }
 
 /*
@@ -855,18 +830,16 @@ static bool handle_hints(void *data, xcb_connection_t 
 
     xcb_icccm_wm_hints_t hints;
 
-    if (reply != NULL) {
-        if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
+    if (reply == NULL)
+        if (!(reply = xcb_get_property_reply(conn, xcb_icccm_get_wm_hints(conn, window), NULL)))
             return false;
-    } else {
-        if (!xcb_icccm_get_wm_hints_reply(conn, xcb_icccm_get_wm_hints_unchecked(conn, con->window->id), &hints, NULL))
-            return false;
-    }
 
+    if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
+        return false;
+
     if (!con->urgent && focused == con) {
         DLOG("Ignoring urgency flag for current client\n");
-        FREE(reply);
-        return true;
+        goto end;
     }
 
     /* Update the flag on the client directly */
@@ -882,17 +855,10 @@ static bool handle_hints(void *data, xcb_connection_t 
 
     tree_render();
 
-#if 0
-    /* If the workspace this client is on is not visible, we need to redraw
-     * the workspace bar */
-    if (!workspace_is_visible(client->workspace)) {
-            Output *output = client->workspace->output;
-            render_workspace(conn, output, output->current_workspace);
-            xcb_flush(conn);
-    }
-#endif
-
-    FREE(reply);
+end:
+    if (con->window)
+        window_update_hints(con->window, reply);
+    else free(reply);
     return true;
 }
 
