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 e4ca8fe5..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))) { @@ -770,14 +778,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 +918,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 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..f0d7369d 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,11 @@ 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); + 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, @@ -196,7 +195,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; @@ -248,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 @@ -257,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); } @@ -268,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, @@ -290,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); @@ -363,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, @@ -371,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; } 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 *);