diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index 98be483..070a727 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -205,6 +205,8 @@ static bool handle_unmap_notify( event_t *event, const xcb_unmap_notify_event_t *xcb_event ) { + if (tray_handle_unmap_notify(backend, xcb_event)) return false; + event->type = ZDWM_EVENT_WINDOW_REMOVE; event->as.window_remove.window = xcb_event->window; if (XCB_EVENT_SENT(xcb_event)) { @@ -221,6 +223,8 @@ static bool handle_destroy_notify( event_t *event, const xcb_destroy_notify_event_t *xcb_event ) { + if (tray_handle_destroy_notify(backend, xcb_event)) return false; + event->type = ZDWM_EVENT_WINDOW_REMOVE; event->as.window_remove.window = xcb_event->window; event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY; diff --git a/src/backend/x11/tray.c b/src/backend/x11/tray.c index b90bea6..5277af9 100644 --- a/src/backend/x11/tray.c +++ b/src/backend/x11/tray.c @@ -62,6 +62,14 @@ static tray_host_t *get_tray_host(void *handle) { return tray; } +static size_t tray_find_icon(tray_host_t *tray, xcb_window_t window) { + for (size_t i = 0; i < tray->icon_count; ++i) { + if (tray->icons[i].window == window) return i; + } + + return SIZE_MAX; +} + static tray_icon_t *tray_get_icon(tray_host_t *tray, xcb_window_t window) { for (size_t i = 0; i < tray->icon_count; ++i) { auto icon = &tray->icons[i]; @@ -92,6 +100,21 @@ static void tray_release_icon_window(backend_t *backend, tray_icon_t *icon) { xcb_reparent_window(conn, window, root, 0, 0); } +static void tray_remove_icon_by_index( + backend_t *backend, + size_t index, + bool release_window +) { + auto tray = backend->tray; + if (index >= tray->icon_count) return; + + auto icon = &tray->icons[index]; + if (release_window) tray_release_icon_window(backend, icon); + + array_erase(tray->icons, tray->icon_count, index); + tray_dispatch_callback(tray); +} + static zdwm_size_t tray_get_icon_size(tray_host_t *tray, size_t index) { auto target_size = MAX(tray->icon_size, (int32_t)1); auto natural_width = tray->icons[index].natural_width; @@ -548,3 +571,36 @@ bool tray_handle_property_notify( if (ev->window == tray->container) return true; return tray_get_icon(tray, ev->window) != nullptr; } + +bool tray_handle_unmap_notify( + backend_t *backend, + const xcb_unmap_notify_event_t *ev +) { + auto tray = get_tray_host(backend); + if (!tray || !tray->initialized) return false; + + auto index = tray_find_icon(tray, ev->window); + if (index == SIZE_MAX) return ev->window == tray->container; + + tray_remove_icon_by_index(backend, index, true); + return true; +} + +bool tray_handle_destroy_notify( + backend_t *backend, + const xcb_destroy_notify_event_t *ev +) { + auto tray = get_tray_host(backend); + if (!tray || !tray->initialized) return false; + + if (ev->window == tray->container) { + tray_cleanup(backend); + return true; + } + + auto index = tray_find_icon(tray, ev->window); + if (index == SIZE_MAX) return false; + + tray_remove_icon_by_index(backend, index, false); + return true; +} diff --git a/src/backend/x11/tray.h b/src/backend/x11/tray.h index a415636..71b3454 100644 --- a/src/backend/x11/tray.h +++ b/src/backend/x11/tray.h @@ -34,3 +34,11 @@ bool tray_handle_property_notify( backend_t *backend, const xcb_property_notify_event_t *ev ); +bool tray_handle_unmap_notify( + backend_t *backend, + const xcb_unmap_notify_event_t *ev +); +bool tray_handle_destroy_notify( + backend_t *backend, + const xcb_destroy_notify_event_t *ev +);