feat: 添加 MOD4 + 鼠标左键移动窗口功能
This commit is contained in:
@@ -538,6 +538,17 @@ static void backend_grab_button(
|
||||
}
|
||||
}
|
||||
|
||||
static void backend_start_move_window(backend_t *backend, xcb_window_t window) {
|
||||
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 cursor = cursor_get_xcb_cursor(backend, ZDWM_CURSOR_MOVE);
|
||||
auto time = XCB_TIME_CURRENT_TIME;
|
||||
xcb_grab_pointer(conn, false, root, mask, mode, mode, root, cursor, time);
|
||||
}
|
||||
|
||||
static void backend_merge_effects(
|
||||
backend_t *backend,
|
||||
const effect_t *effects,
|
||||
@@ -566,6 +577,9 @@ static void backend_merge_effects(
|
||||
XCB_ICCCM_WM_STATE_WITHDRAWN
|
||||
);
|
||||
break;
|
||||
case ZDWM_EFFECT_START_MOVE_WINDOW:
|
||||
backend_start_move_window(backend, e->as.move.window);
|
||||
break;
|
||||
case ZDWM_EFFECT_MINIMIZE_WINDOW: {
|
||||
auto window = e->as.minimize.window;
|
||||
xcb_icccm_wm_state_t state = XCB_ICCCM_WM_STATE_NORMAL;
|
||||
@@ -619,6 +633,10 @@ static void backend_merge_effects(
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,8 @@ static bool handle_button_press(
|
||||
event_t *event,
|
||||
const xcb_button_press_event_t *xcb_event
|
||||
) {
|
||||
auto handled = fill_button_event(xcb_event, &event->as.pointer_button_press);
|
||||
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;
|
||||
|
||||
@@ -12,6 +12,8 @@ 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_WINDOW_SEND_TO_WORKSPACE,
|
||||
ZDWM_COMMAND_WINDOW_SET_FLOATING,
|
||||
ZDWM_COMMAND_WINDOW_SET_STICKY,
|
||||
@@ -42,6 +44,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;
|
||||
} window_start_move_command_t;
|
||||
|
||||
typedef struct window_send_to_workspace_command_t {
|
||||
window_id_t window;
|
||||
workspace_id_t workspace;
|
||||
@@ -93,6 +100,7 @@ typedef struct command_t {
|
||||
only_window_data_t withdraw;
|
||||
configure_data_t configure;
|
||||
window_state_change_command_t state_change;
|
||||
window_start_move_command_t move;
|
||||
window_send_to_workspace_command_t send_to_workspace;
|
||||
window_bool_state_t floating;
|
||||
window_bool_state_t sticky;
|
||||
|
||||
@@ -100,6 +100,16 @@ 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_fullscreen_effect(
|
||||
plan_t *plan,
|
||||
window_id_t window_id,
|
||||
@@ -167,3 +177,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,7 @@ typedef enum effect_type_t {
|
||||
ZDWM_EFFECT_FOCUS_WINDOW,
|
||||
ZDWM_EFFECT_KILL_WINDOW,
|
||||
ZDWM_EFFECT_WITHDRAW_WINDOW,
|
||||
ZDWM_EFFECT_START_MOVE_WINDOW,
|
||||
ZDWM_EFFECT_MINIMIZE_WINDOW,
|
||||
ZDWM_EFFECT_MAXIMIZE_WINDOW,
|
||||
ZDWM_EFFECT_FULLSCREEN_WINDOW,
|
||||
@@ -21,6 +22,7 @@ typedef enum effect_type_t {
|
||||
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 {
|
||||
@@ -68,6 +70,7 @@ typedef struct effect_t {
|
||||
only_window_data_t focus;
|
||||
only_window_data_t kill;
|
||||
only_window_data_t withdraw;
|
||||
only_window_data_t move;
|
||||
effect_bool_window_t minimize;
|
||||
effect_bool_window_t maximize;
|
||||
effect_bool_window_t fullscreen;
|
||||
@@ -98,6 +101,7 @@ 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_fullscreen_effect(
|
||||
plan_t *plan,
|
||||
window_id_t window_id,
|
||||
@@ -110,3 +114,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,72 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
route_pointer_enter(state_t *state, window_id_t window, command_buffer_t *out) {
|
||||
add_focus_window_command(out, window);
|
||||
@@ -676,6 +743,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;
|
||||
@@ -1219,6 +1295,25 @@ 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 window_start_move_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 send_window_to_workspace(
|
||||
const policy_context_t *ctx,
|
||||
const window_send_to_workspace_command_t *command,
|
||||
@@ -1491,6 +1586,13 @@ 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_STOP_MOVE_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;
|
||||
|
||||
@@ -114,6 +114,18 @@ 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,
|
||||
} 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