diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index d25afbb2..21edb057 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -71,10 +71,16 @@ struct sway_workspace *workspace_by_name(const char*); struct sway_workspace *workspace_output_next(struct sway_workspace *current); +struct sway_workspace *workspace_output_next_wrap(struct sway_workspace *current, + bool should_wrap); + struct sway_workspace *workspace_next(struct sway_workspace *current); struct sway_workspace *workspace_output_prev(struct sway_workspace *current); +struct sway_workspace *workspace_output_prev_wrap(struct sway_workspace *current, + bool should_wrap); + struct sway_workspace *workspace_prev(struct sway_workspace *current); bool workspace_is_visible(struct sway_workspace *ws); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index d1a4e89f..48b11bf6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -1128,16 +1128,25 @@ void update_workspace_scroll_percent(struct sway_seat *seat, int dx, int invert) return; } + // TODO: Make the threshold configurable?? + const float THRESHOLD = MAX(0.35 - 0.1, 0); + + // TODO: Make configurable? + // Visualized to the user that this is the last / first workspace by + // allowing a small swipe, a "Spring effect" + float spring_limit = (float) 50 / output->width * output->wlr_output->scale; + // Make sure that the limit is always smaller than the threshold + spring_limit = MIN(THRESHOLD, spring_limit); // Limit the percent depending on if the workspace is the first/last or in // the middle somewhere. float min = -1.0f, max = 1.0f; if (visible_index + 1 >= output->workspaces->length) { // NOTE: Can be adjusted in the future to wrap around workspaces - max = 0; + max = spring_limit; } if (visible_index == 0) { // NOTE: Can be adjusted in the future to wrap around workspaces - min = 0; + min = -spring_limit; } output->workspace_scroll_percent = MIN(max, MAX(min, percent)); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 734b94da..1d938cf7 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -2027,9 +2027,9 @@ 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) { - other_ws = workspace_output_prev(workspace); + other_ws = workspace_output_prev_wrap(workspace, false); } else { - other_ws = workspace_output_next(workspace); + other_ws = workspace_output_next_wrap(workspace, false); } struct sway_container *fullscreen_con = root->fullscreen_global; diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 1b3d4dfb..99c390b4 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -555,6 +555,44 @@ struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { return workspace_output_prev_next_impl(current->output, -1); } +/** + * Get the previous or next workspace on the specified output. Doesn't wrap + * around at the end and beginning. If next is false, the previous workspace + * is returned, otherwise the next one is returned. + */ +static struct sway_workspace *workspace_output_prev_next_no_wrap_impl( + struct sway_output *output, int dir) { + struct sway_seat *seat = input_manager_current_seat(); + struct sway_workspace *workspace = seat_get_focused_workspace(seat); + if (!workspace) { + sway_log(SWAY_DEBUG, + "No focused workspace to base prev/next on output off of"); + return NULL; + } + + int index = list_find(output->workspaces, workspace) + dir; + if (index < 0 || index >= output->workspaces->length) { + return NULL; + } + return output->workspaces->items[index]; +} + +struct sway_workspace *workspace_output_next_wrap(struct sway_workspace *current, + bool should_wrap) { + if (should_wrap) { + return workspace_output_prev_next_impl(current->output, 1); + } + return workspace_output_prev_next_no_wrap_impl(current->output, 1); +} + +struct sway_workspace *workspace_output_prev_wrap(struct sway_workspace *current, + bool should_wrap) { + if (should_wrap) { + return workspace_output_prev_next_impl(current->output, -1); + } + return workspace_output_prev_next_no_wrap_impl(current->output, -1); +} + struct sway_workspace *workspace_auto_back_and_forth( struct sway_workspace *workspace) { struct sway_seat *seat = input_manager_current_seat();