feat(tray): 拦截托盘图标的 unmap/destroy 事件并移除图标

This commit is contained in:
2026-07-28 03:35:08 +08:00
parent 612c2367ca
commit 583b1fa382
3 changed files with 68 additions and 0 deletions

View File

@@ -205,6 +205,8 @@ static bool handle_unmap_notify(
event_t *event, event_t *event,
const xcb_unmap_notify_event_t *xcb_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->type = ZDWM_EVENT_WINDOW_REMOVE;
event->as.window_remove.window = xcb_event->window; event->as.window_remove.window = xcb_event->window;
if (XCB_EVENT_SENT(xcb_event)) { if (XCB_EVENT_SENT(xcb_event)) {
@@ -221,6 +223,8 @@ static bool handle_destroy_notify(
event_t *event, event_t *event,
const xcb_destroy_notify_event_t *xcb_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->type = ZDWM_EVENT_WINDOW_REMOVE;
event->as.window_remove.window = xcb_event->window; event->as.window_remove.window = xcb_event->window;
event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY; event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY;

View File

@@ -62,6 +62,14 @@ static tray_host_t *get_tray_host(void *handle) {
return tray; 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) { 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) { for (size_t i = 0; i < tray->icon_count; ++i) {
auto icon = &tray->icons[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); 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) { 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 target_size = MAX(tray->icon_size, (int32_t)1);
auto natural_width = tray->icons[index].natural_width; auto natural_width = tray->icons[index].natural_width;
@@ -548,3 +571,36 @@ bool tray_handle_property_notify(
if (ev->window == tray->container) return true; if (ev->window == tray->container) return true;
return tray_get_icon(tray, ev->window) != nullptr; 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;
}

View File

@@ -34,3 +34,11 @@ bool tray_handle_property_notify(
backend_t *backend, backend_t *backend,
const xcb_property_notify_event_t *ev 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
);