From: Michael Stapelberg Date: Sat, 28 Feb 2009 21:11:48 +0000 (+0100) Subject: Bugfix: Fix various bugs when switching workspaces X-Git-Tag: 3.a~130 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=cb6ea9861da304e132a5c6a2a6e5ef058e3c58b6;p=i3%2Fi3 Bugfix: Fix various bugs when switching workspaces --- diff --git a/include/handlers.h b/include/handlers.h index 0116d42b..82b149e6 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -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); diff --git a/src/commands.c b/src/commands.c index 30a0ac08..c38ad58b 100644 --- a/src/commands.c +++ b/src/commands.c @@ -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); diff --git a/src/handlers.c b/src/handlers.c index 6b9ac7f1..6d3e50b5 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -28,6 +28,11 @@ #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 + , 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. */ diff --git a/src/mainx.c b/src/mainx.c index 5083f701..ce5b788e 100644 --- a/src/mainx.c +++ b/src/mainx.c @@ -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); diff --git a/src/util.c b/src/util.c index a25e6376..c57e4e3b 100644 --- a/src/util.c +++ b/src/util.c @@ -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); }