Compare commits
5 Commits
9f9adf7e2e
...
9a1e015fc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
9a1e015fc1
|
|||
|
4e7ab45864
|
|||
|
b8cd40df9f
|
|||
|
7a47f4d44d
|
|||
|
090266baa5
|
@@ -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
|
||||
|
||||
@@ -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
71
src/backend/x11/common.c
Normal 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
12
src/backend/x11/common.h
Normal 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
51
src/backend/x11/cursor.c
Normal 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
9
src/backend/x11/cursor.h
Normal 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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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, ¶ms);
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user