Added vertical gesture support

This commit is contained in:
Erik Reider 2024-01-22 16:39:44 +01:00
parent fdf764d3f6
commit 067613854b
8 changed files with 116 additions and 55 deletions

View file

@ -96,6 +96,10 @@ char *gesture_parse(const char *input, struct gesture *output) {
output->directions |= GESTURE_DIRECTION_CLOCKWISE;
} else if (strcmp(item, "counterclockwise") == 0) {
output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
} else if (strcmp(item, "horizontal") == 0) {
output->directions |= GESTURE_DIRECTION_HORIZONTAL;
} else if (strcmp(item, "vertical") == 0) {
output->directions |= GESTURE_DIRECTION_VERTICAL;
} else {
return strformat("expected direction, got %s", item);
}
@ -129,7 +133,7 @@ const char *gesture_type_string(enum gesture_type type) {
int gesture_workspace_swipe_command_parse(char *cmd) {
if (strcmp(cmd, "normal") == 0) {
return -1;
} else if (strcmp(cmd, "invert") == 0) {
} else if (strcmp(cmd, "inverted") == 0) {
return 1;
}
return 0;
@ -155,6 +159,10 @@ const char *gesture_direction_string(enum gesture_direction direction) {
return "clockwise";
case GESTURE_DIRECTION_COUNTERCLOCKWISE:
return "counterclockwise";
case GESTURE_DIRECTION_HORIZONTAL:
return "horizontal";
case GESTURE_DIRECTION_VERTICAL:
return "vertical";
}
return NULL;
@ -328,6 +336,12 @@ struct gesture *gesture_tracker_end(struct gesture_tracker *tracker) {
__attribute__ ((fallthrough));
// Gestures with dx and dy
case GESTURE_TYPE_WORKSPACE_SWIPE:
if (fabs(tracker->dx) > fabs(tracker->dy)) {
result->directions |= GESTURE_DIRECTION_HORIZONTAL;
} else {
result->directions |= GESTURE_DIRECTION_VERTICAL;
}
__attribute__ ((fallthrough));
case GESTURE_TYPE_SWIPE:
if (fabs(tracker->dx) > fabs(tracker->dy)) {
if (tracker->dx > 0) {

View file

@ -39,6 +39,9 @@ enum gesture_direction {
// Directions based on rotation
GESTURE_DIRECTION_CLOCKWISE = 1 << 6,
GESTURE_DIRECTION_COUNTERCLOCKWISE = 1 << 7,
// Directions for workspace swipe
GESTURE_DIRECTION_HORIZONTAL = 1 << 8,
GESTURE_DIRECTION_VERTICAL = 1 << 9,
};
// Turns single direction enum value to constant string representation.

View file

@ -13,6 +13,12 @@
struct sway_server;
struct sway_container;
enum swipe_gesture_direction {
SWIPE_GESTURE_DIRECTION_NONE,
SWIPE_GESTURE_DIRECTION_HORIZONTAL,
SWIPE_GESTURE_DIRECTION_VERTICAL,
};
struct render_data {
pixman_region32_t *damage;
struct wlr_box *clip_box;
@ -58,7 +64,10 @@ struct sway_output {
struct wl_listener frame;
struct wl_listener needs_frame;
float workspace_scroll_percent;
struct {
float percent;
enum swipe_gesture_direction direction;
} workspace_scroll;
struct {
struct wl_signal disable;
@ -202,7 +211,8 @@ void handle_output_manager_test(struct wl_listener *listener, void *data);
void handle_output_power_manager_set_mode(struct wl_listener *listener,
void *data);
void update_workspace_scroll_percent(struct sway_seat *seat, int dx, int invert);
void update_workspace_scroll_percent(struct sway_seat *seat, int gesture_percent,
int invert, enum swipe_gesture_direction direction);
void snap_workspace_scroll_percent(struct sway_seat *seat);

View file

@ -160,7 +160,7 @@ static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, boo
if (gesture_workspace_swipe_command_parse(binding->command) == 0) {
free(binding);
return cmd_results_new(CMD_FAILURE,
"Invalid %s command (%s). Either normal or invert",
"Invalid %s command (%s). Either normal or inverted",
bindtype, errmsg);
}
break;

View file

@ -543,7 +543,7 @@ static int output_repaint_timer_handler(void *data) {
if (fullscreen_con && fullscreen_con->view && !debug.noscanout
// Only output to monitor without compositing when saturation is changed
&& fullscreen_con->saturation == 1.0f &&
output->workspace_scroll_percent == 0.0f) {
output->workspace_scroll.percent == 0.0f) {
// Try to scan-out the fullscreen view
static bool last_scanned_out = false;
bool scanned_out =
@ -991,7 +991,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
update_output_manager_config(server);
output->workspace_scroll_percent = 0.0f;
output->workspace_scroll.percent = 0.0f;
output->workspace_scroll.direction = SWIPE_GESTURE_DIRECTION_NONE;
}
void handle_output_layout_change(struct wl_listener *listener,
@ -1105,7 +1106,8 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
apply_output_config(oc, output);
}
void update_workspace_scroll_percent(struct sway_seat *seat, int dx, int invert) {
void update_workspace_scroll_percent(struct sway_seat *seat, int gesture_percent,
int invert, enum swipe_gesture_direction direction) {
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
struct sway_output *output = focused_ws->output;
@ -1114,16 +1116,16 @@ void update_workspace_scroll_percent(struct sway_seat *seat, int dx, int invert)
return;
}
dx *= invert;
gesture_percent *= invert;
// TODO: Make the speed factor configurable?? Works well on my trackpad...
// Maybe also take in account the width of the actual trackpad??
const int SPEED_FACTOR = 500;
float percent = 0;
if (dx < 0) {
percent = (float) dx / SPEED_FACTOR;
} else if (dx > 0) {
percent = (float) dx / SPEED_FACTOR;
if (gesture_percent < 0) {
percent = (float) gesture_percent / SPEED_FACTOR;
} else if (gesture_percent > 0) {
percent = (float) gesture_percent / SPEED_FACTOR;
} else {
return;
}
@ -1148,7 +1150,8 @@ void update_workspace_scroll_percent(struct sway_seat *seat, int dx, int invert)
// NOTE: Can be adjusted in the future to wrap around workspaces
min = -spring_limit;
}
output->workspace_scroll_percent = MIN(max, MAX(min, percent));
output->workspace_scroll.percent = MIN(max, MAX(min, percent));
output->workspace_scroll.direction = direction;
output_damage_whole(output);
transaction_commit_dirty();
@ -1160,14 +1163,14 @@ void snap_workspace_scroll_percent(struct sway_seat *seat) {
// TODO: Make the threshold configurable??
const float THRESHOLD = 0.35;
if (fabs(output->workspace_scroll_percent) <= THRESHOLD) {
if (fabs(output->workspace_scroll.percent) <= THRESHOLD) {
goto reset_state;
}
int dir = 0;
if (output->workspace_scroll_percent < 0) {
if (output->workspace_scroll.percent < 0) {
dir = -1;
} else if (output->workspace_scroll_percent > 0) {
} else if (output->workspace_scroll.percent > 0) {
dir = 1;
} else {
// Skip setting workspace if the percentage is zero
@ -1184,7 +1187,8 @@ void snap_workspace_scroll_percent(struct sway_seat *seat) {
reset_state:
// Reset the state
output->workspace_scroll_percent = 0;
output->workspace_scroll.percent = 0;
output->workspace_scroll.direction = SWIPE_GESTURE_DIRECTION_NONE;
output_damage_whole(output);
transaction_commit_dirty();

View file

@ -83,14 +83,29 @@ static struct wlr_box get_monitor_box(struct wlr_output *output) {
// Adjust the box position when switching the workspace
static void adjust_box_to_workspace_offset(struct wlr_box *box,
struct decoration_data *deco_data, struct sway_workspace *ws) {
int ws_width = ws->current.width + ws->current_gaps.left + ws->current_gaps.right;
float scroll_percent = ws->output->workspace_scroll_percent;
box->x -= ws_width * scroll_percent;
float scroll_percent = ws->output->workspace_scroll.percent;
int ws_dimen;
int *box_coord;
switch (ws->output->workspace_scroll.direction) {
case SWIPE_GESTURE_DIRECTION_NONE:
return;
case SWIPE_GESTURE_DIRECTION_HORIZONTAL:
ws_dimen = ws->current.width + ws->current_gaps.left + ws->current_gaps.right;
box_coord = &box->x;
break;
case SWIPE_GESTURE_DIRECTION_VERTICAL:
ws_dimen = ws->current.height + ws->current_gaps.top + ws->current_gaps.bottom;
box_coord = &box->y;
break;
}
*box_coord -= ws_dimen * scroll_percent;
if (!deco_data->on_focused_workspace) {
if (scroll_percent > 0) {
box->x += ws_width;
*box_coord += ws_dimen;
} else if (scroll_percent < 0) {
box->x -= ws_width;
*box_coord -= ws_dimen;
}
}
}
@ -99,15 +114,31 @@ static void adjust_box_to_workspace_offset(struct wlr_box *box,
// Fixes containers being rendered across workspaces while switching.
static void adjust_damage_to_workspace_bounds(pixman_region32_t *damage,
struct decoration_data *deco_data, struct sway_workspace *ws) {
float scroll_percent = ws->output->workspace_scroll_percent;
float scale = ws->output->wlr_output->scale;
float scroll_percent = ws->output->workspace_scroll.percent;
int x = 0, y = 0;
int ws_width = ws->current.width + ws->current_gaps.left + ws->current_gaps.right;
int x = round(-ws_width * scroll_percent);
int ws_dimen;
int *coord;
switch (ws->output->workspace_scroll.direction) {
case SWIPE_GESTURE_DIRECTION_NONE:
return;
case SWIPE_GESTURE_DIRECTION_HORIZONTAL:
ws_dimen = ws->current.width + ws->current_gaps.left + ws->current_gaps.right;
coord = &x;
break;
case SWIPE_GESTURE_DIRECTION_VERTICAL:
ws_dimen = ws->current.height + ws->current_gaps.top + ws->current_gaps.bottom;
coord = &y;
break;
}
*coord = round(-ws_dimen * scroll_percent);
if (!deco_data->on_focused_workspace) {
if (scroll_percent > 0) {
x += ws_width;
*coord += ws_dimen;
} else if (scroll_percent < 0) {
x -= ws_width;
*coord -= ws_dimen;
}
}
@ -115,7 +146,7 @@ static void adjust_damage_to_workspace_bounds(pixman_region32_t *damage,
pixman_region32_intersect_rect(damage, damage,
monitor_box.x, monitor_box.y,
monitor_box.width, monitor_box.height);
pixman_region32_translate(damage, x * ws->output->wlr_output->scale, 0);
pixman_region32_translate(damage, x * scale, y * scale);
}
/**
@ -1837,10 +1868,10 @@ static void render_workspace(struct sway_output *output,
struct sway_workspace *other_ws) {
struct sway_workspace *workspaces[2] = { ws, NULL };
if (output->workspace_scroll_percent < 0) {
if (output->workspace_scroll.percent < 0) {
workspaces[0] = other_ws;
workspaces[1] = ws;
} else if (output->workspace_scroll_percent > 0) {
} else if (output->workspace_scroll.percent > 0) {
workspaces[1] = other_ws;
}
@ -1924,7 +1955,7 @@ static void render_floating(struct sway_output *soutput,
struct sway_output *output = root->outputs->items[i];
// Don't render floating windows across outputs when switching workspaces
if (output->workspace_scroll_percent != 0 && output != soutput) {
if (output->workspace_scroll.percent != 0 && output != soutput) {
continue;
}
@ -1932,7 +1963,7 @@ static void render_floating(struct sway_output *soutput,
for (int j = 0; j < output->current.workspaces->length; ++j) {
struct sway_workspace *ws = output->current.workspaces->items[j];
float scroll_percent = soutput->workspace_scroll_percent;
float scroll_percent = soutput->workspace_scroll.percent;
// Only render visible workspace when not scrolling
if (!workspace_is_visible(ws) && scroll_percent == 0) {
@ -2026,7 +2057,7 @@ void output_render(struct sway_output *output, struct timespec *when,
// Get the sibling workspaces
struct sway_workspace *other_ws = NULL;
if (output->workspace_scroll_percent < 0) {
if (output->workspace_scroll.percent < 0) {
other_ws = workspace_output_prev_wrap(workspace, false);
} else {
other_ws = workspace_output_next_wrap(workspace, false);
@ -2053,7 +2084,7 @@ void output_render(struct sway_output *output, struct timespec *when,
int output_width, output_height;
wlr_output_transformed_resolution(wlr_output, &output_width, &output_height);
if (debug.damage == DAMAGE_RERENDER || output->workspace_scroll_percent != 0) {
if (debug.damage == DAMAGE_RERENDER || output->workspace_scroll.percent != 0) {
pixman_region32_union_rect(damage, damage, 0, 0, output_width, output_height);
}
@ -2105,7 +2136,7 @@ void output_render(struct sway_output *output, struct timespec *when,
goto render_overlay;
}
if (fullscreen_con && output->workspace_scroll_percent == 0) {
if (fullscreen_con && output->workspace_scroll.percent == 0) {
// Only draw fullscreen con if not transitioning between workspaces
render_fullscreen_con(damage, output, fullscreen_con, workspace, true);
} else {
@ -2198,10 +2229,10 @@ void output_render(struct sway_output *output, struct timespec *when,
// Render the fullscreen containers on top
if (has_fullscreen) {
struct sway_workspace *workspaces[2] = { workspace, NULL };
if (output->workspace_scroll_percent < 0) {
if (output->workspace_scroll.percent < 0) {
workspaces[0] = other_ws;
workspaces[1] = workspace;
} else if (output->workspace_scroll_percent > 0) {
} else if (output->workspace_scroll.percent > 0) {
workspaces[1] = other_ws;
}
for (int i = 0; i < 2; i++) {

View file

@ -1036,7 +1036,6 @@ static void handle_swipe_update(struct sway_seat *seat,
event->dx, event->dy, NAN, NAN);
struct gesture_tracker *tracker = &seatop->gestures;
struct sway_input_device *device =
event->pointer ? event->pointer->base.data : NULL;
// Determine name of input that received gesture
@ -1047,25 +1046,24 @@ static void handle_swipe_update(struct sway_seat *seat,
struct gesture gesture = {
.fingers = tracker->fingers,
.type = tracker->type,
.directions = fabs(tracker->dx) > fabs(tracker->dy)
? GESTURE_DIRECTION_HORIZONTAL : GESTURE_DIRECTION_VERTICAL,
};
if (fabs(tracker->dx) > fabs(tracker->dy)) {
if (tracker->dx > 0) {
gesture.directions |= GESTURE_DIRECTION_RIGHT;
} else {
gesture.directions |= GESTURE_DIRECTION_LEFT;
}
} else {
if (tracker->dy > 0) {
gesture.directions |= GESTURE_DIRECTION_DOWN;
} else {
gesture.directions |= GESTURE_DIRECTION_UP;
}
}
struct sway_gesture_binding *current = gesture_binding_match(config->current_mode->gesture_bindings, &gesture, input);
int invert = gesture_workspace_swipe_command_parse(current->command);
update_workspace_scroll_percent(seat, seatop->gestures.dx, invert);
struct sway_gesture_binding *binding = gesture_binding_match(
config->current_mode->gesture_bindings, &gesture, input);
if (binding) {
int invert = gesture_workspace_swipe_command_parse(binding->command);
if ((binding->gesture.directions & GESTURE_DIRECTION_VERTICAL) ==
GESTURE_DIRECTION_VERTICAL) {
update_workspace_scroll_percent(seat, tracker->dy, invert,
SWIPE_GESTURE_DIRECTION_VERTICAL);
} else if ((binding->gesture.directions & GESTURE_DIRECTION_HORIZONTAL) ==
GESTURE_DIRECTION_HORIZONTAL) {
update_workspace_scroll_percent(seat, tracker->dx, invert,
SWIPE_GESTURE_DIRECTION_HORIZONTAL);
}
}
} else {
// ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor;

View file

@ -620,7 +620,8 @@ bool workspace_switch(struct sway_workspace *workspace) {
sway_log(SWAY_DEBUG, "Switching to workspace %p:%s",
workspace, workspace->name);
workspace->output->workspace_scroll_percent = 0.0f;
workspace->output->workspace_scroll.percent = 0.0f;
workspace->output->workspace_scroll.direction = SWIPE_GESTURE_DIRECTION_NONE;
struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node);
if (next == NULL) {
next = &workspace->node;