mirror of
https://codeberg.org/vyivel/dulcepan/
synced 2025-12-17 23:55:12 +02:00
Rework mouse controls
This commit is contained in:
@@ -86,13 +86,32 @@ struct dp_seat {
|
|||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dp_selection_action {
|
||||||
|
DP_SELECTION_ACTION_NONE,
|
||||||
|
DP_SELECTION_ACTION_RESIZING,
|
||||||
|
DP_SELECTION_ACTION_MOVING,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dp_resize_edges {
|
||||||
|
DP_EDGE_NONE = 0,
|
||||||
|
|
||||||
|
DP_EDGE_TOP = 1 << 0,
|
||||||
|
DP_EDGE_BOTTOM = 1 << 1,
|
||||||
|
DP_EDGE_LEFT = 1 << 2,
|
||||||
|
DP_EDGE_RIGHT = 1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
struct dp_selection {
|
struct dp_selection {
|
||||||
struct dp_output *output; // May be NULL
|
struct dp_output *output; // May be NULL
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
|
|
||||||
struct dp_output *interactive_output; // NULL if not interactively selecting
|
enum dp_selection_action action;
|
||||||
int interactive_x, interactive_y;
|
bool action_active;
|
||||||
bool interactive_moved;
|
// Pointer offset to apply during movement
|
||||||
|
int ptr_off_x, ptr_off_y;
|
||||||
|
int resize_edges;
|
||||||
|
// Resize anchor
|
||||||
|
int resize_x, resize_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum dp_file_format {
|
enum dp_file_format {
|
||||||
@@ -161,10 +180,13 @@ void dp_output_hide_surface(struct dp_output *output);
|
|||||||
void dp_seat_create(struct dp_state *state, uint32_t name, struct wl_seat *wl_seat);
|
void dp_seat_create(struct dp_state *state, uint32_t name, struct wl_seat *wl_seat);
|
||||||
void dp_seat_destroy(struct dp_seat *seat);
|
void dp_seat_destroy(struct dp_seat *seat);
|
||||||
|
|
||||||
void dp_select_interactive_start(
|
void dp_select_start_interactive(struct dp_selection *selection, struct dp_output *output, int x,
|
||||||
|
int y, bool modify_existing);
|
||||||
|
void dp_select_stop_interactive(struct dp_selection *selection);
|
||||||
|
|
||||||
|
void dp_select_notify_pointer_position(
|
||||||
struct dp_selection *selection, struct dp_output *output, int x, int y);
|
struct dp_selection *selection, struct dp_output *output, int x, int y);
|
||||||
void dp_select_interactive_move(struct dp_selection *selection, int x, int y);
|
|
||||||
void dp_select_interactive_stop(struct dp_selection *selection);
|
|
||||||
void dp_select_whole(struct dp_selection *selection, struct dp_output *output);
|
void dp_select_whole(struct dp_selection *selection, struct dp_output *output);
|
||||||
|
|
||||||
void dp_save(struct dp_state *state);
|
void dp_save(struct dp_state *state);
|
||||||
|
|||||||
74
src/seat.c
74
src/seat.c
@@ -85,12 +85,58 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
|||||||
.modifiers = keyboard_handle_modifiers,
|
.modifiers = keyboard_handle_modifiers,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void save_position(struct dp_seat *seat, wl_fixed_t x, wl_fixed_t y) {
|
static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_selection *selection) {
|
||||||
|
switch (selection->action) {
|
||||||
|
case DP_SELECTION_ACTION_NONE:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
|
||||||
|
case DP_SELECTION_ACTION_RESIZING:
|
||||||
|
if (selection->width == 0 || selection->height == 0) {
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
|
||||||
|
}
|
||||||
|
switch (selection->resize_edges) {
|
||||||
|
case DP_EDGE_TOP:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE;
|
||||||
|
case DP_EDGE_TOP | DP_EDGE_LEFT:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE;
|
||||||
|
case DP_EDGE_TOP | DP_EDGE_RIGHT:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE;
|
||||||
|
case DP_EDGE_BOTTOM:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE;
|
||||||
|
case DP_EDGE_BOTTOM | DP_EDGE_LEFT:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE;
|
||||||
|
case DP_EDGE_BOTTOM | DP_EDGE_RIGHT:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE;
|
||||||
|
case DP_EDGE_LEFT:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE;
|
||||||
|
case DP_EDGE_RIGHT:
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DP_SELECTION_ACTION_MOVING:
|
||||||
|
if (selection->x == 0 && selection->y == 0 &&
|
||||||
|
selection->width == selection->output->width &&
|
||||||
|
selection->height == selection->output->height) {
|
||||||
|
// Moving is impossible
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
|
||||||
|
}
|
||||||
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
|
||||||
|
}
|
||||||
|
abort(); // Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_cursor(struct dp_seat *seat, uint32_t serial) {
|
||||||
|
wp_cursor_shape_device_v1_set_shape(
|
||||||
|
seat->cursor_shape_device, serial, get_cursor_shape(&seat->state->selection));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_position(struct dp_seat *seat, wl_fixed_t x, wl_fixed_t y, uint32_t serial) {
|
||||||
struct dp_output *output = seat->ptr_output;
|
struct dp_output *output = seat->ptr_output;
|
||||||
seat->ptr_x =
|
seat->ptr_x =
|
||||||
(int)(wl_fixed_to_double(x) * output->transformed_width / output->effective_width);
|
(int)(wl_fixed_to_double(x) * output->transformed_width / output->effective_width);
|
||||||
seat->ptr_y =
|
seat->ptr_y =
|
||||||
(int)(wl_fixed_to_double(y) * output->transformed_height / output->effective_height);
|
(int)(wl_fixed_to_double(y) * output->transformed_height / output->effective_height);
|
||||||
|
dp_select_notify_pointer_position(&seat->state->selection, output, seat->ptr_x, seat->ptr_y);
|
||||||
|
update_cursor(seat, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||||
@@ -98,9 +144,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint
|
|||||||
struct dp_seat *seat = data;
|
struct dp_seat *seat = data;
|
||||||
seat->ptr_output = wl_surface_get_user_data(surface);
|
seat->ptr_output = wl_surface_get_user_data(surface);
|
||||||
assert(seat->ptr_output != NULL);
|
assert(seat->ptr_output != NULL);
|
||||||
save_position(seat, sx, sy);
|
process_position(seat, sx, sy, serial);
|
||||||
wp_cursor_shape_device_v1_set_shape(
|
|
||||||
seat->cursor_shape_device, serial, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_handle_leave(
|
static void pointer_handle_leave(
|
||||||
@@ -115,8 +159,7 @@ static void pointer_handle_motion(
|
|||||||
if (seat->ptr_output == NULL) {
|
if (seat->ptr_output == NULL) {
|
||||||
return; // Shouldn't happen
|
return; // Shouldn't happen
|
||||||
}
|
}
|
||||||
save_position(seat, sx, sy);
|
process_position(seat, sx, sy, serial);
|
||||||
dp_select_interactive_move(&seat->state->selection, seat->ptr_x, seat->ptr_y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||||
@@ -126,10 +169,10 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
|
|||||||
|
|
||||||
struct dp_selection *selection = &state->selection;
|
struct dp_selection *selection = &state->selection;
|
||||||
if (button_state != WL_POINTER_BUTTON_STATE_PRESSED) {
|
if (button_state != WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
if (selection->interactive_moved && state->config.quick_select) {
|
if (selection->width > 0 && selection->height > 0 && state->config.quick_select) {
|
||||||
state->status = DP_STATUS_SAVED;
|
state->status = DP_STATUS_SAVED;
|
||||||
}
|
}
|
||||||
dp_select_interactive_stop(selection);
|
dp_select_stop_interactive(selection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,17 +182,22 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
|
|||||||
|
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case BTN_LEFT:
|
case BTN_LEFT:
|
||||||
dp_select_interactive_start(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y);
|
|
||||||
break;
|
|
||||||
case BTN_RIGHT:
|
case BTN_RIGHT:
|
||||||
|
dp_select_start_interactive(
|
||||||
|
selection, seat->ptr_output, seat->ptr_x, seat->ptr_y, button == BTN_LEFT);
|
||||||
|
update_cursor(seat, serial);
|
||||||
|
break;
|
||||||
|
case BTN_MIDDLE:
|
||||||
dp_select_whole(selection, seat->ptr_output);
|
dp_select_whole(selection, seat->ptr_output);
|
||||||
|
|
||||||
|
// dp_select_whole() doesn't invalidate the interactive state, so do it manually
|
||||||
|
dp_select_notify_pointer_position(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y);
|
||||||
|
update_cursor(seat, serial);
|
||||||
|
|
||||||
if (state->config.quick_select) {
|
if (state->config.quick_select) {
|
||||||
state->status = DP_STATUS_SAVED;
|
state->status = DP_STATUS_SAVED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BTN_MIDDLE:
|
|
||||||
state->status = DP_STATUS_SAVED;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
206
src/select.c
206
src/select.c
@@ -1,5 +1,14 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "dulcepan.h"
|
#include "dulcepan.h"
|
||||||
|
|
||||||
|
#define RESIZE_INNER_SIZE 4
|
||||||
|
#define RESIZE_OUTER_SIZE 12
|
||||||
|
#define RESIZE_CORNER_SIZE 24
|
||||||
|
#define RESIZE_THRESHOLD (RESIZE_OUTER_SIZE + RESIZE_CORNER_SIZE)
|
||||||
|
|
||||||
static void set_selected_output(struct dp_selection *selection, struct dp_output *output) {
|
static void set_selected_output(struct dp_selection *selection, struct dp_output *output) {
|
||||||
if (selection->output == output) {
|
if (selection->output == output) {
|
||||||
return;
|
return;
|
||||||
@@ -11,44 +20,183 @@ static void set_selected_output(struct dp_selection *selection, struct dp_output
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_select_interactive_start(
|
static void update_action(struct dp_selection *selection, struct dp_output *output, int x, int y) {
|
||||||
struct dp_selection *selection, struct dp_output *output, int x, int y) {
|
if (output == selection->output) {
|
||||||
selection->interactive_output = output;
|
int sx = x - selection->x;
|
||||||
selection->interactive_x = x;
|
int sy = y - selection->y;
|
||||||
selection->interactive_y = y;
|
|
||||||
selection->interactive_moved = false;
|
|
||||||
|
|
||||||
dp_output_redraw(output);
|
if (sx >= RESIZE_INNER_SIZE && sy >= RESIZE_INNER_SIZE &&
|
||||||
|
sx < selection->width - RESIZE_INNER_SIZE &&
|
||||||
|
sy <= selection->height - RESIZE_INNER_SIZE) {
|
||||||
|
selection->action = DP_SELECTION_ACTION_MOVING;
|
||||||
|
return;
|
||||||
|
} else if (sx >= -RESIZE_OUTER_SIZE && sy >= -RESIZE_OUTER_SIZE &&
|
||||||
|
sx < selection->width + RESIZE_OUTER_SIZE &&
|
||||||
|
sy < selection->height + RESIZE_OUTER_SIZE) {
|
||||||
|
int edges = DP_EDGE_NONE;
|
||||||
|
|
||||||
|
if (sx >= selection->width - RESIZE_THRESHOLD && sx >= selection->width / 2) {
|
||||||
|
edges |= DP_EDGE_RIGHT;
|
||||||
|
} else if (sx < RESIZE_THRESHOLD) {
|
||||||
|
edges |= DP_EDGE_LEFT;
|
||||||
|
}
|
||||||
|
if (sy >= selection->height - RESIZE_THRESHOLD && sy >= selection->height / 2) {
|
||||||
|
edges |= DP_EDGE_BOTTOM;
|
||||||
|
} else if (sy < RESIZE_THRESHOLD) {
|
||||||
|
edges |= DP_EDGE_TOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edges != DP_EDGE_NONE) {
|
||||||
|
selection->action = DP_SELECTION_ACTION_RESIZING;
|
||||||
|
selection->resize_edges = edges;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selection->action = DP_SELECTION_ACTION_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_select_interactive_move(struct dp_selection *selection, int x, int y) {
|
static void do_resize(struct dp_selection *selection, int x, int y) {
|
||||||
if (selection->interactive_output == NULL) {
|
int ptr_x = x - selection->ptr_off_x, ptr_y = y - selection->ptr_off_y;
|
||||||
|
int width = selection->width, height = selection->height;
|
||||||
|
|
||||||
|
retry_horiz:
|
||||||
|
if ((selection->resize_edges & DP_EDGE_LEFT) != 0) {
|
||||||
|
width = selection->resize_x - ptr_x;
|
||||||
|
if (width < 0) {
|
||||||
|
selection->resize_edges = (selection->resize_edges & ~DP_EDGE_LEFT) | DP_EDGE_RIGHT;
|
||||||
|
goto retry_horiz;
|
||||||
|
}
|
||||||
|
selection->x = selection->resize_x - width;
|
||||||
|
} else if ((selection->resize_edges & DP_EDGE_RIGHT) != 0) {
|
||||||
|
width = ptr_x - selection->resize_x;
|
||||||
|
if (width < 0) {
|
||||||
|
selection->resize_edges = (selection->resize_edges & ~DP_EDGE_RIGHT) | DP_EDGE_LEFT;
|
||||||
|
goto retry_horiz;
|
||||||
|
}
|
||||||
|
selection->x = selection->resize_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
retry_verti:
|
||||||
|
if ((selection->resize_edges & DP_EDGE_TOP) != 0) {
|
||||||
|
height = selection->resize_y - ptr_y;
|
||||||
|
if (height < 0) {
|
||||||
|
selection->resize_edges = (selection->resize_edges & ~DP_EDGE_TOP) | DP_EDGE_BOTTOM;
|
||||||
|
goto retry_verti;
|
||||||
|
}
|
||||||
|
selection->y = selection->resize_y - height;
|
||||||
|
} else if ((selection->resize_edges & DP_EDGE_BOTTOM) != 0) {
|
||||||
|
height = ptr_y - selection->resize_y;
|
||||||
|
if (height < 0) {
|
||||||
|
selection->resize_edges = (selection->resize_edges & ~DP_EDGE_BOTTOM) | DP_EDGE_TOP;
|
||||||
|
goto retry_verti;
|
||||||
|
}
|
||||||
|
selection->y = selection->resize_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width == selection->width && height == selection->height) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
set_selected_output(selection, selection->interactive_output);
|
|
||||||
selection->interactive_moved = true;
|
|
||||||
|
|
||||||
if (x < selection->interactive_x) {
|
|
||||||
selection->x = x;
|
|
||||||
selection->width = selection->interactive_x - x;
|
|
||||||
} else {
|
|
||||||
selection->x = selection->interactive_x;
|
|
||||||
selection->width = x - selection->interactive_x;
|
|
||||||
}
|
|
||||||
if (y < selection->interactive_y) {
|
|
||||||
selection->y = y;
|
|
||||||
selection->height = selection->interactive_y - y;
|
|
||||||
} else {
|
|
||||||
selection->y = selection->interactive_y;
|
|
||||||
selection->height = y - selection->interactive_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
selection->width = width;
|
||||||
|
selection->height = height;
|
||||||
dp_output_redraw(selection->output);
|
dp_output_redraw(selection->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_select_interactive_stop(struct dp_selection *selection) {
|
static void do_move(struct dp_selection *selection, int x, int y) {
|
||||||
selection->interactive_output = NULL;
|
int new_x = x - selection->ptr_off_x, new_y = y - selection->ptr_off_y;
|
||||||
selection->interactive_moved = false;
|
|
||||||
|
if (new_x < 0) {
|
||||||
|
new_x = 0;
|
||||||
|
} else if (new_x > selection->output->width - selection->width) {
|
||||||
|
new_x = selection->output->width - selection->width;
|
||||||
|
}
|
||||||
|
if (new_y < 0) {
|
||||||
|
new_y = 0;
|
||||||
|
} else if (new_y > selection->output->height - selection->height) {
|
||||||
|
new_y = selection->output->height - selection->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_x == selection->x && new_y == selection->y) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selection->x = new_x;
|
||||||
|
selection->y = new_y;
|
||||||
|
dp_output_redraw(selection->output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_resize(struct dp_selection *selection, int x, int y) {
|
||||||
|
if ((selection->resize_edges & DP_EDGE_RIGHT) != 0) {
|
||||||
|
selection->ptr_off_x = x - selection->x - selection->width;
|
||||||
|
selection->resize_x = selection->x;
|
||||||
|
} else {
|
||||||
|
selection->ptr_off_x = x - selection->x;
|
||||||
|
selection->resize_x = selection->x + selection->width;
|
||||||
|
}
|
||||||
|
if ((selection->resize_edges & DP_EDGE_BOTTOM) != 0) {
|
||||||
|
selection->ptr_off_y = y - selection->y - selection->height;
|
||||||
|
selection->resize_y = selection->y;
|
||||||
|
} else {
|
||||||
|
selection->ptr_off_y = y - selection->y;
|
||||||
|
selection->resize_y = selection->y + selection->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dp_select_start_interactive(struct dp_selection *selection, struct dp_output *output, int x,
|
||||||
|
int y, bool modify_existing) {
|
||||||
|
update_action(selection, output, x, y);
|
||||||
|
selection->action_active = true;
|
||||||
|
|
||||||
|
if (modify_existing) {
|
||||||
|
switch (selection->action) {
|
||||||
|
case DP_SELECTION_ACTION_NONE:
|
||||||
|
break;
|
||||||
|
case DP_SELECTION_ACTION_RESIZING:
|
||||||
|
init_resize(selection, x, y);
|
||||||
|
return;
|
||||||
|
case DP_SELECTION_ACTION_MOVING:
|
||||||
|
selection->ptr_off_x = x - selection->x;
|
||||||
|
selection->ptr_off_y = y - selection->y;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a new selection
|
||||||
|
|
||||||
|
set_selected_output(selection, output);
|
||||||
|
selection->x = x;
|
||||||
|
selection->y = y;
|
||||||
|
selection->width = 0;
|
||||||
|
selection->height = 0;
|
||||||
|
|
||||||
|
selection->action = DP_SELECTION_ACTION_RESIZING;
|
||||||
|
selection->resize_edges = DP_EDGE_BOTTOM | DP_EDGE_RIGHT;
|
||||||
|
|
||||||
|
init_resize(selection, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dp_select_stop_interactive(struct dp_selection *selection) {
|
||||||
|
selection->action_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dp_select_notify_pointer_position(
|
||||||
|
struct dp_selection *selection, struct dp_output *output, int x, int y) {
|
||||||
|
if (selection->action_active) {
|
||||||
|
switch (selection->action) {
|
||||||
|
case DP_SELECTION_ACTION_NONE:
|
||||||
|
abort(); // Unreachable
|
||||||
|
case DP_SELECTION_ACTION_RESIZING:
|
||||||
|
do_resize(selection, x, y);
|
||||||
|
break;
|
||||||
|
case DP_SELECTION_ACTION_MOVING:
|
||||||
|
do_move(selection, x, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
update_action(selection, output, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_select_whole(struct dp_selection *selection, struct dp_output *output) {
|
void dp_select_whole(struct dp_selection *selection, struct dp_output *output) {
|
||||||
|
|||||||
Reference in New Issue
Block a user