]> git.sur5r.net Git - i3/i3/commitdiff
Bugfix: Change the event mask to ignore enter notifies when rendering the layout...
authorMichael Stapelberg <michael+x200@stapelberg.de>
Tue, 10 Mar 2009 23:20:56 +0000 (00:20 +0100)
committerMichael Stapelberg <michael+x200@stapelberg.de>
Tue, 10 Mar 2009 23:20:56 +0000 (00:20 +0100)
include/layout.h
include/util.h
include/xcb.h
src/commands.c
src/layout.c
src/mainx.c
src/table.c
src/util.c

index 94beb6d488833b2fe2e42a35676dbff52cb11c2a..ca90391c36d07ade9440bfb351016694bb7b0f3f 100644 (file)
@@ -17,6 +17,7 @@ Rect get_unoccupied_space(Workspace *workspace);
 void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable, xcb_gcontext_t gc, int offset);
 void redecorate_window(xcb_connection_t *conn, Client *client);
 void render_container(xcb_connection_t *conn, Container *container);
+void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bool ignore_enter_notify);
 void render_layout(xcb_connection_t *conn);
 
 #endif
index 31beeb80aad23b7056af82ffd9e4c4fe3f1b74a8..12cd852c64bf59a01db8676b5aa776bb4c79e6bf 100644 (file)
                                                 CIRCLEQ_NEXT(elm, field) : NULL)
 #define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? \
                                                 CIRCLEQ_PREV(elm, field) : NULL)
+#define FOR_TABLE(workspace) \
+                        for (int cols = 0; cols < workspace->cols; cols++) \
+                                for (int rows = 0; rows < workspace->rows; rows++)
+
 /* ##__VA_ARGS__ means: leave out __VA_ARGS__ completely if it is empty, that is,
    delete the preceding comma */
 #define LOG(fmt, ...) slog("%s:%s:%d - " fmt, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
index 263171473bad4bb982dde7c4afc41b5e8f968f41..31307e330f7d0b04df06bfc1dc784da2fa192050 100644 (file)
 #define XCB_CURSOR_SB_H_DOUBLE_ARROW 108
 #define XCB_CURSOR_SB_V_DOUBLE_ARROW 116
 
+/* The event masks are defined here because we don’t only set them once but we need to set slight
+   variations of them (without XCB_EVENT_MASK_ENTER_WINDOW while rendering the layout) */
+/* The XCB_CW_EVENT_MASK for the child (= real window) */
+#define CHILD_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | \
+                          XCB_EVENT_MASK_STRUCTURE_NOTIFY | \
+                          XCB_EVENT_MASK_ENTER_WINDOW)
+
+/* The XCB_CW_EVENT_MASK for its frame */
+#define FRAME_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS |          /* …mouse is pressed/released */ \
+                          XCB_EVENT_MASK_BUTTON_RELEASE | \
+                          XCB_EVENT_MASK_EXPOSURE |              /* …our window needs to be redrawn */ \
+                          XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | /* …user moves cursor inside our window */ \
+                          XCB_EVENT_MASK_ENTER_WINDOW)           /* …the application tries to resize itself */
+
+
 enum { _NET_SUPPORTED = 0,
         _NET_SUPPORTING_WM_CHECK,
         _NET_WM_NAME,
index e2907564a1f0f93e20795f13d5f14422560fe47e..e47855f6ef5d27c226219950530a0fbe03370e01 100644 (file)
@@ -417,14 +417,15 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
         /* TODO: does grabbing the server actually bring us any (speed)advantages? */
         //xcb_grab_server(conn);
 
+        ignore_enter_notify_forall(conn, c_ws, true);
+
         /* Unmap all clients of the current workspace */
         int unmapped_clients = 0;
-        for (int cols = 0; cols < c_ws->cols; cols++)
-                for (int rows = 0; rows < c_ws->rows; rows++)
-                        CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) {
-                                xcb_unmap_window(conn, client->frame);
-                                unmapped_clients++;
-                        }
+        FOR_TABLE(c_ws)
+                CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) {
+                        xcb_unmap_window(conn, client->frame);
+                        unmapped_clients++;
+                }
 
         /* If we did not unmap any clients, the workspace is empty and we can destroy it */
         if (unmapped_clients == 0)
@@ -436,22 +437,27 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
                 if (stack_win->container->workspace == c_ws)
                         xcb_unmap_window(conn, stack_win->window);
 
+        ignore_enter_notify_forall(conn, c_ws, false);
+
         c_ws = &workspaces[workspace-1];
         current_row = c_ws->current_row;
         current_col = c_ws->current_col;
         LOG("new current row = %d, current col = %d\n", current_row, current_col);
 
+        ignore_enter_notify_forall(conn, c_ws, true);
+
         /* Map all clients on the new workspace */
-        for (int cols = 0; cols < c_ws->cols; cols++)
-                for (int rows = 0; rows < c_ws->rows; rows++)
-                        CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients)
-                                xcb_map_window(conn, client->frame);
+        FOR_TABLE(c_ws)
+                CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients)
+                        xcb_map_window(conn, client->frame);
 
         /* Map all stack windows, if any */
         SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
                 if (stack_win->container->workspace == c_ws)
                         xcb_map_window(conn, stack_win->window);
 
