Compare commits
3 Commits
1e3a571619
...
a749fc3c6c
| Author | SHA1 | Date | |
|---|---|---|---|
|
a749fc3c6c
|
|||
|
fc68e75f82
|
|||
|
28ebb086b1
|
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "backend/output_utils.h"
|
||||
#include "backend/x11/window.h"
|
||||
#include "base/array.h"
|
||||
#include "base/log.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory.h"
|
||||
@@ -169,6 +170,15 @@ backend_t *backend_create(const char *display_name) {
|
||||
void backend_destroy(backend_t *backend) {
|
||||
if (!backend) return;
|
||||
|
||||
p_delete(&backend->config_list.cfgs);
|
||||
p_clear(&backend->config_list, 1);
|
||||
|
||||
p_delete(&backend->unmap.windows);
|
||||
p_clear(&backend->unmap, 1);
|
||||
|
||||
p_delete(&backend->kill.windows);
|
||||
p_clear(&backend->kill, 1);
|
||||
|
||||
xcb_disconnect(backend->conn);
|
||||
backend->conn = nullptr;
|
||||
free(backend);
|
||||
@@ -415,70 +425,70 @@ backend_restack_windows(backend_t *backend, const effect_window_list_t *list) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct window_configure_t {
|
||||
xcb_window_t window;
|
||||
uint16_t mask;
|
||||
xcb_configure_window_value_list_t value;
|
||||
} window_configure_t;
|
||||
static void window_configure_list_reset(window_configure_list_t *configs) {
|
||||
p_clear(configs->cfgs, configs->count);
|
||||
configs->count = 0;
|
||||
}
|
||||
|
||||
static void backend_apply_window_configure_list(backend_t *backend) {
|
||||
xcb_connection_t *conn = backend->conn;
|
||||
window_configure_list_t *configs = &backend->config_list;
|
||||
for (size_t i = 0; i < configs->count; ++i) {
|
||||
window_configure_t *cfg = &configs->cfgs[i];
|
||||
if (!cfg->mask) continue;
|
||||
|
||||
static void
|
||||
flush_configure(xcb_connection_t *conn, const window_configure_t *cfg) {
|
||||
if (cfg->mask) {
|
||||
xcb_configure_window_aux(conn, cfg->window, cfg->mask, &cfg->value);
|
||||
}
|
||||
}
|
||||
|
||||
static window_configure_t *find_or_push_configure(
|
||||
window_configure_t *cfgs,
|
||||
size_t *cfg_count,
|
||||
xcb_window_t window
|
||||
) {
|
||||
for (size_t j = 0; j < *cfg_count; ++j) {
|
||||
if (cfgs[j].window == window) return &cfgs[j];
|
||||
static window_configure_t *
|
||||
find_or_push_configure(window_configure_list_t *configs, xcb_window_t window) {
|
||||
window_configure_t *cfg = nullptr;
|
||||
for (size_t i = 0; i < configs->count; ++i) {
|
||||
cfg = &configs->cfgs[i];
|
||||
if (cfg->window == window) return cfg;
|
||||
}
|
||||
window_configure_t *cfg = &cfgs[(*cfg_count)++];
|
||||
cfg->window = window;
|
||||
cfg->mask = 0;
|
||||
|
||||
cfg = array_push(configs->cfgs, configs->count, configs->capacity);
|
||||
p_clear(cfg, 1);
|
||||
cfg->window = window;
|
||||
cfg->mask = 0;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
bool backend_apply_effect(
|
||||
static void backend_merge_effects(
|
||||
backend_t *backend,
|
||||
const effect_t *effects,
|
||||
size_t effect_count
|
||||
) {
|
||||
xcb_connection_t *conn = backend->conn;
|
||||
|
||||
/* collect configure-like effects per window */
|
||||
window_configure_t *cfgs = p_new(window_configure_t, effect_count);
|
||||
size_t cfg_count = 0;
|
||||
|
||||
bool focus_window_changed = false;
|
||||
xcb_window_t focus_window = XCB_WINDOW_NONE;
|
||||
window_configure_list_t *configs = &backend->config_list;
|
||||
|
||||
for (size_t i = 0; i < effect_count; ++i) {
|
||||
const effect_t *e = &effects[i];
|
||||
switch (e->type) {
|
||||
case ZDWM_EFFECT_MAP_WINDOW:
|
||||
xcb_map_window(conn, e->as.map.window);
|
||||
window_list_push(&backend->map, e->as.map.window);
|
||||
break;
|
||||
case ZDWM_EFFECT_UNMAP_WINDOW:
|
||||
xcb_unmap_window(conn, e->as.unmap.window);
|
||||
window_list_push(&backend->unmap, e->as.unmap.window);
|
||||
break;
|
||||
case ZDWM_EFFECT_FOCUS_WINDOW:
|
||||
focus_window = e->as.focus.window;
|
||||
focus_window_changed = true;
|
||||
backend->focus_window = e->as.focus.window;
|
||||
backend->update_focus = true;
|
||||
break;
|
||||
case ZDWM_EFFECT_KILL_WINDOW:
|
||||
window_list_push(&backend->kill, e->as.kill.window);
|
||||
break;
|
||||
case ZDWM_EFFECT_MOVE_WINDOW: {
|
||||
window_configure_t *cfg =
|
||||
find_or_push_configure(cfgs, &cfg_count, e->as.move.window);
|
||||
find_or_push_configure(configs, e->as.move.window);
|
||||
cfg->mask |= XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
|
||||
cfg->value.x = e->as.move.left_top_point.x;
|
||||
cfg->value.y = e->as.move.left_top_point.y;
|
||||
} break;
|
||||
case ZDWM_EFFECT_RESIZE_WINDOW: {
|
||||
window_configure_t *cfg =
|
||||
find_or_push_configure(cfgs, &cfg_count, e->as.resize.window);
|
||||
find_or_push_configure(configs, e->as.resize.window);
|
||||
cfg->mask |= XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||
cfg->value.width = (uint32_t)e->as.resize.width;
|
||||
cfg->value.height = (uint32_t)e->as.resize.height;
|
||||
@@ -488,18 +498,15 @@ bool backend_apply_effect(
|
||||
.border_pixel = e->as.change_border_color.color->argb
|
||||
};
|
||||
xcb_change_window_attributes_aux(
|
||||
conn,
|
||||
backend->conn,
|
||||
e->as.change_border_color.window,
|
||||
XCB_CW_BORDER_PIXEL,
|
||||
&value
|
||||
);
|
||||
} break;
|
||||
case ZDWM_EFFECT_CHANGE_BORDER_WIDTH: {
|
||||
window_configure_t *cfg = find_or_push_configure(
|
||||
cfgs,
|
||||
&cfg_count,
|
||||
e->as.change_border_width.window
|
||||
);
|
||||
window_configure_t *cfg =
|
||||
find_or_push_configure(configs, e->as.change_border_width.window);
|
||||
cfg->mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
|
||||
cfg->value.border_width = e->as.change_border_width.border_width;
|
||||
} break;
|
||||
@@ -512,14 +519,56 @@ bool backend_apply_effect(
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cfg_count; ++i) {
|
||||
flush_configure(conn, &cfgs[i]);
|
||||
static void backend_batch_apply_effects(backend_t *backend) {
|
||||
xcb_connection_t *conn = backend->conn;
|
||||
if (backend->unmap.count) {
|
||||
xcb_grab_server(conn);
|
||||
window_clean_event_mask(conn, backend->screen->root);
|
||||
|
||||
window_list_t *unmap = &backend->unmap;
|
||||
for (size_t i = 0; i < unmap->count; ++i) {
|
||||
xcb_window_t window = unmap->windows[i];
|
||||
window_clean_event_mask(conn, window);
|
||||
xcb_unmap_window(conn, window);
|
||||
}
|
||||
|
||||
root_set_event_mask(backend);
|
||||
xcb_ungrab_server(conn);
|
||||
}
|
||||
p_delete(&cfgs);
|
||||
|
||||
if (focus_window_changed) backend_focus_window(backend, focus_window);
|
||||
for (size_t i = 0; i < backend->map.count; ++i) {
|
||||
xcb_window_t window = backend->map.windows[i];
|
||||
window_set_event_mask(conn, window);
|
||||
xcb_map_window(conn, window);
|
||||
}
|
||||
|
||||
xcb_flush(conn);
|
||||
for (size_t i = 0; i < backend->kill.count; ++i) {
|
||||
window_kill(backend, backend->kill.windows[i]);
|
||||
}
|
||||
|
||||
backend_apply_window_configure_list(backend);
|
||||
|
||||
if (backend->update_focus) {
|
||||
backend_focus_window(backend, backend->focus_window);
|
||||
}
|
||||
}
|
||||
|
||||
bool backend_apply_effect(
|
||||
backend_t *backend,
|
||||
const effect_t *effects,
|
||||
size_t effect_count
|
||||
) {
|
||||
backend->update_focus = false;
|
||||
window_configure_list_reset(&backend->config_list);
|
||||
window_list_reset(&backend->unmap);
|
||||
window_list_reset(&backend->map);
|
||||
window_list_reset(&backend->kill);
|
||||
|
||||
backend_merge_effects(backend, effects, effect_count);
|
||||
backend_batch_apply_effects(backend);
|
||||
|
||||
xcb_flush(backend->conn);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
@@ -13,6 +15,7 @@
|
||||
\
|
||||
X(WM_PROTOCOLS) \
|
||||
X(WM_TAKE_FOCUS) \
|
||||
X(WM_DELETE_WINDOW) \
|
||||
X(_NET_ACTIVE_WINDOW) \
|
||||
\
|
||||
X(_NET_SUPPORTING_WM_CHECK) \
|
||||
@@ -54,6 +57,24 @@ typedef struct atoms_t {
|
||||
#undef DECLARATION_ATOM
|
||||
} atoms_t;
|
||||
|
||||
typedef struct window_configure_t {
|
||||
xcb_window_t window;
|
||||
uint16_t mask;
|
||||
xcb_configure_window_value_list_t value;
|
||||
} window_configure_t;
|
||||
|
||||
typedef struct window_configure_list_t {
|
||||
window_configure_t *cfgs;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} window_configure_list_t;
|
||||
|
||||
typedef struct window_list_t {
|
||||
xcb_window_t *windows;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} window_list_t;
|
||||
|
||||
struct backend_t {
|
||||
xcb_connection_t *conn;
|
||||
xcb_screen_t *screen;
|
||||
@@ -65,4 +86,12 @@ struct backend_t {
|
||||
/* When no window should take focus, then focus this window */
|
||||
xcb_window_t window_no_focus;
|
||||
xcb_window_t wm_check_window;
|
||||
|
||||
xcb_window_t focus_window;
|
||||
bool update_focus;
|
||||
|
||||
window_configure_list_t config_list;
|
||||
window_list_t unmap;
|
||||
window_list_t map;
|
||||
window_list_t kill;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "base/array.h"
|
||||
#include "base/memory.h"
|
||||
#include "core/backend.h"
|
||||
#include "internal.h"
|
||||
@@ -244,16 +245,84 @@ window_state_t atom_to_window_state(const atoms_t *atoms, xcb_atom_t atom) {
|
||||
return (window_state_t)-1;
|
||||
}
|
||||
|
||||
void window_takefocus(backend_t *backend, xcb_window_t window) {
|
||||
xcb_client_message_event_t ev = {0};
|
||||
|
||||
ev.response_type = XCB_CLIENT_MESSAGE;
|
||||
ev.window = window;
|
||||
ev.format = 32;
|
||||
ev.type = backend->atoms.WM_PROTOCOLS,
|
||||
ev.data.data32[0] = backend->atoms.WM_TAKE_FOCUS;
|
||||
ev.data.data32[1] = XCB_CURRENT_TIME;
|
||||
static bool
|
||||
window_send_event(backend_t *backend, xcb_window_t window, xcb_atom_t atom) {
|
||||
bool exist = false;
|
||||
|
||||
xcb_connection_t *conn = backend->conn;
|
||||
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
|
||||
auto WM_PROTOCOLS = backend->atoms.WM_PROTOCOLS;
|
||||
|
||||
xcb_get_property_cookie_t cookie =
|
||||
xcb_icccm_get_wm_protocols_unchecked(conn, window, WM_PROTOCOLS);
|
||||
xcb_icccm_get_wm_protocols_reply_t reply = {0};
|
||||
if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, nullptr)) {
|
||||
for (uint32_t i = 0; !exist && i < reply.atoms_len; ++i) {
|
||||
exist = reply.atoms[i] == atom;
|
||||
}
|
||||
xcb_icccm_get_wm_protocols_reply_wipe(&reply);
|
||||
}
|
||||
|
||||
if (exist) {
|
||||
xcb_client_message_event_t ev = {
|
||||
.response_type = XCB_CLIENT_MESSAGE,
|
||||
.format = 32,
|
||||
.window = window,
|
||||
.type = WM_PROTOCOLS,
|
||||
.data.data32 = {atom, XCB_CURRENT_TIME},
|
||||
};
|
||||
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
void window_takefocus(backend_t *backend, xcb_window_t window) {
|
||||
window_send_event(backend, window, backend->atoms.WM_TAKE_FOCUS);
|
||||
}
|
||||
|
||||
void window_kill(backend_t *backend, xcb_window_t window) {
|
||||
if (window_send_event(backend, window, backend->atoms.WM_DELETE_WINDOW)) {
|
||||
xcb_kill_client(backend->conn, window);
|
||||
}
|
||||
}
|
||||
|
||||
void root_set_event_mask(backend_t *backend) {
|
||||
xcb_connection_t *conn = backend->conn;
|
||||
xcb_window_t root = backend->screen->root;
|
||||
xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
|
||||
xcb_change_window_attributes_value_list_t value_list = {
|
||||
.event_mask =
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_KEY_PRESS,
|
||||
};
|
||||
xcb_change_window_attributes_aux(conn, root, change_mask, &value_list);
|
||||
}
|
||||
|
||||
void window_set_event_mask(xcb_connection_t *conn, xcb_window_t window) {
|
||||
xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
|
||||
xcb_change_window_attributes_value_list_t value_list = {
|
||||
.event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE |
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
||||
};
|
||||
xcb_change_window_attributes_aux(conn, window, change_mask, &value_list);
|
||||
}
|
||||
|
||||
void window_clean_event_mask(xcb_connection_t *conn, xcb_window_t window) {
|
||||
xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
|
||||
xcb_change_window_attributes_value_list_t value_list = {
|
||||
.event_mask = XCB_EVENT_MASK_NO_EVENT,
|
||||
};
|
||||
xcb_change_window_attributes_aux(conn, window, change_mask, &value_list);
|
||||
}
|
||||
|
||||
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);
|
||||
*win = window;
|
||||
}
|
||||
|
||||
void window_list_reset(window_list_t *window_list) {
|
||||
p_clear(window_list->windows, window_list->count);
|
||||
window_list->count = 0;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "core/backend.h"
|
||||
#include "core/window.h"
|
||||
#include "internal.h"
|
||||
|
||||
typedef struct atoms_t atoms_t;
|
||||
typedef struct window_list_t window_list_t;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口的 role 属性
|
||||
@@ -78,3 +79,11 @@ window_state_t atom_to_window_state(const atoms_t *atoms, xcb_atom_t atom);
|
||||
xcb_icccm_set_wm_class(conn, win, sizeof(instance_class), instance_class)
|
||||
|
||||
void window_takefocus(backend_t *backend, xcb_window_t window);
|
||||
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_list_push(window_list_t *window_list, xcb_window_t window);
|
||||
void window_list_reset(window_list_t *window_list);
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
|
||||
typedef enum command_type_t {
|
||||
ZDWM_COMMAND_MANAGE_WINDOW,
|
||||
ZDWM_COMMAND_SWITCH_WORKSPACE
|
||||
ZDWM_COMMAND_UNMANAGE_WINDOW,
|
||||
ZDWM_COMMAND_FOCUS_WINDOW,
|
||||
ZDWM_COMMAND_KILL_WINDOW,
|
||||
ZDWM_COMMAND_SWITCH_WORKSPACE,
|
||||
} command_type_t;
|
||||
|
||||
typedef struct manage_window_command_t {
|
||||
@@ -19,6 +22,10 @@ typedef struct switch_workspace_command_t {
|
||||
workspace_id_t workspace;
|
||||
} switch_workspace_command_t;
|
||||
|
||||
typedef struct only_window_command_t {
|
||||
window_id_t window;
|
||||
} only_window_command_t;
|
||||
|
||||
/**
|
||||
* @brief 非 owning 的命令值对象
|
||||
* @details
|
||||
@@ -32,6 +39,9 @@ typedef struct command_t {
|
||||
command_type_t type;
|
||||
union {
|
||||
manage_window_command_t manage_window;
|
||||
only_window_command_t unmanage;
|
||||
only_window_command_t focus;
|
||||
only_window_command_t kill;
|
||||
switch_workspace_command_t switch_workspace;
|
||||
} as;
|
||||
} command_t;
|
||||
|
||||
@@ -9,6 +9,7 @@ typedef enum effect_type_t {
|
||||
ZDWM_EFFECT_MAP_WINDOW = 1,
|
||||
ZDWM_EFFECT_UNMAP_WINDOW,
|
||||
ZDWM_EFFECT_FOCUS_WINDOW,
|
||||
ZDWM_EFFECT_KILL_WINDOW,
|
||||
ZDWM_EFFECT_MOVE_WINDOW,
|
||||
ZDWM_EFFECT_RESIZE_WINDOW,
|
||||
ZDWM_EFFECT_CHANGE_BORDER_COLOR,
|
||||
@@ -53,6 +54,7 @@ typedef struct effect_t {
|
||||
effect_only_window_id_t map;
|
||||
effect_only_window_id_t unmap;
|
||||
effect_only_window_id_t focus;
|
||||
effect_only_window_id_t kill;
|
||||
effect_move_window_t move;
|
||||
effect_resize_window_t resize;
|
||||
effect_change_border_color_t change_border_color;
|
||||
|
||||
@@ -32,7 +32,7 @@ static void route_map_request(
|
||||
if (window) layer_type = MAX(window->layer, layer_type);
|
||||
}
|
||||
|
||||
command_t cmd = {
|
||||
command_t manage_window_cmd = {
|
||||
.type = ZDWM_COMMAND_MANAGE_WINDOW,
|
||||
.as.manage_window = {
|
||||
.workspace = derive_window_workspace(state),
|
||||
@@ -59,7 +59,7 @@ static void route_map_request(
|
||||
rule_action_t action = {.workspace = ZDWM_WORKSPACE_ID_INVALID};
|
||||
bool have_rule_match = rules_resolve(rules, &e->metadata, &action);
|
||||
if (have_rule_match) {
|
||||
manage_window_command_t *data = &cmd.as.manage_window;
|
||||
manage_window_command_t *data = &manage_window_cmd.as.manage_window;
|
||||
if (action.workspace != ZDWM_WORKSPACE_ID_INVALID) {
|
||||
data->workspace = action.workspace;
|
||||
}
|
||||
@@ -74,9 +74,9 @@ static void route_map_request(
|
||||
}
|
||||
}
|
||||
|
||||
command_buffer_push(out, &cmd);
|
||||
command_buffer_push(out, &manage_window_cmd);
|
||||
if (have_rule_match && action.switch_to_workspace) {
|
||||
workspace_id_t workspace_id = cmd.as.manage_window.workspace;
|
||||
workspace_id_t workspace_id = manage_window_cmd.as.manage_window.workspace;
|
||||
const workspace_t *workspace = state_workspace_get(state, workspace_id);
|
||||
|
||||
if (workspace) {
|
||||
@@ -93,6 +93,21 @@ static void route_map_request(
|
||||
}
|
||||
}
|
||||
|
||||
static void route_window_remove(
|
||||
state_t *state,
|
||||
const window_remove_event_t *e,
|
||||
command_buffer_t *out
|
||||
) {
|
||||
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);
|
||||
}
|
||||
|
||||
void policy_route_event(
|
||||
const policy_context_t *ctx,
|
||||
const event_t *event,
|
||||
@@ -100,11 +115,12 @@ void policy_route_event(
|
||||
) {
|
||||
auto state = ctx->state;
|
||||
switch (event->type) {
|
||||
case ZDWM_EVENT_WINDOW_MAP_REQUEST: {
|
||||
auto rules = ctx->rules;
|
||||
route_map_request(state, rules, &event->as.window_map_request, out);
|
||||
case ZDWM_EVENT_WINDOW_MAP_REQUEST:
|
||||
route_map_request(state, ctx->rules, &event->as.window_map_request, out);
|
||||
break;
|
||||
case ZDWM_EVENT_WINDOW_REMOVE:
|
||||
route_window_remove(state, &event->as.window_remove, out);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -174,6 +190,56 @@ static void add_switch_workspace_effects(
|
||||
plan_push_effect(plan, &focus_effect);
|
||||
}
|
||||
|
||||
static void unmanage_window(state_t *state, window_id_t window, plan_t *plan) {
|
||||
const window_t *win = state_window_get(state, window);
|
||||
if (!win) return;
|
||||
|
||||
auto workspace_id = win->workspace_id;
|
||||
auto workspace = state_workspace_get(state, workspace_id);
|
||||
auto output = state_output_get(state, workspace->output_id);
|
||||
|
||||
auto old_focused_window = workspace->focused_window_id;
|
||||
state_window_remove(state, window);
|
||||
if (output->current_workspace_id != workspace_id) return;
|
||||
|
||||
if (old_focused_window != workspace->focused_window_id) {
|
||||
effect_t focus_effect = {
|
||||
.type = ZDWM_EFFECT_FOCUS_WINDOW,
|
||||
.as.focus.window = workspace->focused_window_id
|
||||
};
|
||||
plan_push_effect(plan, &focus_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;
|
||||
|
||||
auto workspace_id = win->workspace_id;
|
||||
auto workspace = state_workspace_get(state, workspace_id);
|
||||
auto old_focused_window = workspace->focused_window_id;
|
||||
|
||||
state_workspace_set_focused_window(state, workspace_id, window);
|
||||
if (old_focused_window == workspace->focused_window_id) return;
|
||||
|
||||
effect_t focus_effect = {
|
||||
.type = ZDWM_EFFECT_FOCUS_WINDOW,
|
||||
.as.focus.window = workspace->focused_window_id,
|
||||
};
|
||||
plan_push_effect(plan, &focus_effect);
|
||||
}
|
||||
|
||||
static void kill_window(state_t *state, window_id_t window, plan_t *plan) {
|
||||
auto win = state_window_get(state, window);
|
||||
if (!win) return;
|
||||
|
||||
effect_t kill_effect = {
|
||||
.type = ZDWM_EFFECT_KILL_WINDOW,
|
||||
.as.kill.window = window,
|
||||
};
|
||||
plan_push_effect(plan, &kill_effect);
|
||||
}
|
||||
|
||||
static void switch_workspace(
|
||||
state_t *state,
|
||||
const switch_workspace_command_t *command,
|
||||
@@ -208,6 +274,15 @@ void policy_apply_command(
|
||||
case ZDWM_COMMAND_MANAGE_WINDOW:
|
||||
manage_window(ctx, &cmd->as.manage_window, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_UNMANAGE_WINDOW:
|
||||
unmanage_window(state, cmd->as.unmanage.window, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_FOCUS_WINDOW:
|
||||
focus_window(state, cmd->as.focus.window, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_KILL_WINDOW:
|
||||
kill_window(state, cmd->as.kill.window, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_SWITCH_WORKSPACE:
|
||||
switch_workspace(state, &cmd->as.switch_workspace, plan);
|
||||
break;
|
||||
|
||||
@@ -386,14 +386,20 @@ void state_window_remove(state_t *state, window_id_t id) {
|
||||
p_delete(&window->class_name);
|
||||
p_delete(&window->instance_name);
|
||||
|
||||
for (size_t i = index + 1; i < state->window_count; i++) {
|
||||
state->windows[i - 1] = state->windows[i];
|
||||
if (array_erase(state->windows, state->window_count, index)) {
|
||||
window = &state->windows[state->window_count];
|
||||
p_clear(window, 1);
|
||||
window->id = ZDWM_WINDOW_ID_INVALID;
|
||||
window->transient_for = ZDWM_WINDOW_ID_INVALID;
|
||||
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
|
||||
|
||||
for (size_t i = 0; i < state->window_count; ++i) {
|
||||
window = &state->windows[i];
|
||||
if (window->transient_for != id) continue;
|
||||
|
||||
window->transient_for = ZDWM_WINDOW_ID_INVALID;
|
||||
}
|
||||
}
|
||||
window = &state->windows[state->window_count - 1];
|
||||
p_clear(window, 1);
|
||||
window->id = ZDWM_WINDOW_ID_INVALID;
|
||||
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
|
||||
state->window_count--;
|
||||
|
||||
layer_stack_t *layer = &state->stacks[layer_type];
|
||||
if (layer) {
|
||||
|
||||
@@ -166,7 +166,7 @@ bool state_set_current_output(state_t *state, output_id_t output_id);
|
||||
const window_t *state_window_add(state_t *state, const window_info_t *info);
|
||||
const window_t *state_window_get(const state_t *state, window_id_t id);
|
||||
const window_t *state_window_at(const state_t *state, size_t index);
|
||||
/* 删除窗口,并同步将其从对应的堆叠栈中移除 */
|
||||
/* 删除窗口,同步将其从对应的堆叠栈中移除,并调整对应 workspace 的焦点窗口 */
|
||||
void state_window_remove(state_t *state, window_id_t id);
|
||||
size_t state_window_count(const state_t *state);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user