Compare commits

...

5 Commits

18 changed files with 583 additions and 33 deletions

View File

@@ -26,6 +26,8 @@ project(${APP_NAME}
add_executable(${APP_NAME}
${SOURCE_DIR}/backend/output_utils.c
${SOURCE_DIR}/backend/x11/backend.c
${SOURCE_DIR}/backend/x11/common.c
${SOURCE_DIR}/backend/x11/cursor.c
${SOURCE_DIR}/backend/x11/event.c
${SOURCE_DIR}/backend/x11/window.c
@@ -76,6 +78,7 @@ find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED
xcb
xcb-aux
xcb-cursor
xcb-icccm
xcb-keysyms
xcb-randr

View File

@@ -18,6 +18,7 @@
#include <xcb/xproto.h>
#include "backend/output_utils.h"
#include "backend/x11/cursor.h"
#include "backend/x11/window.h"
#include "base/app.h"
#include "base/array.h"
@@ -184,10 +185,13 @@ backend_t *backend_create(const char *display_name) {
backend->key_symbols = xcb_key_symbols_alloc(conn);
cursor_init(backend);
atoms_init(backend);
create_wm_check_window(backend);
create_no_focus_window(backend);
window_change_cursor(backend, root, ZDWM_CURSOR_NORMAL);
return backend;
}
@@ -204,6 +208,8 @@ void backend_destroy(backend_t *backend) {
xcb_key_symbols_free(backend->key_symbols);
backend->key_symbols = nullptr;
cursor_cleanup(backend);
xcb_disconnect(backend->conn);
backend->conn = nullptr;
free(backend);
@@ -516,6 +522,33 @@ backend_bind_key(backend_t *backend, const effect_bind_key_t *bind_key) {
window_grab_keys(backend, root, bind_key->keys, bind_key->count);
}
static void backend_grab_button(
backend_t *backend,
const effect_grab_button_t *grab_button
) {
auto conn = backend->conn;
auto window = grab_button->window;
xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY);
auto buttons = grab_button->buttons;
for (size_t i = 0; i < grab_button->count; ++i) {
auto button = buttons[i].button;
auto modifiers = buttons[i].modifiers;
window_grab_button(backend, window, button, modifiers);
}
}
static void backend_grab_pointer(backend_t *backend, cursor_t cursor) {
auto conn = backend->conn;
auto root = backend->screen->root;
auto mask = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION;
auto mode = XCB_GRAB_MODE_ASYNC;
auto xcursor = cursor_get_xcb_cursor(backend, cursor);
auto time = XCB_TIME_CURRENT_TIME;
xcb_grab_pointer(conn, false, root, mask, mode, mode, root, xcursor, time);
}
static void backend_merge_effects(
backend_t *backend,
const effect_t *effects,
@@ -544,6 +577,12 @@ static void backend_merge_effects(
XCB_ICCCM_WM_STATE_WITHDRAWN
);
break;
case ZDWM_EFFECT_START_MOVE_WINDOW:
backend_grab_pointer(backend, ZDWM_CURSOR_MOVE);
break;
case ZDWM_EFFECT_START_RESIZE_WINDOW:
backend_grab_pointer(backend, ZDWM_CURSOR_RESIZE);
break;
case ZDWM_EFFECT_MINIMIZE_WINDOW: {
auto window = e->as.minimize.window;
xcb_icccm_wm_state_t state = XCB_ICCCM_WM_STATE_NORMAL;
@@ -595,6 +634,12 @@ static void backend_merge_effects(
case ZDWM_EFFECT_BIND_KEY:
backend_bind_key(backend, &e->as.bind_key);
break;
case ZDWM_EFFECT_GRAB_BUTTON:
backend_grab_button(backend, &e->as.grab_button);
break;
case ZDWM_EFFECT_UNGRAB_POINTER:
xcb_ungrab_pointer(backend->conn, XCB_CURRENT_TIME);
break;
}
}
}

71
src/backend/x11/common.c Normal file
View File

@@ -0,0 +1,71 @@
#include "common.h"
#include <stddef.h>
#include <stdint.h>
#include <xcb/xproto.h>
#include "base/macros.h"
#include "core/types.h"
typedef struct modifier_map_t {
modifier_bit_t modifier;
xcb_mod_mask_t mask;
} modifier_map_t;
static constexpr modifier_map_t modifier_map[] = {
{ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT},
{ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL},
{ZDWM_MOD_1, XCB_MOD_MASK_1},
{ZDWM_MOD_2, XCB_MOD_MASK_2},
{ZDWM_MOD_3, XCB_MOD_MASK_3},
{ZDWM_MOD_4, XCB_MOD_MASK_4},
{ZDWM_MOD_5, XCB_MOD_MASK_5},
};
modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask) {
modifier_mask_t mods = ZDWM_MOD_NONE;
for (size_t i = 0; i < countof(modifier_map); ++i) {
auto item = &modifier_map[i];
if (mask & item->mask) mods |= item->modifier;
}
return mods;
}
uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask) {
uint16_t mods = 0U;
for (size_t i = 0; i < countof(modifier_map); ++i) {
auto item = &modifier_map[i];
if (mask & item->modifier) mods |= item->mask;
}
return mods;
}
typedef struct button_map_t {
button_t zdwm_button;
xcb_button_index_t xcb_button;
} button_map_t;
static constexpr button_map_t button_map[] = {
{ZDWM_BUTTON_LEFT, XCB_BUTTON_INDEX_1},
{ZDWM_BUTTON_RIGHT, XCB_BUTTON_INDEX_3},
{ZDWM_BUTTON_MIDDLE, XCB_BUTTON_INDEX_2},
/* TODO: 后续可以考虑加上鼠标滚轮事件 */
};
button_t button_xcb_to_zdwm(xcb_button_t button) {
for (size_t i = 0; i < countof(button_map); ++i) {
auto item = &button_map[i];
if (button == item->xcb_button) return item->zdwm_button;
}
return ZDWM_BUTTON_NONE;
}
xcb_button_t button_zdwm_to_xcb(button_t button) {
for (size_t i = 0; i < countof(button_map); ++i) {
auto item = &button_map[i];
if (button == item->zdwm_button) return item->xcb_button;
}
return XCB_BUTTON_INDEX_ANY;
}

