feat(backend/X11): 处理 PropertyNotify 和 ClientMessage 事件
This commit is contained in:
@@ -275,6 +275,170 @@ static bool handle_enter_notify(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool handle_property_notify(
|
||||||
|
backend_t *backend,
|
||||||
|
event_t *event,
|
||||||
|
const xcb_property_notify_event_t *xcb_event
|
||||||
|
) {
|
||||||
|
auto window_id = xcb_event->window;
|
||||||
|
if (xcb_event->atom == backend->atoms.WM_NAME ||
|
||||||
|
xcb_event->atom == backend->atoms._NET_WM_NAME) {
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED;
|
||||||
|
|
||||||
|
auto data = &event->as.window_metadata_change;
|
||||||
|
data->window = window_id;
|
||||||
|
data->metadata.title = window_get_title(backend, window_id);
|
||||||
|
data->changed_fields = ZDWM_WINDOW_METADATA_CHANGE_TITLE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcb_event->atom == backend->atoms.WM_WINDOW_ROLE) {
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED;
|
||||||
|
|
||||||
|
auto data = &event->as.window_metadata_change;
|
||||||
|
data->window = window_id;
|
||||||
|
data->metadata.role = window_get_role(backend, window_id);
|
||||||
|
data->changed_fields = ZDWM_WINDOW_METADATA_CHANGE_ROLE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcb_event->atom == XCB_ATOM_WM_CLASS) {
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED;
|
||||||
|
|
||||||
|
auto data = &event->as.window_metadata_change;
|
||||||
|
data->window = window_id;
|
||||||
|
window_get_class(
|
||||||
|
backend,
|
||||||
|
window_id,
|
||||||
|
&data->metadata.class_name,
|
||||||
|
&data->metadata.instance_name
|
||||||
|
);
|
||||||
|
data->changed_fields =
|
||||||
|
ZDWM_WINDOW_METADATA_CHANGE_CLASS | ZDWM_WINDOW_METADATA_CHANGE_INSTANCE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcb_event->atom == XCB_ATOM_WM_HINTS) {
|
||||||
|
xcb_icccm_wm_hints_t hints = {0};
|
||||||
|
auto handled = window_get_wm_hints(backend, window_id, &hints);
|
||||||
|
if (!handled) return false;
|
||||||
|
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST;
|
||||||
|
|
||||||
|
auto data = &event->as.window_state_request;
|
||||||
|
data->window = window_id;
|
||||||
|
if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) {
|
||||||
|
data->type = ZDWM_WINDOW_STATE_REQUEST_URGENT;
|
||||||
|
data->action = xcb_icccm_wm_hints_get_urgency(&hints)
|
||||||
|
? ZDWM_WINDOW_STATE_ACTION_ADD
|
||||||
|
: ZDWM_WINDOW_STATE_ACTION_REMOVE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcb_event->atom == XCB_ATOM_WM_NORMAL_HINTS) {
|
||||||
|
bool fixed_size = false;
|
||||||
|
if (!window_get_fixed_size(backend, window_id, &fixed_size)) return false;
|
||||||
|
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST;
|
||||||
|
|
||||||
|
auto data = &event->as.window_state_request;
|
||||||
|
data->window = window_id;
|
||||||
|
data->type = ZDWM_WINDOW_STATE_REQUEST_FIXED_SIZE;
|
||||||
|
data->action = fixed_size ? ZDWM_WINDOW_STATE_ACTION_ADD
|
||||||
|
: ZDWM_WINDOW_STATE_ACTION_REMOVE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handle_client_message(
|
||||||
|
backend_t *backend,
|
||||||
|
event_t *event,
|
||||||
|
const xcb_client_message_event_t *xcb_event
|
||||||
|
) {
|
||||||
|
auto atoms = &backend->atoms;
|
||||||
|
|
||||||
|
if (xcb_event->type == atoms->_NET_ACTIVE_WINDOW) {
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_ACTIVATE_REQUEST;
|
||||||
|
event->as.window_activate_request.window = xcb_event->window;
|
||||||
|
event->as.window_activate_request.source = xcb_event->data.data32[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcb_event->type == atoms->WM_CHANGE_STATE) {
|
||||||
|
if (xcb_event->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) {
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST;
|
||||||
|
event->as.window_state_request.window = xcb_event->window;
|
||||||
|
event->as.window_state_request.type = ZDWM_WINDOW_STATE_REQUEST_MINIMIZED;
|
||||||
|
event->as.window_state_request.action = ZDWM_WINDOW_STATE_ACTION_ADD;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcb_event->type == atoms->_NET_WM_STATE) {
|
||||||
|
event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST;
|
||||||
|
auto data = &event->as.window_state_request;
|
||||||
|
data->window = xcb_event->window;
|
||||||
|
/**
|
||||||
|
* _NET_WM_STATE 协议数据格式为
|
||||||
|
* data.data32 = {
|
||||||
|
* action, // 操作类型(添加/移除/切换)
|
||||||
|
* property1, // 第一个状态原子(如_NET_WM_STATE_FULLSCREEN)
|
||||||
|
* property2, // 第二个状态原子(可选,通常为0)
|
||||||
|
* 0, // 预留字段(固定为0)
|
||||||
|
* 0 // 预留字段(固定为0)
|
||||||
|
* };
|
||||||
|
* action 值可能为
|
||||||
|
* _NET_WM_STATE_ADD(1):添加全屏状态,窗口进入全屏模式
|
||||||
|
* _NET_WM_STATE_REMOVE(0):移除全屏状态,窗口退出全屏模式
|
||||||
|
* _NET_WM_STATE_TOGGLE(2):切换全屏状态(若当前全屏则退出,反之进入)
|
||||||
|
*/
|
||||||
|
auto action = xcb_event->data.data32[0];
|
||||||
|
switch (action) {
|
||||||
|
case 0:
|
||||||
|
data->action = ZDWM_WINDOW_STATE_ACTION_REMOVE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
data->action = ZDWM_WINDOW_STATE_ACTION_ADD;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
data->action = ZDWM_WINDOW_STATE_ACTION_TOGGLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto properties = &xcb_event->data.data32[1];
|
||||||
|
uint32_t count = 2;
|
||||||
|
auto geometry_mode = geometry_mode_from_states(atoms, properties, count);
|
||||||
|
switch (geometry_mode) {
|
||||||
|
case ZDWM_GEOMETRY_FULLSCREEN:
|
||||||
|
data->type = ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN;
|
||||||
|
return true;
|
||||||
|
case ZDWM_GEOMETRY_MAXIMIZED:
|
||||||
|
data->type = ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED;
|
||||||
|
return true;
|
||||||
|
case ZDWM_GEOMETRY_MINIMIZED:
|
||||||
|
case ZDWM_GEOMETRY_NORMAL:
|
||||||
|
}
|
||||||
|
|
||||||
|
if (derive_skip_taskbar(atoms, properties, count)) {
|
||||||
|
data->type = ZDWM_WINDOW_STATE_REQUEST_SKIP_TASKBAR;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urgent_from_states(atoms, properties, count)) {
|
||||||
|
data->type = ZDWM_WINDOW_STATE_REQUEST_URGENT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool backend_next_event(backend_t *backend, event_t *event) {
|
bool backend_next_event(backend_t *backend, event_t *event) {
|
||||||
if (!backend || !backend->conn || !event) return false;
|
if (!backend || !backend->conn || !event) return false;
|
||||||
|
|
||||||
@@ -301,6 +465,8 @@ bool backend_next_event(backend_t *backend, event_t *event) {
|
|||||||
EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request);
|
EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request);
|
||||||
EVENT(XCB_KEY_PRESS, handle_key_press);
|
EVENT(XCB_KEY_PRESS, handle_key_press);
|
||||||
EVENT(XCB_ENTER_NOTIFY, handle_enter_notify);
|
EVENT(XCB_ENTER_NOTIFY, handle_enter_notify);
|
||||||
|
EVENT(XCB_PROPERTY_NOTIFY, handle_property_notify);
|
||||||
|
EVENT(XCB_CLIENT_MESSAGE, handle_client_message);
|
||||||
|
|
||||||
#undef EVENT
|
#undef EVENT
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
\
|
\
|
||||||
X(WM_WINDOW_ROLE) \
|
X(WM_WINDOW_ROLE) \
|
||||||
X(WM_NAME) \
|
X(WM_NAME) \
|
||||||
|
X(WM_CHANGE_STATE) \
|
||||||
X(_NET_WM_NAME) \
|
X(_NET_WM_NAME) \
|
||||||
\
|
\
|
||||||
X(WM_PROTOCOLS) \
|
X(WM_PROTOCOLS) \
|
||||||
|
|||||||
@@ -76,21 +76,6 @@ typedef struct window_metadata_change_event_t {
|
|||||||
window_metadata_t metadata;
|
window_metadata_t metadata;
|
||||||
} window_metadata_change_event_t;
|
} window_metadata_change_event_t;
|
||||||
|
|
||||||
typedef enum window_hint_changed_flags_t {
|
|
||||||
ZDWM_WINDOW_HINT_CHANGED_NONE = 0,
|
|
||||||
ZDWM_WINDOW_HINT_CHANGED_URGENT = 1u << 0,
|
|
||||||
ZDWM_WINDOW_HINT_CHANGED_FIXED_SIZE = 1u << 1,
|
|
||||||
ZDWM_WINDOW_HINT_CHANGED_SKIP_TASKBAR = 1u << 2,
|
|
||||||
} window_hint_changed_flags_t;
|
|
||||||
|
|
||||||
typedef struct window_hints_changed_event_t {
|
|
||||||
window_id_t window;
|
|
||||||
uint32_t changed_fields;
|
|
||||||
bool urgent;
|
|
||||||
bool fixed_size;
|
|
||||||
bool skip_taskbar;
|
|
||||||
} window_hints_changed_event_t;
|
|
||||||
|
|
||||||
typedef enum window_activation_source_t {
|
typedef enum window_activation_source_t {
|
||||||
ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
|
ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
|
||||||
ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
|
ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
|
||||||
@@ -119,7 +104,6 @@ typedef struct event_t {
|
|||||||
window_map_request_event_t window_map_request;
|
window_map_request_event_t window_map_request;
|
||||||
window_remove_event_t window_remove;
|
window_remove_event_t window_remove;
|
||||||
window_metadata_change_event_t window_metadata_change;
|
window_metadata_change_event_t window_metadata_change;
|
||||||
window_hints_changed_event_t window_hints_changed;
|
|
||||||
window_activate_request_event_t window_activate_request;
|
window_activate_request_event_t window_activate_request;
|
||||||
window_state_request_event_t window_state_request;
|
window_state_request_event_t window_state_request;
|
||||||
configure_data_t configure_request;
|
configure_data_t configure_request;
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ typedef enum window_state_request_type_t {
|
|||||||
ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN,
|
ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN,
|
||||||
ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED,
|
ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED,
|
||||||
ZDWM_WINDOW_STATE_REQUEST_MINIMIZED,
|
ZDWM_WINDOW_STATE_REQUEST_MINIMIZED,
|
||||||
|
ZDWM_WINDOW_STATE_REQUEST_SKIP_TASKBAR,
|
||||||
|
ZDWM_WINDOW_STATE_REQUEST_URGENT,
|
||||||
|
ZDWM_WINDOW_STATE_REQUEST_FIXED_SIZE,
|
||||||
} window_state_request_type_t;
|
} window_state_request_type_t;
|
||||||
|
|
||||||
typedef enum window_state_request_action_t {
|
typedef enum window_state_request_action_t {
|
||||||
|
|||||||
Reference in New Issue
Block a user