]> git.sur5r.net Git - i3/i3/commitdiff
Bugfix: Fix various bugs when switching workspaces
authorMichael Stapelberg <michael+x200@stapelberg.de>
Sat, 28 Feb 2009 21:11:48 +0000 (22:11 +0100)
committerMichael Stapelberg <michael+x200@stapelberg.de>
Sat, 28 Feb 2009 21:11:48 +0000 (22:11 +0100)
include/handlers.h
src/commands.c
src/handlers.c
src/mainx.c
src/util.c

index 0116d42b23e614847dc83c16d5d5feab82055a09..82b149e6b4cb65cf0c49b020e19f2aa1e1db29fc 100644 (file)
@@ -16,6 +16,7 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_
 int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event);
 int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event);
 int handle_map_notify_event(void *prophs, xcb_connection_t *conn, xcb_map_notify_event_t *event);
+int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_notify_event_t *event);
 int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
                                 xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop);
 int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *event);
index 30a0ac0885633188c63d12aa55db4a23e3249df8..c38ad58b18dd7cffacd7fa943e28e0d1d76514fe 100644 (file)
@@ -322,7 +322,7 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
 
         /* Restore focus on the new workspace */
         if (CUR_CELL->currently_focused != NULL)
-                xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, CUR_CELL->currently_focused->child, XCB_CURRENT_TIME);
+                set_focus(conn, CUR_CELL->currently_focused);
         else xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, root, XCB_CURRENT_TIME);
 
         //xcb_ungrab_server(conn);
index 6b9ac7f19409fae67eccfb7ec7515974d3d3b91f..6d3e50b5f535c94eca458c075a67ff27d906d626 100644 (file)
 #include "util.h"
 #include "xinerama.h"
 
+/* After mapping/unmapping windows, a notify event is generated. However, we don’t want it,
+   since it’d trigger an infinite loop of switching between the different windows when
+   changing workspaces */
+int ignore_notify_event = -1;
+
 /*
  * Due to bindings like Mode_switch + <a>, we need to bind some keys in XCB_GRAB_MODE_SYNC.
  * Therefore, we just replay all key presses.
@@ -89,7 +94,13 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_
  *
  */
 int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) {
-        printf("enter_notify for %08x\n", event->event);
+        printf("enter_notify for %08x, serial %d\n", event->event, event->sequence);
+        /* Some events are not interesting, because they were not generated actively by the
+           user, but be reconfiguration of windows */
+        if (event->sequence == ignore_notify_event) {
+                printf("Ignoring, because of previous map\n");
+                return 1;
+        }
 
         /* This was either a focus for a client’s parent (= titlebar)… */
         Client *client = table_get(byParent, event->event);
@@ -299,11 +310,23 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
 int handle_map_notify_event(void *prophs, xcb_connection_t *conn, xcb_map_notify_event_t *event) {
         window_attributes_t wa = { TAG_VALUE };
         wa.u.override_redirect = event->override_redirect;
-        printf("MapNotify for 0x%08x.\n", event->window);
+        printf("MapNotify for 0x%08x, serial is %d.\n", event->window, event->sequence);
+        ignore_notify_event = event->sequence;
         manage_window(prophs, conn, event->window, wa);
         return 1;
 }
 
+/*
+ * Configuration notifies are only handled because we need to set up ignore for the following
+ * enter notify events
+ *
+ */
+int handle_configure_event(void *prophs, xcb_connection_t *conn, xcb_configure_notify_event_t *event) {
+        printf("handle_configure_event\n");
+        ignore_notify_event = event->sequence;
+        return 1;
+}
+
 /*
  * Our window decorations were unmapped. That means, the window will be killed now,
  * so we better clean up before.
@@ -312,6 +335,8 @@ int handle_map_notify_event(void *prophs, xcb_connection_t *conn, xcb_map_notify
 int handle_unmap_notify_event(void *data, xcb_connection_t *c, xcb_unmap_notify_event_t *e) {
         xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(c)).data->root;
 
+        ignore_notify_event = e->sequence;
+
         Client *client = table_get(byChild, e->window);
         /* First, we need to check if the client is awaiting an unmap-request which
            was generated by us reparenting the window. In that case, we just ignore it. */
index 5083f7018e3ab36fb5ff726e16d5c77e551f2dbf..ce5b788e9311955a528d6e790435b8d533069f1c 100644 (file)
@@ -87,14 +87,14 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *c, xcb_win
                 wa.u.override_redirect = attr->override_redirect;
         }
 
-        /* Check if the window is already managed */
-        if (!wa.u.override_redirect && table_get(byChild, window))
-                goto out;
-
         /* Don’t manage clients with the override_redirect flag */
         if (wa.u.override_redirect)
                 goto out;
 
+        /* Check if the window is already managed */
+        if (table_get(byChild, window))
+                goto out;
+
         /* Get the initial geometry (position, size, …) */
         geomc = xcb_get_geometry(c, d);
         if (!attr) {
@@ -133,12 +133,13 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
 
         Client *new = table_get(byChild, child);
-        if (new == NULL) {
-                /* TODO: When does this happen for existing clients? Is that a bug? */
-                printf("oh, it's new\n");
-                new = calloc(sizeof(Client), 1);
-                new->force_reconfigure = true;
-        }
+
+        /* Events for already managed windows should already be filtered in manage_window() */
+        assert(new == NULL);
+
+        printf("reparenting new client\n");
+        new = calloc(sizeof(Client), 1);
+        new->force_reconfigure = true;
         uint32_t mask = 0;
         uint32_t values[3];
 
@@ -370,6 +371,10 @@ int main(int argc, char *argv[], char *env[]) {
            it any longer. Usually, the client destroys the window shortly afterwards. */
         xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, 0);
 
+        /* Configure notify = window’s configuration (geometry, stacking, …). We only need
+           it to set up ignore the following enter_notify events */
+        xcb_event_set_configure_notify_handler(&evenths, handle_configure_event, 0);
+
         /* Client message = client changed its properties (EWMH) */
         /* TODO: can’t we do this via property handlers? */
         xcb_event_set_client_message_handler(&evenths, handle_client_message, 0);
index a25e63763d191114b188be02264839e60f81d592..c57e4e3b4436148a1daa0854e0fd2c65ea4230dc 100644 (file)
@@ -140,18 +140,21 @@ void set_focus(xcb_connection_t *conn, Client *client) {
         current_col = client->container->col;
         current_row = client->container->row;
 
+        printf("set_focus(frame %08x, child %08x)\n", client->frame, client->child);
         /* Set focus to the entered window, and flush xcb buffer immediately */
         xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
         //xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10);
-        /* Update last/current client’s titlebar */
-        if (old_client != NULL)
-                decorate_window(conn, old_client, old_client->frame, old_client->titlegc, 0);
-        decorate_window(conn, client, client->frame, client->titlegc, 0);
 
         /* If we’re in stacking mode, we render the container to update changes in the title
            bars and to raise the focused client */
         if (client->container->mode == MODE_STACK)
                 render_container(conn, client->container);
+        else {
+                /* Update last/current client’s titlebar */
+                if (old_client != NULL)
+                        decorate_window(conn, old_client, old_client->frame, old_client->titlegc, 0);
+                decorate_window(conn, client, client->frame, client->titlegc, 0);
+        }
 
         xcb_flush(conn);
 }