12
src/backend/x11/common.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
#include <xcb/xproto.h>
#include "core/types.h"
modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask);
uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask);
button_t button_xcb_to_zdwm(xcb_button_t button);
xcb_button_t button_zdwm_to_xcb(button_t button);

51
src/backend/x11/cursor.c Normal file
View File

@@ -0,0 +1,51 @@
#include <stddef.h>
#include <xcb/xcb_cursor.h>
#include <xcb/xproto.h>
#include "base/macros.h"
#include "base/memory.h"
#include "internal.h"
static const char *const cursor_name_map[] = {
[ZDWM_CURSOR_NORMAL] = "left_ptr",
[ZDWM_CURSOR_MOVE] = "fleur",
[ZDWM_CURSOR_RESIZE] = "bottom_right_corner",
};
static xcb_cursor_context_t *get_xcb_cursor_context(backend_t *backend) {
if (backend->cursor_context) return backend->cursor_context;
auto conn = backend->conn;
auto screen = backend->screen;
if (xcb_cursor_context_new(conn, screen, &backend->cursor_context) == 0) {
return backend->cursor_context;
}
return nullptr;
}
void cursor_init(backend_t *backend) {
auto ctx = get_xcb_cursor_context(backend);
if (!ctx) return;
for (size_t i = 0; i < countof(backend->cursors); ++i) {
auto cursor_name = cursor_name_map[i];
backend->cursors[i] = xcb_cursor_load_cursor(ctx, cursor_name);
}
}
void cursor_cleanup(backend_t *backend) {
constexpr size_t count = countof(backend->cursors);
for (size_t i = 0; i < count; ++i) {
xcb_free_cursor(backend->conn, backend->cursors[i]);
}
p_clear(backend->cursors, count);
xcb_cursor_context_free(backend->cursor_context);
backend->cursor_context = nullptr;
}
xcb_cursor_t cursor_get_xcb_cursor(backend_t *backend, cursor_t cursor) {
if (backend->cursor_context == nullptr) return XCB_CURSOR_NONE;
return backend->cursors[cursor];
}