+        ignore_enter_notify_forall(conn, c_ws, false);
+
         /* Restore focus on the new workspace */
         if (CUR_CELL->currently_focused != NULL)
                 set_focus(conn, CUR_CELL->currently_focused);
index 68db98bdb58fd71501bf024042de1277080292d4..3783e9bb48bf64be649381fea33e16356d30c657 100644 (file)
@@ -464,6 +464,34 @@ static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int wid
         LOG("done rendering internal\n");
 }
 
+/*
+ * Modifies the event mask of all clients on the given workspace to either ignore or to handle
+ * enter notifies. It is handy to ignore notifies because they will be sent when a window is mapped
+ * under the cursor, thus when the user didn’t enter the window actively at all.
+ *
+ */
+void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bool ignore_enter_notify) {
+        Client *client;
+        uint32_t values[1];
+
+        LOG("Ignore enter_notify = %d\n", ignore_enter_notify);
+
+        FOR_TABLE(workspace)
+                CIRCLEQ_FOREACH(client, &(workspace->table[cols][rows]->clients), clients) {
+                        /* Change event mask for the decorations */
+                        values[0] = FRAME_EVENT_MASK;
+                        if (ignore_enter_notify)
+                                values[0] &= ~(XCB_EVENT_MASK_ENTER_WINDOW);
+                        xcb_change_window_attributes(conn, client->frame, XCB_CW_EVENT_MASK, values);
+
+                        /* Change event mask for the child itself */
+                        values[0] = CHILD_EVENT_MASK;
+                        if (ignore_enter_notify)
+                                values[0] &= ~(XCB_EVENT_MASK_ENTER_WINDOW);
+                        xcb_change_window_attributes(conn, client->child, XCB_CW_EVENT_MASK, values);
+                }
+}
+
 void render_layout(xcb_connection_t *conn) {
         i3Screen *screen;
         i3Font *font = load_font(conn, config.font);
@@ -496,41 +524,45 @@ void render_layout(xcb_connection_t *conn) {
                         xoffset[rows] = r_ws->rect.x;
 
                 dump_table(conn, r_ws);
+
+                ignore_enter_notify_forall(conn, r_ws, true);
+
                 /* Go through the whole table and render what’s necessary */
-                for (int cols = 0; cols < r_ws->cols; cols++)
-                        for (int rows = 0; rows < r_ws->rows; rows++) {
-                                Container *container = r_ws->table[cols][rows];
-                                int single_width, single_height;
-                                LOG("\n");
-                                LOG("========\n");
-                                LOG("container has %d colspan, %d rowspan\n",
-                                                container->colspan, container->rowspan);
-                                LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
-                                /* Update position of the container */
-                                container->row = rows;
-                                container->col = cols;
-                                container->x = xoffset[rows];
-                                container->y = yoffset[cols];
-
-                                if (container->width_factor == 0)
-                                        container->width = (width / r_ws->cols);
-                                else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor;
-                                single_width = container->width;
-                                container->width *= container->colspan;
-
-                                if (container->height_factor == 0)
-                                        container->height = (height / r_ws->rows);
-                                else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
-                                single_height = container->height;
-                                container->height *= container->rowspan;
-
-                                /* Render the container if it is not empty */
-                                render_container(conn, container);
-
-                                xoffset[rows] += single_width;
-                                yoffset[cols] += single_height;
-                                LOG("==========\n");
-                        }
+                FOR_TABLE(r_ws) {
+                        Container *container = r_ws->table[cols][rows];
+                        int single_width, single_height;
+                        LOG("\n");
+                        LOG("========\n");
+                        LOG("container has %d colspan, %d rowspan\n",
+                                        container->colspan, container->rowspan);
+                        LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
+                        /* Update position of the container */
+                        container->row = rows;
+                        container->col = cols;
+                        container->x = xoffset[rows];
+                        container->y = yoffset[cols];
+
+                        if (container->width_factor == 0)
+                                container->width = (width / r_ws->cols);
+                        else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor;
+                        single_width = container->width;
+                        container->width *= container->colspan;
+
+                        if (container->height_factor == 0)
+                                container->height = (height / r_ws->rows);
+                        else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
+                        single_height = container->height;
+                        container->height *= container->rowspan;
+
+                        /* Render the container if it is not empty */
+                        render_container(conn, container);
+
+                        xoffset[rows] += single_width;
+                        yoffset[cols] += single_height;
+                        LOG("==========\n");
+                }
+
+                ignore_enter_notify_forall(conn, r_ws, false);
 
                 render_bars(conn, r_ws, width, &height);
                 render_internal_bar(conn, r_ws, width, font->height + 6);
index 61d2bb547ad72c5b51de723722d189d391d54e9d..ba5ece5911d601796dda47e27874e39ec067ef52 100644 (file)
@@ -131,9 +131,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         /* We are interested in property changes */
         mask = XCB_CW_EVENT_MASK;
-        values[0] =     XCB_EVENT_MASK_PROPERTY_CHANGE |
-                        XCB_EVENT_MASK_STRUCTURE_NOTIFY |
-                        XCB_EVENT_MASK_ENTER_WINDOW;
+        values[0] = CHILD_EVENT_MASK;
         xcb_change_window_attributes(conn, child, mask, values);
 
         /* Map the window first to avoid flickering */
@@ -171,11 +169,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         /* We want to know when… */
         mask |= XCB_CW_EVENT_MASK;
-        values[1] =     XCB_EVENT_MASK_BUTTON_PRESS |           /* …mouse is pressed/released */
-                        XCB_EVENT_MASK_BUTTON_RELEASE |
-                        XCB_EVENT_MASK_EXPOSURE |               /* …our window needs to be redrawn */
-                        XCB_EVENT_MASK_ENTER_WINDOW |           /* …user moves cursor inside our window */
-                        XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;   /* …the application tries to resize itself */
+        values[1] = FRAME_EVENT_MASK;
 
         LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
 
index 3bc45019357c3dda343e61d7ba97c46b9472f784..4c13be8366cb8fc497b7d0992e6308f164c6783d 100644 (file)
@@ -170,18 +170,16 @@ static void move_rows_from(xcb_connection_t *conn, Workspace *workspace, int row
 
 void dump_table(xcb_connection_t *conn, Workspace *workspace) {
         LOG("dump_table()\n");
-        for (int cols = 0; cols < workspace->cols; cols++) {
-                for (int rows = 0; rows < workspace->rows; rows++) {
-                        Container *con = workspace->table[cols][rows];
-                        LOG("----\n");
-                        LOG("at col=%d, row=%d\n", cols, rows);
-                        LOG("currently_focused = %p\n", con->currently_focused);
-                        Client *loop;
-                        CIRCLEQ_FOREACH(loop, &(con->clients), clients) {
-                                LOG("got client %08x / %s\n", loop->child, loop->name);
-                        }
-                        LOG("----\n");
+        FOR_TABLE(workspace) {
+                Container *con = workspace->table[cols][rows];
+                LOG("----\n");
+                LOG("at col=%d, row=%d\n", cols, rows);
+                LOG("currently_focused = %p\n", con->currently_focused);
+                Client *loop;
+                CIRCLEQ_FOREACH(loop, &(con->clients), clients) {
+                        LOG("got client %08x / %s\n", loop->child, loop->name);
                 }
+                LOG("----\n");
         }
         LOG("done\n");
 }
@@ -258,22 +256,21 @@ void cleanup_table(xcb_connection_t *conn, Workspace *workspace) {
 void fix_colrowspan(xcb_connection_t *conn, Workspace *workspace) {
         LOG("Fixing col/rowspan\n");
 
-        for (int cols = 0; cols < workspace->cols; cols++)
-                for (int rows = 0; rows < workspace->rows; rows++) {
-                        Container *con = workspace->table[cols][rows];
-                        if (con->colspan > 1) {
-                                LOG("gots one with colspan %d\n", con->colspan);
-                                while (con->colspan > 1 &&
-                                       workspace->table[cols + (con->colspan - 1)][rows]->currently_focused != NULL)
-                                        con->colspan--;
-                                LOG("fixed it to %d\n", con->colspan);
-                        }
-                        if (con->rowspan > 1) {
-                                LOG("gots one with rowspan %d\n", con->rowspan);
-                                while (con->rowspan > 1 &&
-                                       workspace->table[cols][rows + (con->rowspan - 1)]->currently_focused != NULL)
-                                        con->rowspan--;
-                                LOG("fixed it to %d\n", con->rowspan);
-                        }
+        FOR_TABLE(workspace) {
+                Container *con = workspace->table[cols][rows];
+                if (con->colspan > 1) {
+                        LOG("gots one with colspan %d\n", con->colspan);
+                        while (con->colspan > 1 &&
+                               workspace->table[cols + (con->colspan - 1)][rows]->currently_focused != NULL)
+                                con->colspan--;
+                        LOG("fixed it to %d\n", con->colspan);
                 }
+                if (con->rowspan > 1) {
+                        LOG("gots one with rowspan %d\n", con->rowspan);
+                        while (con->rowspan > 1 &&
+                               workspace->table[cols][rows + (con->rowspan - 1)]->currently_focused != NULL)
+                                con->rowspan--;
+                        LOG("fixed it to %d\n", con->rowspan);
+                }
+        }
 }
index 2ca1e1ca1ab82f63d397eeedc7b3dfc2d77b5e9b..d44a2593ab695210fa3a3751c795fe424789fea0 100644 (file)
@@ -371,8 +371,8 @@ void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
                 /* Because the coordinates of the window haven’t changed, it would not be
                    re-configured if we don’t set the following flag */
                 client->force_reconfigure = true;
-                /* We left fullscreen mode, redraw the container */
-                render_container(conn, client->container);
+                /* We left fullscreen mode, redraw the whole layout to ensure enternotify events are disabled */
+                render_layout(conn);
         }
 
         xcb_flush(conn);