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}
|
add_executable(${APP_NAME}
|
||||||
${SOURCE_DIR}/backend/output_utils.c
|
${SOURCE_DIR}/backend/output_utils.c
|
||||||
${SOURCE_DIR}/backend/x11/backend.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/event.c
|
||||||
${SOURCE_DIR}/backend/x11/window.c
|
${SOURCE_DIR}/backend/x11/window.c
|
||||||
|
|
||||||
@@ -76,6 +78,7 @@ find_package(PkgConfig REQUIRED)
|
|||||||
pkg_check_modules(deps REQUIRED
|
pkg_check_modules(deps REQUIRED
|
||||||
xcb
|
xcb
|
||||||
xcb-aux
|
xcb-aux
|
||||||
|
xcb-cursor
|
||||||
xcb-icccm
|
xcb-icccm
|
||||||
xcb-keysyms
|
xcb-keysyms
|
||||||
xcb-randr
|
xcb-randr
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
#include "backend/output_utils.h"
|
#include "backend/output_utils.h"
|
||||||
|
#include "backend/x11/cursor.h"
|
||||||
#include "backend/x11/window.h"
|
#include "backend/x11/window.h"
|
||||||
#include "base/app.h"
|
#include "base/app.h"
|
||||||
#include "base/array.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);
|
backend->key_symbols = xcb_key_symbols_alloc(conn);
|
||||||
|
|
||||||
|
cursor_init(backend);
|
||||||
atoms_init(backend);
|
atoms_init(backend);
|
||||||
create_wm_check_window(backend);
|
create_wm_check_window(backend);
|
||||||
create_no_focus_window(backend);
|
create_no_focus_window(backend);
|
||||||
|
|
||||||
|
window_change_cursor(backend, root, ZDWM_CURSOR_NORMAL);
|
||||||
|
|
||||||
return backend;
|
return backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +208,8 @@ void backend_destroy(backend_t *backend) {
|
|||||||
xcb_key_symbols_free(backend->key_symbols);
|
xcb_key_symbols_free(backend->key_symbols);
|
||||||
backend->key_symbols = nullptr;
|
backend->key_symbols = nullptr;
|
||||||
|
|
||||||
|
cursor_cleanup(backend);
|
||||||
|
|
||||||
xcb_disconnect(backend->conn);
|
xcb_disconnect(backend->conn);
|
||||||
backend->conn = nullptr;
|
backend->conn = nullptr;
|
||||||
free(backend);
|
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);
|
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(
|
static void backend_merge_effects(
|
||||||
backend_t *backend,
|
backend_t *backend,
|
||||||
const effect_t *effects,
|
const effect_t *effects,
|
||||||
@@ -544,6 +577,12 @@ static void backend_merge_effects(
|
|||||||
XCB_ICCCM_WM_STATE_WITHDRAWN
|
XCB_ICCCM_WM_STATE_WITHDRAWN
|
||||||
);
|
);
|
||||||
break;
|
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: {
|
case ZDWM_EFFECT_MINIMIZE_WINDOW: {
|
||||||
auto window = e->as.minimize.window;
|
auto window = e->as.minimize.window;
|
||||||
xcb_icccm_wm_state_t state = XCB_ICCCM_WM_STATE_NORMAL;
|
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:
|
case ZDWM_EFFECT_BIND_KEY:
|
||||||
backend_bind_key(backend, &e->as.bind_key);
|
backend_bind_key(backend, &e->as.bind_key);
|
||||||
break;
|
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 "core/event.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
@@ -8,8 +9,8 @@
|
|||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
|
#include "backend/x11/common.h"
|
||||||
#include "backend/x11/window.h"
|
#include "backend/x11/window.h"
|
||||||
#include "base/macros.h"
|
|
||||||
#include "base/memory.h"
|
#include "base/memory.h"
|
||||||
#include "core/backend.h"
|
#include "core/backend.h"
|
||||||
#include "core/types.h"
|
#include "core/types.h"
|
||||||
@@ -232,29 +233,6 @@ static bool handle_configure_request(
|
|||||||
return true;
|
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(
|
static bool handle_key_press(
|
||||||
backend_t *backend,
|
backend_t *backend,
|
||||||
event_t *event,
|
event_t *event,
|
||||||
@@ -268,11 +246,64 @@ static bool handle_key_press(
|
|||||||
event->type = ZDWM_EVENT_KEY_PRESS;
|
event->type = ZDWM_EVENT_KEY_PRESS;
|
||||||
event->as.key_press.keycode = keycode;
|
event->as.key_press.keycode = keycode;
|
||||||
event->as.key_press.keysym = keysym;
|
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;
|
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(
|
static bool handle_enter_notify(
|
||||||
backend_t *backend,
|
backend_t *backend,
|
||||||
event_t *event,
|
event_t *event,
|
||||||
@@ -469,6 +500,9 @@ static bool handle_event(
|
|||||||
EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify);
|
EVENT(XCB_DESTROY_NOTIFY, handle_destroy_notify);
|
||||||
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_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_ENTER_NOTIFY, handle_enter_notify);
|
||||||
EVENT(XCB_PROPERTY_NOTIFY, handle_property_notify);
|
EVENT(XCB_PROPERTY_NOTIFY, handle_property_notify);
|
||||||
EVENT(XCB_CLIENT_MESSAGE, handle_client_message);
|
EVENT(XCB_CLIENT_MESSAGE, handle_client_message);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xcb_cursor.h>
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
@@ -78,7 +79,14 @@ typedef struct window_configure_list_t {
|
|||||||
size_t capacity;
|
size_t capacity;
|
||||||
} window_configure_list_t;
|
} 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_key_symbols_t *key_symbols;
|
||||||
xcb_connection_t *conn;
|
xcb_connection_t *conn;
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
@@ -94,11 +102,14 @@ struct backend_t {
|
|||||||
xcb_window_t focus_window;
|
xcb_window_t focus_window;
|
||||||
bool update_focus;
|
bool update_focus;
|
||||||
|
|
||||||
|
xcb_cursor_t cursors[ZDWM_CURSOR_COUNT];
|
||||||
|
xcb_cursor_context_t *cursor_context;
|
||||||
|
|
||||||
window_configure_list_t config_list;
|
window_configure_list_t config_list;
|
||||||
window_list_t unmap;
|
window_list_t unmap;
|
||||||
window_list_t map;
|
window_list_t map;
|
||||||
window_list_t kill;
|
window_list_t kill;
|
||||||
};
|
} backend_t;
|
||||||
|
|
||||||
bool populate_window_event(
|
bool populate_window_event(
|
||||||
struct backend_t *backend,
|
struct backend_t *backend,
|
||||||
|
|||||||
@@ -3,10 +3,13 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xcb_aux.h>
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
|
#include "backend/x11/common.h"
|
||||||
|
#include "backend/x11/cursor.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/memory.h"
|
#include "base/memory.h"
|
||||||
#include "core/backend.h"
|
#include "core/backend.h"
|
||||||
@@ -451,3 +454,36 @@ visual_t *window_get_visual(backend_t *backend, bool prefer_alpha) {
|
|||||||
|
|
||||||
return visual;
|
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 释放
|
* @returns 返回的信息使用后记得使用 free 释放
|
||||||
*/
|
*/
|
||||||
visual_t *window_get_visual(backend_t *backend, bool prefer_alpha);
|
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_WITHDRAW_WINDOW,
|
||||||
ZDWM_COMMAND_CONFIGURE_WINDOW,
|
ZDWM_COMMAND_CONFIGURE_WINDOW,
|
||||||
ZDWM_COMMAND_CHANGE_WINDOW_STATE,
|
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_SEND_TO_WORKSPACE,
|
||||||
ZDWM_COMMAND_WINDOW_SET_FLOATING,
|
ZDWM_COMMAND_WINDOW_SET_FLOATING,
|
||||||
ZDWM_COMMAND_WINDOW_SET_STICKY,
|
ZDWM_COMMAND_WINDOW_SET_STICKY,
|
||||||
@@ -42,6 +46,11 @@ typedef struct window_state_change_command_t {
|
|||||||
window_state_request_action_t action;
|
window_state_request_action_t action;
|
||||||
} window_state_change_command_t;
|
} 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 {
|
typedef struct window_send_to_workspace_command_t {
|
||||||
window_id_t window;
|
window_id_t window;
|
||||||
workspace_id_t workspace;
|
workspace_id_t workspace;
|
||||||
@@ -93,6 +102,8 @@ typedef struct command_t {
|
|||||||
only_window_data_t withdraw;
|
only_window_data_t withdraw;
|
||||||
configure_data_t configure;
|
configure_data_t configure;
|
||||||
window_state_change_command_t state_change;
|
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_send_to_workspace_command_t send_to_workspace;
|
||||||
window_bool_state_t floating;
|
window_bool_state_t floating;
|
||||||
window_bool_state_t sticky;
|
window_bool_state_t sticky;
|
||||||
|
|||||||
@@ -27,12 +27,6 @@ typedef struct key_press_event_t {
|
|||||||
uint32_t keycode;
|
uint32_t keycode;
|
||||||
} key_press_event_t;
|
} 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 {
|
typedef struct pointer_button_event_t {
|
||||||
modifier_mask_t modifiers;
|
modifier_mask_t modifiers;
|
||||||
button_t button;
|
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:
|
case ZDWM_EFFECT_BIND_KEY:
|
||||||
p_delete(&effect->as.bind_key.keys);
|
p_delete(&effect->as.bind_key.keys);
|
||||||
break;
|
break;
|
||||||
|
case ZDWM_EFFECT_GRAB_BUTTON:
|
||||||
|
p_delete(&effect->as.grab_button.buttons);
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,6 +100,26 @@ void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id) {
|
|||||||
plan_push_effect(plan, &effect);
|
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(
|
void plan_push_fullscreen_effect(
|
||||||
plan_t *plan,
|
plan_t *plan,
|
||||||
window_id_t window_id,
|
window_id_t window_id,
|
||||||
@@ -165,3 +187,8 @@ void plan_push_change_border_color_effect(
|
|||||||
};
|
};
|
||||||
plan_push_effect(plan, &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_FOCUS_WINDOW,
|
||||||
ZDWM_EFFECT_KILL_WINDOW,
|
ZDWM_EFFECT_KILL_WINDOW,
|
||||||
ZDWM_EFFECT_WITHDRAW_WINDOW,
|
ZDWM_EFFECT_WITHDRAW_WINDOW,
|
||||||
|
ZDWM_EFFECT_START_MOVE_WINDOW,
|
||||||
|
ZDWM_EFFECT_START_RESIZE_WINDOW,
|
||||||
ZDWM_EFFECT_MINIMIZE_WINDOW,
|
ZDWM_EFFECT_MINIMIZE_WINDOW,
|
||||||
ZDWM_EFFECT_MAXIMIZE_WINDOW,
|
ZDWM_EFFECT_MAXIMIZE_WINDOW,
|
||||||
ZDWM_EFFECT_FULLSCREEN_WINDOW,
|
ZDWM_EFFECT_FULLSCREEN_WINDOW,
|
||||||
@@ -20,6 +22,8 @@ typedef enum effect_type_t {
|
|||||||
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
|
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
|
||||||
ZDWM_EFFECT_RESTACK_WINDOWS,
|
ZDWM_EFFECT_RESTACK_WINDOWS,
|
||||||
ZDWM_EFFECT_BIND_KEY,
|
ZDWM_EFFECT_BIND_KEY,
|
||||||
|
ZDWM_EFFECT_GRAB_BUTTON,
|
||||||
|
ZDWM_EFFECT_UNGRAB_POINTER,
|
||||||
} effect_type_t;
|
} effect_type_t;
|
||||||
|
|
||||||
typedef struct effect_move_window_t {
|
typedef struct effect_move_window_t {
|
||||||
@@ -48,6 +52,12 @@ typedef struct effect_bind_key_t {
|
|||||||
size_t count;
|
size_t count;
|
||||||
} effect_bind_key_t;
|
} 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 {
|
typedef struct effect_bool_window_t {
|
||||||
window_id_t window;
|
window_id_t window;
|
||||||
bool value;
|
bool value;
|
||||||
@@ -61,6 +71,8 @@ typedef struct effect_t {
|
|||||||
only_window_data_t focus;
|
only_window_data_t focus;
|
||||||
only_window_data_t kill;
|
only_window_data_t kill;
|
||||||
only_window_data_t withdraw;
|
only_window_data_t withdraw;
|
||||||
|
only_window_data_t move;
|
||||||
|
only_window_data_t resize;
|
||||||
effect_bool_window_t minimize;
|
effect_bool_window_t minimize;
|
||||||
effect_bool_window_t maximize;
|
effect_bool_window_t maximize;
|
||||||
effect_bool_window_t fullscreen;
|
effect_bool_window_t fullscreen;
|
||||||
@@ -69,6 +81,7 @@ typedef struct effect_t {
|
|||||||
effect_window_list_t change_window_list;
|
effect_window_list_t change_window_list;
|
||||||
effect_window_list_t restack_windows;
|
effect_window_list_t restack_windows;
|
||||||
effect_bind_key_t bind_key;
|
effect_bind_key_t bind_key;
|
||||||
|
effect_grab_button_t grab_button;
|
||||||
} as;
|
} as;
|
||||||
} effect_t;
|
} 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_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_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_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(
|
void plan_push_fullscreen_effect(
|
||||||
plan_t *plan,
|
plan_t *plan,
|
||||||
window_id_t window_id,
|
window_id_t window_id,
|
||||||
@@ -102,3 +117,4 @@ void plan_push_change_border_color_effect(
|
|||||||
window_id_t window_id,
|
window_id_t window_id,
|
||||||
const color_t *color
|
const color_t *color
|
||||||
);
|
);
|
||||||
|
void plan_push_ungrab_pointer(plan_t *plan);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#include <zdwm/action.h>
|
#include <zdwm/action.h>
|
||||||
#include <zdwm/types.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
|
static void
|
||||||
route_pointer_enter(state_t *state, window_id_t window, command_buffer_t *out) {
|
route_pointer_enter(state_t *state, window_id_t window, command_buffer_t *out) {
|
||||||
add_focus_window_command(out, window);
|
add_focus_window_command(out, window);
|
||||||
@@ -676,6 +779,15 @@ void policy_route_event(
|
|||||||
case ZDWM_EVENT_KEY_PRESS:
|
case ZDWM_EVENT_KEY_PRESS:
|
||||||
route_key_press(ctx, &event->as.key_press, out);
|
route_key_press(ctx, &event->as.key_press, out);
|
||||||
break;
|
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:
|
case ZDWM_EVENT_POINTER_ENTER:
|
||||||
route_pointer_enter(state, event->as.pointer_enter.window, out);
|
route_pointer_enter(state, event->as.pointer_enter.window, out);
|
||||||
break;
|
break;
|
||||||
@@ -762,6 +874,24 @@ static void push_window_list_effect(const state_t *state, plan_t *plan) {
|
|||||||
plan_push_effect(plan, &effect);
|
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(
|
static void manage_window(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const manage_window_command_t *command,
|
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_workspace(state, window_id, workspace_id);
|
||||||
state_window_set_floating(state, window_id, command->floating);
|
state_window_set_floating(state, window_id, command->floating);
|
||||||
set_foucs_window(ctx, workspace_id, window_id, plan);
|
set_foucs_window(ctx, workspace_id, window_id, plan);
|
||||||
|
plan_push_grab_button_effect(plan, window_id);
|
||||||
push_window_list_effect(state, plan);
|
push_window_list_effect(state, plan);
|
||||||
listeners_notify_window_added(ctx->listeners, state, window_id);
|
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);
|
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(
|
static void send_window_to_workspace(
|
||||||
const policy_context_t *ctx,
|
const policy_context_t *ctx,
|
||||||
const window_send_to_workspace_command_t *command,
|
const window_send_to_workspace_command_t *command,
|
||||||
@@ -1472,6 +1648,17 @@ void policy_apply_command(
|
|||||||
case ZDWM_COMMAND_CHANGE_WINDOW_STATE:
|
case ZDWM_COMMAND_CHANGE_WINDOW_STATE:
|
||||||
change_window_state(ctx, &cmd->as.state_change, plan);
|
change_window_state(ctx, &cmd->as.state_change, plan);
|
||||||
break;
|
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:
|
case ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE:
|
||||||
send_window_to_workspace(ctx, &cmd->as.send_to_workspace, plan);
|
send_window_to_workspace(ctx, &cmd->as.send_to_workspace, plan);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ typedef struct policy_bar_t {
|
|||||||
} policy_bar_t;
|
} policy_bar_t;
|
||||||
|
|
||||||
typedef struct policy_context_t {
|
typedef struct policy_context_t {
|
||||||
|
window_interaction_state_t *interaction;
|
||||||
binding_table_t *bind_table;
|
binding_table_t *bind_table;
|
||||||
state_t *state;
|
state_t *state;
|
||||||
const rules_t *rules;
|
const rules_t *rules;
|
||||||
|
|||||||
@@ -55,6 +55,18 @@ typedef struct key_bind_t {
|
|||||||
keysym_t keysym;
|
keysym_t keysym;
|
||||||
} key_bind_t;
|
} 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 {
|
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,
|
||||||
@@ -102,6 +114,19 @@ typedef struct only_window_data_t {
|
|||||||
window_id_t window;
|
window_id_t window;
|
||||||
} only_window_data_t;
|
} 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) {
|
static inline bool window_id_invalid(window_id_t window_id) {
|
||||||
return window_id == ZDWM_WINDOW_ID_INVALID;
|
return window_id == ZDWM_WINDOW_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ typedef struct runtime_t {
|
|||||||
void *config_module_handle;
|
void *config_module_handle;
|
||||||
binding_table_t *binding_table;
|
binding_table_t *binding_table;
|
||||||
listeners_t listeners;
|
listeners_t listeners;
|
||||||
|
window_interaction_state_t interaction;
|
||||||
|
|
||||||
bar_t bar;
|
bar_t bar;
|
||||||
window_list_t bar_windows;
|
window_list_t bar_windows;
|
||||||
@@ -197,6 +198,7 @@ static void runtime_shutdown(runtime_t *runtime) {
|
|||||||
binding_table_destroy(runtime->binding_table);
|
binding_table_destroy(runtime->binding_table);
|
||||||
runtime->binding_table = nullptr;
|
runtime->binding_table = nullptr;
|
||||||
listeners_cleanup(&runtime->listeners);
|
listeners_cleanup(&runtime->listeners);
|
||||||
|
p_clear(&runtime->interaction, 1);
|
||||||
window_list_cleanup(&runtime->bar_windows);
|
window_list_cleanup(&runtime->bar_windows);
|
||||||
backend_destroy(runtime->backend);
|
backend_destroy(runtime->backend);
|
||||||
runtime->backend = nullptr;
|
runtime->backend = nullptr;
|
||||||
@@ -402,6 +404,8 @@ static void runtime_arrange(runtime_t *runtime) {
|
|||||||
|
|
||||||
static policy_context_t policy_context_init(runtime_t *runtime) {
|
static policy_context_t policy_context_init(runtime_t *runtime) {
|
||||||
policy_context_t ctx = {
|
policy_context_t ctx = {
|
||||||
|
.interaction = &runtime->interaction,
|
||||||
|
|
||||||
.bind_table = runtime->binding_table,
|
.bind_table = runtime->binding_table,
|
||||||
.state = &runtime->state,
|
.state = &runtime->state,
|
||||||
.rules = &runtime->rules,
|
.rules = &runtime->rules,
|
||||||
|
|||||||
Reference in New Issue
Block a user