9
src/backend/x11/cursor.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <xcb/xproto.h>
#include "internal.h"
void cursor_init(backend_t *backend);
void cursor_cleanup(backend_t *backend);
xcb_cursor_t cursor_get_xcb_cursor(backend_t *backend, cursor_t cursor);

View File

@@ -1,5 +1,6 @@
#include "core/event.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <xcb/xcb.h>
@@ -8,8 +9,8 @@
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
#include "backend/x11/common.h"
#include "backend/x11/window.h"
#include "base/macros.h"
#include "base/memory.h"
#include "core/backend.h"
#include "core/types.h"
@@ -232,29 +233,6 @@ static bool handle_configure_request(
return true;
}
static modifier_mask_t get_modifiers(uint16_t mask) {
typedef struct modifier_map_t {
modifier_bit_t modifier;
xcb_mod_mask_t mask;
} modifier_map_t;
static constexpr modifier_map_t modifier_map[] = {
{ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT},
{ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL},
{ZDWM_MOD_1, XCB_MOD_MASK_1},
{ZDWM_MOD_2, XCB_MOD_MASK_2},
{ZDWM_MOD_3, XCB_MOD_MASK_3},
{ZDWM_MOD_4, XCB_MOD_MASK_4},
{ZDWM_MOD_5, XCB_MOD_MASK_5},
};
auto mods = ZDWM_MOD_NONE;
for (size_t i = 0; i < countof(modifier_map); ++i) {
auto item = &modifier_map[i];
if (mask & item->mask) mods |= item->modifier;
}
return mods;
}
static bool handle_key_press(
backend_t *backend,
event_t *event,
@@ -268,11 +246,64 @@ static bool handle_key_press(
event->type = ZDWM_EVENT_KEY_PRESS;
event->as.key_press.keycode = keycode;
event->as.key_press.keysym = keysym;
event->as.key_press.modifiers = get_modifiers(xcb_event->state);
event->as.key_press.modifiers = modifiers_xcb_to_zdwm(xcb_event->state);
return true;
}
static bool fill_button_event(
const xcb_button_press_event_t *xcb_event,
pointer_button_event_t *data
) {
auto button = button_xcb_to_zdwm(xcb_event->detail);
data->modifiers = modifiers_xcb_to_zdwm(xcb_event->state);
data->button = button;
data->window = xcb_event->event;
data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y};
data->local = (point_t){.x = xcb_event->event_x, .y = xcb_event->event_y};
return true;
}
static bool handle_button_press(
backend_t *backend,
event_t *event,
const xcb_button_press_event_t *xcb_event
) {
auto press = &event->as.pointer_button_press;
auto handled = fill_button_event(xcb_event, press);
if (handled) event->type = ZDWM_EVENT_POINTER_BUTTON_PRESS;
return handled;
}
static bool handle_button_release(
backend_t *backend,
event_t *event,
const xcb_button_release_event_t *xcb_event
) {
auto release = &event->as.pointer_button_release;
auto handled = fill_button_event(xcb_event, release);
if (handled) event->type = ZDWM_EVENT_POINTER_BUTTON_RELEASE;
return handled;
}
static bool handle_motion_notify(
backend_t *backend,
event_t *event,
const xcb_motion_notify_event_t *xcb_event
) {
event->type = ZDWM_EVENT_POINTER_MOTION;
auto data = &event->as.pointer_motion;
data->window = xcb_event->event;
data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y};
data->local = (point_t){.x = xcb_event->event_x, .y = xcb_event->event_y};
return true;
}
static bool handle_enter_notify(
backend_t *backend,
event_t *event,
@@ -469,6 +500,9 @@ static bool handle_event(
EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify);
EVENT(XCB_CONFIGURE_REQUEST, handle_configure_request);
EVENT(XCB_KEY_PRESS, handle_key_press);
EVENT(XCB_BUTTON_PRESS, handle_button_press);
EVENT(XCB_BUTTON_RELEASE, handle_button_release);
EVENT(XCB_MOTION_NOTIFY, handle_motion_notify);
EVENT(XCB_ENTER_NOTIFY, handle_enter_notify);
EVENT(XCB_PROPERTY_NOTIFY, handle_property_notify);
EVENT(XCB_CLIENT_MESSAGE, handle_client_message);

View File

@@ -3,6 +3,7 @@
#include <stddef.h>
#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/xcb_cursor.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
@@ -78,7 +79,14 @@ typedef struct window_configure_list_t {
size_t capacity;
} window_configure_list_t;
struct backend_t {
typedef enum cursor_t {
ZDWM_CURSOR_NORMAL,
ZDWM_CURSOR_MOVE,
ZDWM_CURSOR_RESIZE,
ZDWM_CURSOR_COUNT,
} cursor_t;
typedef struct backend_t {
xcb_key_symbols_t *key_symbols;
xcb_connection_t *conn;
xcb_screen_t *screen;
@@ -94,11 +102,14 @@ struct backend_t {
xcb_window_t focus_window;
bool update_focus;
xcb_cursor_t cursors[ZDWM_CURSOR_COUNT];
xcb_cursor_context_t *cursor_context;
window_configure_list_t config_list;
window_list_t unmap;
window_list_t map;
window_list_t kill;
};
} backend_t;
bool populate_window_event(
struct backend_t *backend,

View File

@@ -3,10 +3,13 @@
#include <stddef.h>
#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
#include "backend/x11/common.h"
#include "backend/x11/cursor.h"
#include "base/macros.h"
#include "base/memory.h"
#include "core/backend.h"
@@ -451,3 +454,36 @@ visual_t *window_get_visual(backend_t *backend, bool prefer_alpha) {
return visual;
}
void window_change_cursor(
backend_t *backend,
xcb_window_t window,
cursor_t cursor
) {
auto conn = backend->conn;
xcb_params_cw_t params = {.cursor = cursor_get_xcb_cursor(backend, cursor)};
xcb_aux_change_window_attributes(conn, window, XCB_CW_CURSOR, &params);
}
void window_grab_button(
backend_t *backend,
xcb_window_t window,
button_t button,
modifier_mask_t modifiers
) {
auto xcb_button = button_zdwm_to_xcb(button);
if (xcb_button == XCB_BUTTON_INDEX_ANY) return;
xcb_grab_button(
backend->conn,
false, /* 事件仅发送给抓取者,不发送给其他窗口 */
window,
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_SYNC,
XCB_WINDOW_NONE,
XCB_CURSOR_NONE,
xcb_button,
modifiers_zdwm_to_xcb(modifiers)
);
}

View File

@@ -118,3 +118,16 @@ typedef struct visual_t {
* @returns 返回的信息使用后记得使用 free 释放
*/
visual_t *window_get_visual(backend_t *backend, bool prefer_alpha);
void window_change_cursor(
backend_t *backend,
xcb_window_t window,
cursor_t cursor
);
void window_grab_button(
backend_t *backend,
xcb_window_t window,
button_t button,
modifier_mask_t modifiers
);

View File

@@ -12,6 +12,10 @@ typedef enum command_type_t {
ZDWM_COMMAND_WITHDRAW_WINDOW,
ZDWM_COMMAND_CONFIGURE_WINDOW,
ZDWM_COMMAND_CHANGE_WINDOW_STATE,
ZDWM_COMMAND_START_MOVE_WINDOW,
ZDWM_COMMAND_STOP_MOVE_WINDOW,
ZDWM_COMMAND_START_RESIZE_WINDOW,
ZDWM_COMMAND_STOP_RESIZE_WINDOW,
ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE,
ZDWM_COMMAND_WINDOW_SET_FLOATING,
ZDWM_COMMAND_WINDOW_SET_STICKY,
@@ -42,6 +46,11 @@ typedef struct window_state_change_command_t {
window_state_request_action_t action;
} window_state_change_command_t;
typedef struct window_start_move_command_t {
window_id_t window;
point_t pointer_coordinate;
} start_interaction_command_t;
typedef struct window_send_to_workspace_command_t {
window_id_t window;
workspace_id_t workspace;
@@ -93,6 +102,8 @@ typedef struct command_t {
only_window_data_t withdraw;
configure_data_t configure;
window_state_change_command_t state_change;
start_interaction_command_t move;
start_interaction_command_t resize;
window_send_to_workspace_command_t send_to_workspace;
window_bool_state_t floating;
window_bool_state_t sticky;

View File

@@ -27,12 +27,6 @@ typedef struct key_press_event_t {
uint32_t keycode;
} key_press_event_t;
typedef enum button_t {
ZDWM_BUTTON_LEFT,
ZDWM_BUTTON_RIGHT,
ZDWM_BUTTON_MIDDLE,
} button_t;
typedef struct pointer_button_event_t {
modifier_mask_t modifiers;
button_t button;

View File

@@ -20,6 +20,8 @@ static void free_memory_hold_by_effects(effect_t *effects, size_t count) {
case ZDWM_EFFECT_BIND_KEY:
p_delete(&effect->as.bind_key.keys);
break;
case ZDWM_EFFECT_GRAB_BUTTON:
p_delete(&effect->as.grab_button.buttons);
default:
}
}
@@ -98,6 +100,26 @@ void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id) {
plan_push_effect(plan, &effect);
}
void plan_push_move_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return;
effect_t effect = {
.type = ZDWM_EFFECT_START_MOVE_WINDOW,
.as.move.window = window_id,
};
plan_push_effect(plan, &effect);
}
void plan_push_resize_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return;
effect_t effect = {
.type = ZDWM_EFFECT_START_RESIZE_WINDOW,
.as.resize.window = window_id,
};
plan_push_effect(plan, &effect);
}
void plan_push_fullscreen_effect(
plan_t *plan,
window_id_t window_id,
@@ -165,3 +187,8 @@ void plan_push_change_border_color_effect(
};
plan_push_effect(plan, &effect);
}
void plan_push_ungrab_pointer(plan_t *plan) {
effect_t effect = {.type = ZDWM_EFFECT_UNGRAB_POINTER};
plan_push_effect(plan, &effect);
}

View File

@@ -12,6 +12,8 @@ typedef enum effect_type_t {
ZDWM_EFFECT_FOCUS_WINDOW,
ZDWM_EFFECT_KILL_WINDOW,
ZDWM_EFFECT_WITHDRAW_WINDOW,
ZDWM_EFFECT_START_MOVE_WINDOW,
ZDWM_EFFECT_START_RESIZE_WINDOW,
ZDWM_EFFECT_MINIMIZE_WINDOW,
ZDWM_EFFECT_MAXIMIZE_WINDOW,
ZDWM_EFFECT_FULLSCREEN_WINDOW,
@@ -20,6 +22,8 @@ typedef enum effect_type_t {
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
ZDWM_EFFECT_RESTACK_WINDOWS,
ZDWM_EFFECT_BIND_KEY,
ZDWM_EFFECT_GRAB_BUTTON,
ZDWM_EFFECT_UNGRAB_POINTER,
} effect_type_t;
typedef struct effect_move_window_t {
@@ -48,6 +52,12 @@ typedef struct effect_bind_key_t {
size_t count;
} effect_bind_key_t;
typedef struct effect_grab_button_t {
window_id_t window;
const grab_button_t *buttons;
size_t count;
} effect_grab_button_t;
typedef struct effect_bool_window_t {
window_id_t window;
bool value;
@@ -61,6 +71,8 @@ typedef struct effect_t {
only_window_data_t focus;
only_window_data_t kill;
only_window_data_t withdraw;
only_window_data_t move;
only_window_data_t resize;
effect_bool_window_t minimize;
effect_bool_window_t maximize;
effect_bool_window_t fullscreen;
@@ -69,6 +81,7 @@ typedef struct effect_t {
effect_window_list_t change_window_list;
effect_window_list_t restack_windows;
effect_bind_key_t bind_key;
effect_grab_button_t grab_button;
} as;
} effect_t;
@@ -90,6 +103,8 @@ void plan_push_unmap_effect(plan_t *plan, window_id_t window_id);
void plan_push_focus_effect(plan_t *plan, window_id_t window_id);
void plan_push_kill_effect(plan_t *plan, window_id_t window_id);
void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id);
void plan_push_move_effect(plan_t *plan, window_id_t window_id);
void plan_push_resize_effect(plan_t *plan, window_id_t window_id);
void plan_push_fullscreen_effect(
plan_t *plan,
window_id_t window_id,
@@ -102,3 +117,4 @@ void plan_push_change_border_color_effect(
window_id_t window_id,
const color_t *color
);
void plan_push_ungrab_pointer(plan_t *plan);

View File

@@ -2,6 +2,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <zdwm/action.h>
#include <zdwm/types.h>
@@ -459,6 +460,108 @@ static void route_key_press(
}
}
static void route_pointer_press(
const policy_context_t *ctx,
const pointer_button_event_t *data,
command_buffer_t *out
) {
auto window_id = data->window;
auto window = state_window_get(ctx->state, window_id);
if (!window) return;
/* TODO: 后续改为配置 */
if (data->button == ZDWM_BUTTON_LEFT && data->modifiers == ZDWM_MOD_4) {
command_t start_move_cmd = {
.type = ZDWM_COMMAND_START_MOVE_WINDOW,
.as.move = {
.window = window_id,
.pointer_coordinate = data->root,
},
};
command_buffer_push(out, &start_move_cmd);
}
if (data->button == ZDWM_BUTTON_RIGHT && data->modifiers == ZDWM_MOD_4) {
command_t start_resize_cmd = {
.type = ZDWM_COMMAND_START_RESIZE_WINDOW,
.as.resize = {
.window = window_id,
.pointer_coordinate = data->root,
}
};
command_buffer_push(out, &start_resize_cmd);
}
}
static void route_pointer_release(
const policy_context_t *ctx,
const pointer_button_event_t *data,
command_buffer_t *out
) {
switch (ctx->interaction->mode) {
case ZDWM_WINDOW_INTERACTION_NONE:
break;
case ZDWM_WINDOW_INTERACTION_MOVE: {
command_t stop_move_cmd = {.type = ZDWM_COMMAND_STOP_MOVE_WINDOW};
command_buffer_push(out, &stop_move_cmd);
} break;
case ZDWM_WINDOW_INTERACTION_RESIZE: {
command_t stop_resize_cmd = {.type = ZDWM_COMMAND_STOP_RESIZE_WINDOW};
command_buffer_push(out, &stop_resize_cmd);
} break;
}
}
static void route_pointer_motion(
const policy_context_t *ctx,
const pointer_motion_event_t *data,
command_buffer_t *out
) {
auto interaction = ctx->interaction;
switch (interaction->mode) {
case ZDWM_WINDOW_INTERACTION_NONE:
break;
case ZDWM_WINDOW_INTERACTION_MOVE: {
auto rect = interaction->origin_rect;
auto start = interaction->start_coordinate;
auto end = data->root;
command_t configure = {
.type = ZDWM_COMMAND_CONFIGURE_WINDOW,
.as.configure = {
.window = interaction->window,
.changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y,
.x = rect.x + (end.x - start.x),
.y = rect.y + (end.y - start.y),
},
};
command_buffer_push(out, &configure);
} break;
case ZDWM_WINDOW_INTERACTION_RESIZE: {
auto rect = interaction->origin_rect;
auto start = interaction->start_coordinate;
auto end = data->root;
auto width = rect.width + (end.x - start.x);
auto height = rect.height + (end.y - start.y);
width = MAX(width, 10);
height = MAX(height, 10);
command_t configure_cmd = {
.type = ZDWM_COMMAND_CONFIGURE_WINDOW,
.as.configure = {
.window = interaction->window,
.changed_fields =
ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT,
.width = width,
.height = height,
}
};
command_buffer_push(out, &configure_cmd);
} break;
}
}
static void
route_pointer_enter(state_t *state, window_id_t window, command_buffer_t *out) {
add_focus_window_command(out, window);
@@ -676,6 +779,15 @@ void policy_route_event(
case ZDWM_EVENT_KEY_PRESS:
route_key_press(ctx, &event->as.key_press, out);
break;
case ZDWM_EVENT_POINTER_BUTTON_PRESS:
route_pointer_press(ctx, &event->as.pointer_button_press, out);
break;
case ZDWM_EVENT_POINTER_BUTTON_RELEASE:
route_pointer_release(ctx, &event->as.pointer_button_release, out);
break;
case ZDWM_EVENT_POINTER_MOTION:
route_pointer_motion(ctx, &event->as.pointer_motion, out);
break;
case ZDWM_EVENT_POINTER_ENTER:
route_pointer_enter(state, event->as.pointer_enter.window, out);
break;
@@ -762,6 +874,24 @@ static void push_window_list_effect(const state_t *state, plan_t *plan) {
plan_push_effect(plan, &effect);
}
static void plan_push_grab_button_effect(plan_t *plan, window_id_t window) {
/* TODO: 后续会改成配置 */
static const grab_button_t buttons[] = {
[0] = {.modifiers = ZDWM_MOD_4, .button = ZDWM_BUTTON_LEFT},
[1] = {.modifiers = ZDWM_MOD_4, .button = ZDWM_BUTTON_RIGHT},
};
constexpr const size_t count = countof(buttons);
auto btns = p_new(grab_button_t, count);
memcpy(btns, buttons, sizeof(buttons));
effect_t grab_button_effect = {
.type = ZDWM_EFFECT_GRAB_BUTTON,
.as.grab_button = {.window = window, .buttons = btns, .count = count},
};
plan_push_effect(plan, &grab_button_effect);
}
static void manage_window(
const policy_context_t *ctx,
const manage_window_command_t *command,
@@ -774,6 +904,7 @@ static void manage_window(
state_window_set_workspace(state, window_id, workspace_id);
state_window_set_floating(state, window_id, command->floating);
set_foucs_window(ctx, workspace_id, window_id, plan);
plan_push_grab_button_effect(plan, window_id);
push_window_list_effect(state, plan);
listeners_notify_window_added(ctx->listeners, state, window_id);
@@ -1200,6 +1331,51 @@ static void change_window_state(
listeners_notify_window_updated(ctx->listeners, state, command->window);
}
static void start_window_move(
const policy_context_t *ctx,
const start_interaction_command_t *command,
plan_t *plan
) {
auto window_id = command->window;
auto window = state_window_get(ctx->state, window_id);
if (!window) return;
plan_push_move_effect(plan, window_id);
*ctx->interaction = (window_interaction_state_t){
.mode = ZDWM_WINDOW_INTERACTION_MOVE,
.window = window_id,
.start_coordinate = command->pointer_coordinate,
.origin_rect = window->frame_rect,
};
}
static void start_window_resize(
const policy_context_t *ctx,
const start_interaction_command_t *command,
plan_t *plan
) {
auto window_id = command->window;
auto window = state_window_get(ctx->state, window_id);
if (!window) return;
auto frame_rect = window->frame_rect;
point_t pointer_position = {
.x = frame_rect.x + frame_rect.width,
.y = frame_rect.y + frame_rect.height,
};
plan_push_resize_effect(plan, window_id);
*ctx->interaction = (window_interaction_state_t){
.mode = ZDWM_WINDOW_INTERACTION_RESIZE,
.window = window_id,
.start_coordinate = pointer_position,
.origin_rect = frame_rect,
};
}
static void send_window_to_workspace(
const policy_context_t *ctx,
const window_send_to_workspace_command_t *command,
@@ -1472,6 +1648,17 @@ void policy_apply_command(
case ZDWM_COMMAND_CHANGE_WINDOW_STATE:
change_window_state(ctx, &cmd->as.state_change, plan);
break;
case ZDWM_COMMAND_START_MOVE_WINDOW:
start_window_move(ctx, &cmd->as.move, plan);
break;
case ZDWM_COMMAND_START_RESIZE_WINDOW:
start_window_resize(ctx, &cmd->as.resize, plan);
break;
case ZDWM_COMMAND_STOP_MOVE_WINDOW:
case ZDWM_COMMAND_STOP_RESIZE_WINDOW:
plan_push_ungrab_pointer(plan);
p_clear(ctx->interaction, 1);
break;
case ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE:
send_window_to_workspace(ctx, &cmd->as.send_to_workspace, plan);
break;

View File

@@ -22,6 +22,7 @@ typedef struct policy_bar_t {
} policy_bar_t;
typedef struct policy_context_t {
window_interaction_state_t *interaction;
binding_table_t *bind_table;
state_t *state;
const rules_t *rules;

View File

@@ -55,6 +55,18 @@ typedef struct key_bind_t {
keysym_t keysym;
} key_bind_t;
typedef enum button_t {
ZDWM_BUTTON_NONE,
ZDWM_BUTTON_LEFT,
ZDWM_BUTTON_RIGHT,
ZDWM_BUTTON_MIDDLE,
} button_t;
typedef struct grab_button_t {
modifier_mask_t modifiers;
button_t button;
} grab_button_t;
typedef enum window_state_request_type_t {
ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN,
ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED,
@@ -102,6 +114,19 @@ typedef struct only_window_data_t {
window_id_t window;
} only_window_data_t;
typedef enum window_interaction_mode_t {
ZDWM_WINDOW_INTERACTION_NONE,
ZDWM_WINDOW_INTERACTION_MOVE,
ZDWM_WINDOW_INTERACTION_RESIZE,
} window_interaction_mode_t;
typedef struct window_interaction_state_t {
window_interaction_mode_t mode;
window_id_t window;
point_t start_coordinate;
rect_t origin_rect;
} window_interaction_state_t;
static inline bool window_id_invalid(window_id_t window_id) {
return window_id == ZDWM_WINDOW_ID_INVALID;
}

View File

@@ -48,6 +48,7 @@ typedef struct runtime_t {
void *config_module_handle;
binding_table_t *binding_table;
listeners_t listeners;
window_interaction_state_t interaction;
bar_t bar;
window_list_t bar_windows;
@@ -197,6 +198,7 @@ static void runtime_shutdown(runtime_t *runtime) {
binding_table_destroy(runtime->binding_table);
runtime->binding_table = nullptr;
listeners_cleanup(&runtime->listeners);
p_clear(&runtime->interaction, 1);
window_list_cleanup(&runtime->bar_windows);
backend_destroy(runtime->backend);
runtime->backend = nullptr;
@@ -402,6 +404,8 @@ static void runtime_arrange(runtime_t *runtime) {
static policy_context_t policy_context_init(runtime_t *runtime) {
policy_context_t ctx = {
.interaction = &runtime->interaction,
.bind_table = runtime->binding_table,
.state = &runtime->state,
.rules = &runtime->rules,