From a42762493ae4aeb7e892166d76c8bd5843b2be67 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 14 May 2016 14:20:08 +0200 Subject: [PATCH 1/4] xembed: Handle reparents correctly The Xembed specification states that the protocol ends by reparenting the embedded window elsewhere while unmapping the window can be done without ending the protocol. This commit makes us follow this part of the spec. Signed-off-by: Uli Schlachter --- event.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/event.c b/event.c index e4ca8fe5..6e2ea836 100644 --- a/event.c +++ b/event.c @@ -770,14 +770,6 @@ event_handle_unmapnotify(xcb_unmap_notify_event_t *ev) if((c = client_getbywin(ev->window))) client_unmanage(c, true); - else - for(int i = 0; i < globalconf.embedded.len; i++) - if(globalconf.embedded.tab[i].win == ev->window) - { - xembed_window_array_take(&globalconf.embedded, i); - xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, ev->window); - luaA_systray_invalidate(); - } } /** The randr screen change notify event handler. @@ -918,6 +910,16 @@ event_handle_reparentnotify(xcb_reparent_notify_event_t *ev) if (ev->parent != globalconf.screen->root) client_unmanage(c, true); } + else if (ev->parent != globalconf.systray.window) { + /* Embedded window moved elsewhere, end of embedding */ + for(int i = 0; i < globalconf.embedded.len; i++) + if(globalconf.embedded.tab[i].win == ev->window) + { + xembed_window_array_take(&globalconf.embedded, i); + xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, ev->window); + luaA_systray_invalidate(); + } + } } static void From 0b64c8987d8068de73b86027d333f1b0bf3a841d Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 29 May 2016 14:29:23 +0200 Subject: [PATCH 2/4] Remove unused argument to systray_request_handle() It always had the value NULL. Signed-off-by: Uli Schlachter --- objects/client.c | 2 +- systray.c | 13 ++++--------- systray.h | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/objects/client.c b/objects/client.c index c696f06f..45ba0830 100644 --- a/objects/client.c +++ b/objects/client.c @@ -1113,7 +1113,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, xcb_get_window_at if(systray_iskdedockapp(w)) { - systray_request_handle(w, NULL); + systray_request_handle(w); return; } diff --git a/systray.c b/systray.c index cad77b5a..e0e08664 100644 --- a/systray.c +++ b/systray.c @@ -124,11 +124,10 @@ systray_cleanup(void) /** Handle a systray request. * \param embed_win The window to embed. - * \param info The embedding info * \return 0 on no error. */ int -systray_request_handle(xcb_window_t embed_win, xembed_info_t *info) +systray_request_handle(xcb_window_t embed_win) { xembed_window_t em; xcb_get_property_cookie_t em_cookie; @@ -145,8 +144,7 @@ systray_request_handle(xcb_window_t embed_win, xembed_info_t *info) p_clear(&em_cookie, 1); - if(!info) - em_cookie = xembed_info_get_unchecked(globalconf.connection, embed_win); + em_cookie = xembed_info_get_unchecked(globalconf.connection, embed_win); xcb_change_window_attributes(globalconf.connection, embed_win, XCB_CW_EVENT_MASK, select_input_val); @@ -161,10 +159,7 @@ systray_request_handle(xcb_window_t embed_win, xembed_info_t *info) em.win = embed_win; - if(info) - em.info = *info; - else - xembed_info_get_reply(globalconf.connection, em_cookie, &em.info); + xembed_info_get_reply(globalconf.connection, em_cookie, &em.info); xembed_embedded_notify(globalconf.connection, em.win, globalconf.systray.window, @@ -196,7 +191,7 @@ systray_process_client_message(xcb_client_message_event_t *ev) return -1; if(globalconf.screen->root == geom_r->root) - ret = systray_request_handle(ev->data.data32[2], NULL); + ret = systray_request_handle(ev->data.data32[2]); p_delete(&geom_r); break; diff --git a/systray.h b/systray.h index 2b037ca5..b4176400 100644 --- a/systray.h +++ b/systray.h @@ -28,7 +28,7 @@ void systray_init(void); void systray_cleanup(void); -int systray_request_handle(xcb_window_t, xembed_info_t *); +int systray_request_handle(xcb_window_t); bool systray_iskdedockapp(xcb_window_t); int systray_process_client_message(xcb_client_message_event_t *); int xembed_process_client_message(xcb_client_message_event_t *); From e801df1ee3790262c9925502663cb456be9bb3ba Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 29 May 2016 14:31:22 +0200 Subject: [PATCH 3/4] xembed: Use sane defaults if _XEMBED_INFO is not present Skype's tray icon doesn't seem to follow the XEMBED spec... Signed-off-by: Uli Schlachter --- systray.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/systray.c b/systray.c index e0e08664..b4e66acd 100644 --- a/systray.c +++ b/systray.c @@ -159,7 +159,11 @@ systray_request_handle(xcb_window_t embed_win) em.win = embed_win; - xembed_info_get_reply(globalconf.connection, em_cookie, &em.info); + if (!xembed_info_get_reply(globalconf.connection, em_cookie, &em.info)) { + /* Set some sane defaults */ + em.info.version = XEMBED_VERSION; + em.info.flags = XEMBED_MAPPED; + } xembed_embedded_notify(globalconf.connection, em.win, globalconf.systray.window, From ec076ca4bd6669095ae426cf087e4dc91caa7398 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sat, 14 May 2016 14:30:22 +0200 Subject: [PATCH 4/4] Properly support the XEMBED_MAPPED bit The XEmbed protocol defines a special property that defines if the embedded window wants to be visible or not. Up to now, awesome always ignored this entry and instead behaved as if the bit was set. This commit makes it properly respect the bit. Testing done: None. No idea how. Apparently nothing really uses this bit, because we didn't get bug reports about it yet. Signed-off-by: Uli Schlachter --- common/xembed.c | 4 ++++ event.c | 10 +++++++++- systray.c | 27 ++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/common/xembed.c b/common/xembed.c index bb70ab1f..3f4c8673 100644 --- a/common/xembed.c +++ b/common/xembed.c @@ -24,6 +24,9 @@ #include "common/util.h" #include "common/atoms.h" +/* I should really include the correct header instead... */ +void luaA_systray_invalidate(void); + /** Send an XEMBED message to a window. * \param connection Connection to the X server. * \param towin Destination window @@ -141,6 +144,7 @@ xembed_property_update(xcb_connection_t *connection, xembed_window_t *emwin, xembed_window_deactivate(connection, emwin->win); xembed_focus_out(connection, emwin->win); } + luaA_systray_invalidate(); } } diff --git a/event.c b/event.c index 6e2ea836..c4e2ea3d 100644 --- a/event.c +++ b/event.c @@ -711,6 +711,7 @@ static void event_handle_maprequest(xcb_map_request_event_t *ev) { client_t *c; + xembed_window_t *em; xcb_get_window_attributes_cookie_t wa_c; xcb_get_window_attributes_reply_t *wa_r; xcb_get_geometry_cookie_t geom_c; @@ -724,10 +725,17 @@ event_handle_maprequest(xcb_map_request_event_t *ev) if(wa_r->override_redirect) goto bailout; - if(xembed_getbywin(&globalconf.embedded, ev->window)) + if((em = xembed_getbywin(&globalconf.embedded, ev->window))) { xcb_map_window(globalconf.connection, ev->window); xembed_window_activate(globalconf.connection, ev->window); + /* The correct way to set this is via the _XEMBED_INFO property. Neither + * of the XEMBED not the systray spec talk about mapping windows. + * Apparently, Qt doesn't care and does not set an _XEMBED_INFO + * property. Let's simulate the XEMBED_MAPPED bit. + */ + em->info.flags |= XEMBED_MAPPED; + luaA_systray_invalidate(); } else if((c = client_getbywin(ev->window))) { diff --git a/systray.c b/systray.c index b4e66acd..f0d7369d 100644 --- a/systray.c +++ b/systray.c @@ -247,6 +247,16 @@ xembed_process_client_message(xcb_client_message_event_t *ev) return 0; } +static int +systray_num_visible_entries(void) +{ + int result = 0; + foreach(em, globalconf.embedded) + if (em->info.flags & XEMBED_MAPPED) + result++; + return result; +} + /** Inform lua that the systray needs to be updated. */ void @@ -256,7 +266,7 @@ luaA_systray_invalidate(void) signal_object_emit(L, &global_signals, "systray::update", 0); /* Unmap now if the systray became empty */ - if(globalconf.embedded.len == 0) + if(systray_num_visible_entries() == 0) xcb_unmap_window(globalconf.connection, globalconf.systray.window); } @@ -267,11 +277,12 @@ systray_update(int base_size, bool horizontal, bool reverse, int spacing, bool f return; /* Give the systray window the correct size */ + int num_entries = systray_num_visible_entries(); uint32_t config_vals[4] = { base_size, base_size, 0, 0 }; if(horizontal) - config_vals[0] = base_size * globalconf.embedded.len + spacing * (globalconf.embedded.len - 1); + config_vals[0] = base_size * num_entries + spacing * (num_entries - 1); else - config_vals[1] = base_size * globalconf.embedded.len + spacing * (globalconf.embedded.len - 1); + config_vals[1] = base_size * num_entries + spacing * (num_entries - 1); xcb_configure_window(globalconf.connection, globalconf.systray.window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, @@ -289,6 +300,12 @@ systray_update(int base_size, bool horizontal, bool reverse, int spacing, bool f else em = &globalconf.embedded.tab[i]; + if (!(em->info.flags & XEMBED_MAPPED)) + { + xcb_unmap_window(globalconf.connection, em->win); + continue; + } + xcb_configure_window(globalconf.connection, em->win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, config_vals); @@ -362,7 +379,7 @@ luaA_systray(lua_State *L) globalconf.systray.parent = w; - if(globalconf.embedded.len != 0) + if(systray_num_visible_entries() != 0) { systray_update(base_size, horiz, revers, spacing, force_redraw); xcb_map_window(globalconf.connection, @@ -370,7 +387,7 @@ luaA_systray(lua_State *L) } } - lua_pushinteger(L, globalconf.embedded.len); + lua_pushinteger(L, systray_num_visible_entries()); luaA_object_push(L, globalconf.systray.parent); return 2; }