core: 添加 pointer enter 事件

This commit is contained in:
2026-03-22 02:12:31 +08:00
parent f573575ed6
commit ad22b0fe93
6 changed files with 80 additions and 8 deletions

View File

@@ -31,7 +31,8 @@ request event而不是直接改 core 状态。
4. =policy=
负责把事件路由为命令,并把命令应用到状态。
=WM_EVENT_KEY_PRESS= / =WM_EVENT_POINTER_BUTTON_PRESS= 的路由都使用 bootstrap
固定下来的输入绑定表
固定下来的输入绑定表;像 =WM_EVENT_POINTER_ENTER= 这种不经绑定的输入事实,
则由 policy 配置决定是否转换为 =FOCUS_WINDOW=。
5. =layout=
负责为某个输出上当前显示的工作区中的平铺窗口计算外框几何。
@@ -224,16 +225,19 @@ end
1. =focus_raises=
焦点切换时是否隐式执行 raise。
2. =sticky_windows_participate_in_direction_focus=
2. =pointer_enter_focuses_window=
收到 =WM_EVENT_POINTER_ENTER= 时是否切换焦点focus-follows-mouse
3. =sticky_windows_participate_in_direction_focus=
sticky 窗口是否参与方向焦点搜索。
3. =manage_sets_focus=
4. =manage_sets_focus=
新受管窗口是否默认夺取所属 workspace 的焦点。
4. =switch_workspace_restores_last_focus=
5. =switch_workspace_restores_last_focus=
切换工作区时是否恢复该 workspace 的最近焦点。
5. =minimize_clears_focus=
6. =minimize_clears_focus=
最小化当前焦点窗口时是否清空或重选该 workspace 焦点。
* 边框约定

View File

