Added vertical gesture support
This commit is contained in:
parent
fdf764d3f6
commit
067613854b
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue