Updated swipe percentage calculation to also use avg_velocity

This commit is contained in:
Erik Reider 2024-01-23 18:54:46 +01:00
parent 42fcd6c86d
commit 54daaa9ed2
3 changed files with 80 additions and 45 deletions

View file

@ -19,6 +19,13 @@ enum swipe_gesture_direction {
SWIPE_GESTURE_DIRECTION_VERTICAL, SWIPE_GESTURE_DIRECTION_VERTICAL,
}; };
struct workspace_scroll {
double percent;
double avg_velocity;
int num_updates;
enum swipe_gesture_direction direction;
};
struct render_data { struct render_data {
pixman_region32_t *damage; pixman_region32_t *damage;
struct wlr_box *clip_box; struct wlr_box *clip_box;
@ -64,10 +71,7 @@ struct sway_output {
struct wl_listener frame; struct wl_listener frame;
struct wl_listener needs_frame; struct wl_listener needs_frame;
struct { struct workspace_scroll workspace_scroll;
float percent;
enum swipe_gesture_direction direction;
} workspace_scroll;
struct { struct {
struct wl_signal disable; struct wl_signal disable;
@ -211,10 +215,13 @@ void handle_output_manager_test(struct wl_listener *listener, void *data);
void handle_output_power_manager_set_mode(struct wl_listener *listener, void handle_output_power_manager_set_mode(struct wl_listener *listener,
void *data); void *data);
void update_workspace_scroll_percent(struct sway_seat *seat, int gesture_percent, void workspace_scroll_begin(struct sway_seat *seat,
int invert, enum swipe_gesture_direction direction); enum swipe_gesture_direction direction);
void snap_workspace_scroll_percent(struct sway_seat *seat); void workspace_scroll_update(struct sway_seat *seat, double delta_sum,
enum swipe_gesture_direction direction);
void workspace_scroll_end(struct sway_seat *seat);
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output); struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);

View file

@ -36,6 +36,15 @@
#define PREV_WS_LIMIT -1.0f #define PREV_WS_LIMIT -1.0f
#define NEXT_WS_LIMIT 1.0f #define NEXT_WS_LIMIT 1.0f
static struct workspace_scroll workspace_scroll_get_default() {
return (struct workspace_scroll) {
.percent = 0,
.avg_velocity = 0,
.num_updates = 0,
.direction = SWIPE_GESTURE_DIRECTION_NONE,
};
}
struct sway_output *output_by_name_or_id(const char *name_or_id) { struct sway_output *output_by_name_or_id(const char *name_or_id) {
for (int i = 0; i < root->outputs->length; ++i) { for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i]; struct sway_output *output = root->outputs->items[i];
@ -994,8 +1003,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
wlr_damage_ring_set_bounds(&output->damage_ring, width, height); wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
update_output_manager_config(server); update_output_manager_config(server);
output->workspace_scroll.percent = 0.0f; output->workspace_scroll = workspace_scroll_get_default();
output->workspace_scroll.direction = SWIPE_GESTURE_DIRECTION_NONE;
} }
void handle_output_layout_change(struct wl_listener *listener, void handle_output_layout_change(struct wl_listener *listener,
@ -1109,39 +1117,49 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
apply_output_config(oc, output); apply_output_config(oc, output);
} }
void update_workspace_scroll_percent(struct sway_seat *seat, int gesture_percent, void workspace_scroll_begin(struct sway_seat *seat,
int invert, enum swipe_gesture_direction direction) { enum swipe_gesture_direction direction) {
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat); struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
struct sway_output *output = focused_ws->output; struct sway_output *output = focused_ws->output;
// Reset the state
output->workspace_scroll = workspace_scroll_get_default();
output->workspace_scroll.direction = direction;
output_damage_whole(output);
transaction_commit_dirty();
}
void workspace_scroll_update(struct sway_seat *seat, double delta_sum,
enum swipe_gesture_direction direction) {
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
struct sway_output *output = focused_ws->output;
struct workspace_scroll *ws_scroll = &output->workspace_scroll;
if (direction != ws_scroll->direction) {
return;
}
int visible_index = list_find(output->workspaces, focused_ws); int visible_index = list_find(output->workspaces, focused_ws);
if (visible_index == -1) { if (visible_index == -1) {
return; return;
} }
gesture_percent *= invert; // Get the updated average velocity
ws_scroll->avg_velocity = fabs(delta_sum) / (++ws_scroll->num_updates);
// TODO: Make configurable
const int SPEED_FACTOR = 750;
double percent = delta_sum / SPEED_FACTOR;
// TODO: Make the speed factor configurable?? Works well on my trackpad... double min = PREV_WS_LIMIT, max = NEXT_WS_LIMIT;
// Maybe also take in account the width of the actual trackpad??
const int SPEED_FACTOR = 500;
float percent = 0;
if (gesture_percent < 0) {
percent = (float) gesture_percent / SPEED_FACTOR;
} else if (gesture_percent > 0) {
percent = (float) gesture_percent / SPEED_FACTOR;
} else {
return;
}
float min = PREV_WS_LIMIT, max = NEXT_WS_LIMIT;
if (!config->workspace_gesture_wrap_around) { if (!config->workspace_gesture_wrap_around) {
// Visualized to the user that this is the last / first workspace by // Visualized to the user that this is the last / first workspace by
// allowing a small swipe, a "Spring effect" // allowing a small swipe, a "Spring effect"
float spring_limit = (float) config->workspace_gesture_spring_size / double spring_limit = (double) config->workspace_gesture_spring_size /
output->width * output->wlr_output->scale; output->width * output->wlr_output->scale;
// Make sure that the limit is always smaller than the threshold to // Make sure that the limit is always smaller than the threshold to
// avoid accidental workspace switches // avoid accidental workspace switches
float small_threshold = MAX(config->workspace_gesture_threshold - 0.1, 0); double small_threshold = MAX(config->workspace_gesture_threshold - 0.1, 0);
spring_limit = MIN(small_threshold, spring_limit); spring_limit = MIN(small_threshold, spring_limit);
// Limit the percent depending on if the workspace is the first/last or in // Limit the percent depending on if the workspace is the first/last or in
// the middle somewhere. // the middle somewhere.
@ -1152,32 +1170,42 @@ void update_workspace_scroll_percent(struct sway_seat *seat, int gesture_percent
min = -spring_limit; min = -spring_limit;
} }
} }
output->workspace_scroll.percent = MIN(max, MAX(min, percent)); ws_scroll->percent = CLAMP(percent, min, max);
output->workspace_scroll.direction = direction; ws_scroll->direction = direction;
output_damage_whole(output); output_damage_whole(output);
transaction_commit_dirty(); transaction_commit_dirty();
} }
void snap_workspace_scroll_percent(struct sway_seat *seat) { void workspace_scroll_end(struct sway_seat *seat) {
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat); struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
struct sway_output *output = focused_ws->output; struct sway_output *output = focused_ws->output;
struct workspace_scroll *ws_scroll = &output->workspace_scroll;
if (fabs(output->workspace_scroll.percent) <= config->workspace_gesture_threshold) { int visible_index = list_find(output->workspaces, focused_ws);
goto reset_state;
}
int dir = 0; bool not_edge_ws = config->workspace_gesture_wrap_around;
if (output->workspace_scroll.percent < 0) { int dir;
if (ws_scroll->percent < 0) {
dir = PREV_WS_LIMIT; dir = PREV_WS_LIMIT;
} else if (output->workspace_scroll.percent > 0) { not_edge_ws |= visible_index > 0;
} else if (ws_scroll->percent > 0) {
dir = NEXT_WS_LIMIT; dir = NEXT_WS_LIMIT;
not_edge_ws |= visible_index + 1 < output->workspaces->length;
} else { } else {
// Skip setting workspace if the percentage is zero // Skip setting workspace if the percentage is zero
goto reset_state; goto reset_state;
} }
int visible_index = list_find(output->workspaces, focused_ws); // TODO: Make configurable
const int VELOCITY_NEEDED = 8;
// Only switch workspaces when the percent exceeds the threshold or if
// the avg_speed exceeds the limit (for fast but short swipes).
bool threshold_met = fabs(ws_scroll->percent) >= config->workspace_gesture_threshold;
bool enough_velocity = ws_scroll->avg_velocity >= VELOCITY_NEEDED && not_edge_ws;
if (!threshold_met && !enough_velocity) {
goto reset_state;
}
size_t ws_index = wrap(visible_index + dir, output->workspaces->length); size_t ws_index = wrap(visible_index + dir, output->workspaces->length);
struct sway_workspace *new_ws = output->workspaces->items[ws_index]; struct sway_workspace *new_ws = output->workspaces->items[ws_index];
@ -1187,8 +1215,7 @@ void snap_workspace_scroll_percent(struct sway_seat *seat) {
reset_state: reset_state:
// Reset the state // Reset the state
output->workspace_scroll.percent = 0; output->workspace_scroll = workspace_scroll_get_default();
output->workspace_scroll.direction = SWIPE_GESTURE_DIRECTION_NONE;
output_damage_whole(output); output_damage_whole(output);
transaction_commit_dirty(); transaction_commit_dirty();

View file

@ -1014,9 +1014,11 @@ static void handle_swipe_begin(struct sway_seat *seat,
} else if (gesture_binding_check(bindings, GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL, event->fingers, device)) { } else if (gesture_binding_check(bindings, GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL, event->fingers, device)) {
struct seatop_default_event *seatop = seat->seatop_data; struct seatop_default_event *seatop = seat->seatop_data;
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL, event->fingers); gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL, event->fingers);
workspace_scroll_begin(seat, SWIPE_GESTURE_DIRECTION_HORIZONTAL);
} else if (gesture_binding_check(bindings, GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL, event->fingers, device)) { } else if (gesture_binding_check(bindings, GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL, event->fingers, device)) {
struct seatop_default_event *seatop = seat->seatop_data; struct seatop_default_event *seatop = seat->seatop_data;
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL, event->fingers); gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL, event->fingers);
workspace_scroll_begin(seat, SWIPE_GESTURE_DIRECTION_VERTICAL);
} else { } else {
// ... otherwise forward to client // ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor; struct sway_cursor *cursor = seat->cursor;
@ -1036,9 +1038,6 @@ static void handle_swipe_update(struct sway_seat *seat,
event->dx, event->dy, NAN, NAN); event->dx, event->dy, NAN, NAN);
} else if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL) || } else if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL) ||
gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL)) { gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL)) {
gesture_tracker_update(&seatop->gestures,
event->dx, event->dy, NAN, NAN);
// Find the gesture and update the swipe percentage // Find the gesture and update the swipe percentage
struct gesture_tracker *tracker = &seatop->gestures; struct gesture_tracker *tracker = &seatop->gestures;
struct sway_input_device *device = struct sway_input_device *device =
@ -1058,13 +1057,15 @@ static void handle_swipe_update(struct sway_seat *seat,
if (binding) { if (binding) {
int invert = binding->flags & BINDING_INVERTED ? 1 : -1; int invert = binding->flags & BINDING_INVERTED ? 1 : -1;
tracker->dx += event->dx * invert;
tracker->dy += event->dy * invert;
switch (binding->gesture.type) { switch (binding->gesture.type) {
case GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL: case GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL:
update_workspace_scroll_percent(seat, tracker->dx, invert, workspace_scroll_update(seat, tracker->dx,
SWIPE_GESTURE_DIRECTION_HORIZONTAL); SWIPE_GESTURE_DIRECTION_HORIZONTAL);
break; break;
case GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL: case GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL:
update_workspace_scroll_percent(seat, tracker->dy, invert, workspace_scroll_update(seat, tracker->dy,
SWIPE_GESTURE_DIRECTION_VERTICAL); SWIPE_GESTURE_DIRECTION_VERTICAL);
break; break;
default: default:
@ -1109,7 +1110,7 @@ static void handle_swipe_end(struct sway_seat *seat,
switch (binding->gesture.type) { switch (binding->gesture.type) {
case GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL: case GESTURE_TYPE_WORKSPACE_SWIPE_HORIZONTAL:
case GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL: case GESTURE_TYPE_WORKSPACE_SWIPE_VERTICAL:
snap_workspace_scroll_percent(seat); workspace_scroll_end(seat);
break; break;
default: default:
gesture_binding_execute(seat, binding); gesture_binding_execute(seat, binding);