diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index 926b82d..31efd77 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -494,6 +495,13 @@ static void backend_merge_effects( case ZDWM_EFFECT_KILL_WINDOW: window_list_push(&backend->kill, e->as.kill.window); break; + case ZDWM_EFFECT_WITHDRAW_WINDOW: + window_set_icccm_wm_state( + backend->conn, + e->as.withdraw.window, + XCB_ICCCM_WM_STATE_WITHDRAWN + ); + break; case ZDWM_EFFECT_MOVE_WINDOW: { window_configure_t *cfg = find_or_push_configure(configs, e->as.move.window); diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index b50333c..da2ed5d 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -173,7 +173,11 @@ static bool handle_unmap_notify( ) { event->type = ZDWM_EVENT_WINDOW_REMOVE; event->as.window_remove.window = xcb_event->window; - event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_WITHDRAWN; + if (XCB_EVENT_SENT(xcb_event)) { + event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_WITHDRAWN; + } else { + event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY; + } return true; } @@ -251,7 +255,8 @@ bool backend_next_event(backend_t *backend, event_t *event) { uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event); bool handled = false; - printf("xcb event type: %u\n", response_type); + auto label = xcb_event_get_label(response_type); + printf("xcb event type: %s[%u]\n", label, response_type); switch (response_type) { #define EVENT(type, handler) \ diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 178b6a8..0a261d5 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -319,6 +319,27 @@ void window_clean_event_mask(xcb_connection_t *conn, xcb_window_t window) { xcb_change_window_attributes_aux(conn, window, change_mask, &value_list); } +void window_set_icccm_wm_state( + xcb_connection_t *conn, + xcb_window_t window, + xcb_icccm_wm_state_t state +) { + xcb_icccm_wm_hints_t hints; + xcb_icccm_wm_hints_set_none(&hints); + switch (state) { + case XCB_ICCCM_WM_STATE_WITHDRAWN: + xcb_icccm_wm_hints_set_withdrawn(&hints); + break; + case XCB_ICCCM_WM_STATE_NORMAL: + xcb_icccm_wm_hints_set_normal(&hints); + break; + case XCB_ICCCM_WM_STATE_ICONIC: + xcb_icccm_wm_hints_set_iconic(&hints); + break; + } + xcb_icccm_set_wm_hints(conn, window, &hints); +} + void window_list_push(window_list_t *window_list, xcb_window_t window) { xcb_window_t *win = array_push(window_list->windows, window_list->count, window_list->capacity); diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 95451db..5815942 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -84,6 +84,11 @@ void window_kill(backend_t *backend, xcb_window_t window); void root_set_event_mask(backend_t *backend); void window_set_event_mask(xcb_connection_t *conn, xcb_window_t window); void window_clean_event_mask(xcb_connection_t *conn, xcb_window_t window); +void window_set_icccm_wm_state( + xcb_connection_t *conn, + xcb_window_t window, + xcb_icccm_wm_state_t state +); void window_list_push(window_list_t *window_list, xcb_window_t window); void window_list_reset(window_list_t *window_list); diff --git a/src/core/command.h b/src/core/command.h index 82927a0..f55f443 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -6,6 +6,7 @@ typedef enum command_type_t { ZDWM_COMMAND_MANAGE_WINDOW, ZDWM_COMMAND_UNMANAGE_WINDOW, + ZDWM_COMMAND_WITHDRAW_WINDOW, ZDWM_COMMAND_FOCUS_WINDOW, ZDWM_COMMAND_KILL_WINDOW, ZDWM_COMMAND_SWITCH_WORKSPACE, @@ -40,6 +41,7 @@ typedef struct command_t { union { manage_window_command_t manage_window; only_window_command_t unmanage; + only_window_command_t withdraw; only_window_command_t focus; only_window_command_t kill; switch_workspace_command_t switch_workspace; diff --git a/src/core/plan.h b/src/core/plan.h index 122cb4b..a7bea3b 100644 --- a/src/core/plan.h +++ b/src/core/plan.h @@ -10,6 +10,7 @@ typedef enum effect_type_t { ZDWM_EFFECT_UNMAP_WINDOW, ZDWM_EFFECT_FOCUS_WINDOW, ZDWM_EFFECT_KILL_WINDOW, + ZDWM_EFFECT_WITHDRAW_WINDOW, ZDWM_EFFECT_MOVE_WINDOW, ZDWM_EFFECT_RESIZE_WINDOW, ZDWM_EFFECT_CHANGE_BORDER_COLOR, @@ -61,6 +62,7 @@ typedef struct effect_t { effect_only_window_id_t unmap; effect_only_window_id_t focus; effect_only_window_id_t kill; + effect_only_window_id_t withdraw; effect_move_window_t move; effect_resize_window_t resize; effect_change_border_color_t change_border_color; diff --git a/src/core/policy.c b/src/core/policy.c index 8752f64..1e2c8aa 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -119,11 +119,22 @@ static void route_window_remove( const window_t *window = state_window_get(state, e->window); if (!window) return; - command_t unmanage_window_cmd = { - .type = ZDWM_COMMAND_UNMANAGE_WINDOW, - .as.unmanage.window = e->window, - }; - command_buffer_push(out, &unmanage_window_cmd); + switch (e->reason) { + case ZDWM_WINDOW_REMOVE_WITHDRAWN: + command_t withdrawn_window_cmd = { + .type = ZDWM_COMMAND_WITHDRAW_WINDOW, + .as.withdraw.window = e->window, + }; + command_buffer_push(out, &withdrawn_window_cmd); + break; + case ZDWM_WINDOW_REMOVE_DESTROY: + command_t unmanage_window_cmd = { + .type = ZDWM_COMMAND_UNMANAGE_WINDOW, + .as.unmanage.window = e->window, + }; + command_buffer_push(out, &unmanage_window_cmd); + break; + } } void policy_route_event( @@ -232,6 +243,18 @@ static void unmanage_window(state_t *state, window_id_t window, plan_t *plan) { } } +static void +withdraw_window(const state_t *state, window_id_t window, plan_t *plan) { + auto win = state_window_get(state, window); + if (!win) return; + + effect_t withdraw_window_effect = { + .type = ZDWM_EFFECT_WITHDRAW_WINDOW, + .as.withdraw.window = win->id, + }; + plan_push_effect(plan, &withdraw_window_effect); +} + static void focus_window(state_t *state, window_id_t window, plan_t *plan) { auto win = state_window_get(state, window); if (!win) return; @@ -298,6 +321,9 @@ void policy_apply_command( case ZDWM_COMMAND_UNMANAGE_WINDOW: unmanage_window(state, cmd->as.unmanage.window, plan); break; + case ZDWM_COMMAND_WITHDRAW_WINDOW: + withdraw_window(state, cmd->as.withdraw.window, plan); + break; case ZDWM_COMMAND_FOCUS_WINDOW: focus_window(state, cmd->as.focus.window, plan); break;