From: Michael Stapelberg Date: Sun, 10 Jul 2011 21:44:13 +0000 (+0200) Subject: Ignore X11 errors caused by ReparentWindow / ChangeProperty on already destroyed... X-Git-Tag: tree-pr4~40 X-Git-Url: https://git.sur5r.net/?p=i3%2Fi3;a=commitdiff_plain;h=05e39c1c480de807b59bd13386d2cffe35e564b6 Ignore X11 errors caused by ReparentWindow / ChangeProperty on already destroyed windows These errors can happen because a DestroyWindow request by a client will trigger an UnmapNotify, then a DestroyNotify. We cannot distinguish this UnmapNotify from an UnmapNotify not followed by a DestroyNotify, so we just try to send the ReparentWindow / ChangeProperty and ignore the errors, if any. --- diff --git a/include/handlers.h b/include/handlers.h index 839bac61..0aaaf158 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -15,8 +15,22 @@ extern int randr_base; +/** + * Adds the given sequence to the list of events which are ignored. + * If this ignore should only affect a specific response_type, pass + * response_type, otherwise, pass -1. + * + * Every ignored sequence number gets garbage collected after 5 seconds. + * + */ void add_ignore_event(const int sequence, const int response_type); +/** + * Checks if the given sequence is ignored and returns true if so. + * + */ +bool event_is_ignored(const int sequence, const int response_type); + /** * Takes an xcb_generic_event_t and calls the appropriate handler, based on the * event type. diff --git a/src/handlers.c b/src/handlers.c index 8e9bbb04..0b64d141 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -21,6 +21,14 @@ int randr_base = -1; changing workspaces */ static SLIST_HEAD(ignore_head, Ignore_Event) ignore_events; +/* + * Adds the given sequence to the list of events which are ignored. + * If this ignore should only affect a specific response_type, pass + * response_type, otherwise, pass -1. + * + * Every ignored sequence number gets garbage collected after 5 seconds. + * + */ void add_ignore_event(const int sequence, const int response_type) { struct Ignore_Event *event = smalloc(sizeof(struct Ignore_Event)); @@ -35,7 +43,7 @@ void add_ignore_event(const int sequence, const int response_type) { * Checks if the given sequence is ignored and returns true if so. * */ -static bool event_is_ignored(const int sequence, const int response_type) { +bool event_is_ignored(const int sequence, const int response_type) { struct Ignore_Event *event; time_t now = time(NULL); for (event = SLIST_FIRST(&ignore_events); event != SLIST_END(&ignore_events);) { @@ -51,7 +59,7 @@ static bool event_is_ignored(const int sequence, const int response_type) { if (event->sequence != sequence) continue; - if (event->response_type != 0 && + if (event->response_type != -1 && event->response_type != response_type) continue; @@ -286,7 +294,7 @@ static int handle_map_request(xcb_map_request_event_t *event) { cookie = xcb_get_window_attributes_unchecked(conn, event->window); DLOG("window = 0x%08x, serial is %d.\n", event->window, event->sequence); - add_ignore_event(event->sequence, 0); + add_ignore_event(event->sequence, -1); manage_window(event->window, cookie, false); x_push_changes(croot); diff --git a/src/main.c b/src/main.c index a2764cc1..7910c8b1 100644 --- a/src/main.c +++ b/src/main.c @@ -70,7 +70,9 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) { while ((event = xcb_poll_for_event(conn)) != NULL) { if (event->response_type == 0) { - ELOG("X11 Error received! sequence %x\n", event->sequence); + if (event_is_ignored(event->sequence, 0)) + DLOG("Expected X11 Error received for sequence %x\n", event->sequence); + else ELOG("X11 Error received! sequence %x\n", event->sequence); continue; } diff --git a/src/tree.c b/src/tree.c index caf29678..272276f4 100644 --- a/src/tree.c +++ b/src/tree.c @@ -153,13 +153,23 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent) { x_window_kill(con->window->id, kill_window); return false; } else { + xcb_void_cookie_t cookie; /* un-parent the window */ - xcb_reparent_window(conn, con->window->id, root, 0, 0); + cookie = xcb_reparent_window(conn, con->window->id, root, 0, 0); + + /* Ignore X11 errors for the ReparentWindow request. + * X11 Errors are returned when the window was already destroyed */ + add_ignore_event(cookie.sequence, 0); + /* We are no longer handling this window, thus set WM_STATE to * WM_STATE_WITHDRAWN (see ICCCM 4.1.3.1) */ long data[] = { XCB_ICCCM_WM_STATE_WITHDRAWN, XCB_NONE }; - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id, - A_WM_STATE, A_WM_STATE, 32, 2, data); + cookie = xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + con->window->id, A_WM_STATE, A_WM_STATE, 32, 2, data); + + /* Ignore X11 errors for the ReparentWindow request. + * X11 Errors are returned when the window was already destroyed */ + add_ignore_event(cookie.sequence, 0); } FREE(con->window->class_class); FREE(con->window->class_instance); diff --git a/src/xcb.c b/src/xcb.c index 3fd0bfcd..07f3ce1e 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -328,7 +328,7 @@ void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r) { XCB_CONFIG_WINDOW_HEIGHT, &(r.x)); /* ignore events which are generated because we configured a window */ - add_ignore_event(cookie.sequence, 0); + add_ignore_event(cookie.sequence, -1); } /*