@@ -26,6 +26,7 @@ void wm_runtime_process_event(wm_runtime_t *runtime, const wm_event_t *event) {
if (!consumed) {
wm_policy_route_event(
&runtime->state,
&runtime->policy,
&runtime->keybindings,
&runtime->pointer_bindings,
event,
@@ -320,6 +321,7 @@ typedef struct wm_runtime_bootstrap_t {
#+BEGIN_SRC c
bool wm_policy_route_event(const wm_state_t *state,
const wm_policy_config_t *policy,
const wm_key_binding_table_t *keybindings,
const wm_pointer_binding_table_t *pointer_bindings,
const wm_event_t *event,
@@ -333,6 +335,10 @@ bool wm_policy_route_event(const wm_state_t *state,
return route_pointer_press(state, pointer_bindings,
&event->data.pointer_button_press, out);
case WM_EVENT_POINTER_ENTER:
return route_pointer_enter(state, policy,
&event->data.pointer_enter, out);
case WM_EVENT_WINDOW_MAP_REQUEST:
return route_map_request(state, &event->data.window_map_request, out);
@@ -514,6 +520,43 @@ static bool route_pointer_press(const wm_state_t *state,
return wm_command_buffer_push(out, cmd);
}
static bool route_pointer_enter(const wm_state_t *state,
const wm_policy_config_t *policy,
const wm_pointer_enter_event_t *e,
wm_command_buffer_t *out) {
const wm_window_t *win;
const wm_workspace_t *ws;
if (!policy->pointer_enter_focuses_window) {
return false;
}
if (e->window == WM_WINDOW_ID_INVALID) {
return false;
}
win = wm_state_window_get(state, e->window);
if (!win) {
return false;
}
if (win->workspace_id >= state->workspace_count) {
return false;
}
ws = &state->workspaces[win->workspace_id];
if (ws->focused_window_id == win->id) {
return false;
}
return wm_command_buffer_push(out, (wm_command_t){
.type = WM_COMMAND_FOCUS_WINDOW,
.as.focus_window = {
.window_id = win->id,
},
});
}
// 窗口映射请求路由
static bool route_map_request(const wm_state_t *state,
const wm_window_map_request_event_t *e,
@@ -757,6 +800,7 @@ static bool route_move_floating_event(wm_runtime_t *runtime,
|---------|---------------|------|
| KEY_PRESS | 任意命令(通过键盘绑定) | 绑定存在 |
| POINTER_BUTTON_PRESS | 任意窗口命令 / BEGIN_*_INTERACTION通过鼠标绑定 | 绑定存在 |
| POINTER_ENTER | FOCUS_WINDOW | policy.pointer_enter_focuses_window == true 且窗口已管理 |
| WINDOW_MAP_REQUEST | MANAGE_WINDOW | 窗口未管理 |
| WINDOW_REMOVE | UNMANAGE_WINDOW | 窗口已管理 |
| WINDOW_ACTIVATE_REQUEST | SWITCH_WORKSPACE + FOCUS_WINDOW / SET_WINDOW_URGENT | source == pager / source != pager |
@@ -768,9 +812,11 @@ static bool route_move_floating_event(wm_runtime_t *runtime,
1. `WM_EVENT_CONFIGURE_REQUEST` 只携带稀疏几何字段,不直接镜像 X11 全量协议载荷。
2. 最小核心当前只会把这些几何请求映射到 floating 窗口的 move/resize 语义。
3. `border_width` / `sibling` / `stack_mode` 这类协议细节留在 backend / adapter 层
4. fullscreen / maximize / minimize 这类窗口模式切换不属于 configure request
5. `WM_EVENT_WINDOW_STATE_REQUEST` 表达后端看到的原始 add/remove/toggle 请求;
3. `WM_EVENT_POINTER_ENTER` 是“pointer focus 进入窗口”的输入事实,不经过 pointer binding 表
4. 类似 `raise_or_run` 这类程序化恢复鼠标位置导致的单次 crossing 抑制,应由 runtime 维护瞬时状态后在路由前过滤,而不是下沉到 backend 业务逻辑
5. `border_width` / `sibling` / `stack_mode` 这类协议细节留在 backend / adapter 层。
6. fullscreen / maximize / minimize 这类窗口模式切换不属于 configure request。
7. `WM_EVENT_WINDOW_STATE_REQUEST` 表达后端看到的原始 add/remove/toggle 请求;
core command 仍保持 =SET_*= 这种最终状态语义。
* 事件处理的边界条件

View File

@@ -16,6 +16,8 @@ typedef enum wm_event_type_t {
WM_EVENT_POINTER_BUTTON_PRESS,
WM_EVENT_POINTER_BUTTON_RELEASE,
WM_EVENT_POINTER_MOTION,
// 指针焦点进入某个窗口;对应 X11 EnterNotify / Wayland wl_pointer.enter
WM_EVENT_POINTER_ENTER,
WM_EVENT_WINDOW_MAP_REQUEST,
WM_EVENT_WINDOW_REMOVE,
WM_EVENT_WINDOW_METADATA_CHANGED,
@@ -64,6 +66,15 @@ typedef struct wm_pointer_motion_event_t {
wm_window_id_t window;
} wm_pointer_motion_event_t;
typedef struct wm_pointer_enter_event_t {
// 全局桌面坐标
wm_point_t root;
// 相对 window 的坐标;若 window == WM_WINDOW_ID_INVALID则该值未定义
wm_point_t local;
// 当前进入并获得 pointer focus 的窗口;若未命中窗口,则为 WM_WINDOW_ID_INVALID
wm_window_id_t window;
} wm_pointer_enter_event_t;
typedef struct wm_window_map_request_event_t {
wm_window_info_t info;
// 仅用于 manage 路由判断,不进入持久 state
@@ -204,6 +215,7 @@ typedef struct wm_event_t {
wm_pointer_button_event_t pointer_button_press;
wm_pointer_button_event_t pointer_button_release;
wm_pointer_motion_event_t pointer_motion;
wm_pointer_enter_event_t pointer_enter;
wm_window_map_request_event_t window_map_request;
wm_window_remove_event_t window_remove;
wm_window_metadata_changed_event_t window_metadata_changed;

View File

@@ -21,6 +21,7 @@ void wm_command_buffer_shutdown(wm_command_buffer_t *buffer);
bool wm_command_buffer_push(wm_command_buffer_t *buffer, wm_command_t command);
bool wm_policy_route_event(const wm_state_t *state,
const wm_policy_config_t *policy,
const wm_key_binding_table_t *keybindings,
const wm_pointer_binding_table_t *pointer_bindings,
const wm_event_t *event,

View File

@@ -4,6 +4,7 @@
typedef struct wm_policy_config_t {
bool focus_raises;
bool pointer_enter_focuses_window;
bool sticky_windows_participate_in_direction_focus;
bool manage_sets_focus;
bool switch_workspace_restores_last_focus;