Added gesture support
This commit is contained in:
parent
6552778dd6
commit
0c6d69b7fe
|
@ -50,6 +50,8 @@ char *gesture_parse(const char *input, struct gesture *output) {
|
|||
output->type = GESTURE_TYPE_PINCH;
|
||||
} else if (strcmp(split->items[0], "swipe") == 0) {
|
||||
output->type = GESTURE_TYPE_SWIPE;
|
||||
} else if (strcmp(split->items[0], "workspace_swipe") == 0) {
|
||||
output->type = GESTURE_TYPE_WORKSPACE_SWIPE;
|
||||
} else {
|
||||
return strformat("expected hold|pinch|swipe, got %s",
|
||||
split->items[0]);
|
||||
|
@ -117,11 +119,22 @@ const char *gesture_type_string(enum gesture_type type) {
|
|||
return "pinch";
|
||||
case GESTURE_TYPE_SWIPE:
|
||||
return "swipe";
|
||||
case GESTURE_TYPE_WORKSPACE_SWIPE:
|
||||
return "workspace_swipe";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int gesture_workspace_swipe_command_parse(char *cmd) {
|
||||
if (strcmp(cmd, "normal") == 0) {
|
||||
return -1;
|
||||
} else if (strcmp(cmd, "invert") == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *gesture_direction_string(enum gesture_direction direction) {
|
||||
switch (direction) {
|
||||
case GESTURE_DIRECTION_NONE:
|
||||
|
@ -314,6 +327,7 @@ struct gesture *gesture_tracker_end(struct gesture_tracker *tracker) {
|
|||
}
|
||||
__attribute__ ((fallthrough));
|
||||
// Gestures with dx and dy
|
||||
case GESTURE_TYPE_WORKSPACE_SWIPE:
|
||||
case GESTURE_TYPE_SWIPE:
|
||||
if (fabs(tracker->dx) > fabs(tracker->dy)) {
|
||||
if (tracker->dx > 0) {
|
||||
|
|
|
@ -12,11 +12,14 @@ enum gesture_type {
|
|||
GESTURE_TYPE_HOLD,
|
||||
GESTURE_TYPE_PINCH,
|
||||
GESTURE_TYPE_SWIPE,
|
||||
GESTURE_TYPE_WORKSPACE_SWIPE,
|
||||
};
|
||||
|
||||
// Turns single type enum value to constant string representation.
|
||||
const char *gesture_type_string(enum gesture_type direction);
|
||||
|
||||
int gesture_workspace_swipe_command_parse(char *cmd);
|
||||
|
||||
// Value to use to accept any finger count
|
||||
extern const uint8_t GESTURE_FINGERS_ANY;
|
||||
|
||||
|
|
|
@ -202,6 +202,12 @@ 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(int dx, int invert);
|
||||
|
||||
void snap_workspace_scroll_percent(int dx, int invert);
|
||||
|
||||
void reset_workspace_scroll_percent();
|
||||
|
||||
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -154,6 +154,19 @@ static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, boo
|
|||
return gesture_binding_remove(binding, argv[0]);
|
||||
}
|
||||
binding->command = join_args(argv + 1, argc - 1);
|
||||
// Make sure that the gesture command is valid
|
||||
switch (binding->gesture.type) {
|
||||
case GESTURE_TYPE_WORKSPACE_SWIPE:
|
||||
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",
|
||||
bindtype, errmsg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return gesture_binding_add(binding, argv[0], warn);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "util.h"
|
||||
|
||||
struct sway_output *output_by_name_or_id(const char *name_or_id) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
|
@ -1103,3 +1104,95 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
|||
oc = store_output_config(oc);
|
||||
apply_output_config(oc, output);
|
||||
}
|
||||
|
||||
static void workspace_scroll_mark_dirty() {
|
||||
// Damage all outputs
|
||||
struct sway_output *soutput;
|
||||
wl_list_for_each(soutput, &root->all_outputs, link) {
|
||||
output_damage_whole(soutput);
|
||||
}
|
||||
transaction_commit_dirty();
|
||||
}
|
||||
|
||||
void update_workspace_scroll_percent(int dx, int invert) {
|
||||
struct sway_seat *seat = input_manager_get_default_seat();
|
||||
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
|
||||
struct sway_output *output = focused_ws->output;
|
||||
|
||||
int visible_index = list_find(output->workspaces, focused_ws);
|
||||
if (visible_index == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
dx *= 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;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit the percent depending on if the workspace is the first/last or in
|
||||
// the middle somewhere.
|
||||
int min = -1, max = 1;
|
||||
if (visible_index + 1 >= output->workspaces->length) {
|
||||
max = 0;
|
||||
}
|
||||
if (visible_index == 0) {
|
||||
min = 0;
|
||||
}
|
||||
output->workspace_scroll_percent = MIN(max, MAX(min, percent));
|
||||
|
||||
workspace_scroll_mark_dirty();
|
||||
}
|
||||
|
||||
void snap_workspace_scroll_percent(int dx, int invert) {
|
||||
struct sway_seat *seat = input_manager_get_default_seat();
|
||||
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
|
||||
struct sway_output *output = focused_ws->output;
|
||||
|
||||
// TODO: Make the threshold configurable??
|
||||
const float THRESHOLD = 0.35;
|
||||
if (ABS(output->workspace_scroll_percent) <= THRESHOLD) {
|
||||
goto reset;
|
||||
}
|
||||
|
||||
dx *= invert;
|
||||
|
||||
int dir = 0;
|
||||
if (dx < 0) {
|
||||
dir = -1;
|
||||
} else if (dx > 0) {
|
||||
dir = 1;
|
||||
} else {
|
||||
goto reset;
|
||||
}
|
||||
|
||||
int visible_index = list_find(output->workspaces, focused_ws);
|
||||
|
||||
size_t ws_index = wrap(visible_index + dir, output->workspaces->length);
|
||||
struct sway_workspace *new_ws = output->workspaces->items[ws_index];
|
||||
sway_log(SWAY_DEBUG, "Switched to workspace: %s\n", new_ws->name);
|
||||
workspace_switch(new_ws);
|
||||
seat_consider_warp_to_focus(seat);
|
||||
|
||||
reset:
|
||||
// Reset the state
|
||||
reset_workspace_scroll_percent();
|
||||
}
|
||||
|
||||
void reset_workspace_scroll_percent() {
|
||||
struct sway_seat *seat = input_manager_get_default_seat();
|
||||
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
|
||||
struct sway_output *output = focused_ws->output;
|
||||
|
||||
output->workspace_scroll_percent = 0;
|
||||
|
||||
workspace_scroll_mark_dirty();
|
||||
}
|
||||
|
|
|
@ -1011,6 +1011,9 @@ static void handle_swipe_begin(struct sway_seat *seat,
|
|||
if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) {
|
||||
struct seatop_default_event *seatop = seat->seatop_data;
|
||||
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers);
|
||||
} else if (gesture_binding_check(bindings, GESTURE_TYPE_WORKSPACE_SWIPE, event->fingers, device)) {
|
||||
struct seatop_default_event *seatop = seat->seatop_data;
|
||||
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE, event->fingers);
|
||||
} else {
|
||||
// ... otherwise forward to client
|
||||
struct sway_cursor *cursor = seat->cursor;
|
||||
|
@ -1028,6 +1031,41 @@ static void handle_swipe_update(struct sway_seat *seat,
|
|||
if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
|
||||
gesture_tracker_update(&seatop->gestures,
|
||||
event->dx, event->dy, NAN, NAN);
|
||||
} else if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE)) {
|
||||
gesture_tracker_update(&seatop->gestures,
|
||||
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
|
||||
char *input = device
|
||||
? input_device_get_identifier(device->wlr_device)
|
||||
: strdup("*");
|
||||
|
||||
struct gesture gesture = {
|
||||
.fingers = tracker->fingers,
|
||||
.type = tracker->type,
|
||||
};
|
||||
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(seatop->gestures.dx, invert);
|
||||
} else {
|
||||
// ... otherwise forward to client
|
||||
struct sway_cursor *cursor = seat->cursor;
|
||||
|
@ -1041,13 +1079,21 @@ static void handle_swipe_end(struct sway_seat *seat,
|
|||
struct wlr_pointer_swipe_end_event *event) {
|
||||
// Ensure gesture is being tracked and was not cancelled
|
||||
struct seatop_default_event *seatop = seat->seatop_data;
|
||||
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
|
||||
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE) &&
|
||||
!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_WORKSPACE_SWIPE)) {
|
||||
struct sway_cursor *cursor = seat->cursor;
|
||||
wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures,
|
||||
cursor->seat->wlr_seat, event->time_msec, event->cancelled);
|
||||
return;
|
||||
}
|
||||
if (event->cancelled) {
|
||||
switch (seatop->gestures.type) {
|
||||
case GESTURE_TYPE_WORKSPACE_SWIPE:
|
||||
reset_workspace_scroll_percent();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gesture_tracker_cancel(&seatop->gestures);
|
||||
return;
|
||||
}
|
||||
|
@ -1059,7 +1105,15 @@ static void handle_swipe_end(struct sway_seat *seat,
|
|||
&seatop->gestures, device);
|
||||
|
||||
if (binding) {
|
||||
gesture_binding_execute(seat, binding);
|
||||
switch (binding->gesture.type) {
|
||||
case GESTURE_TYPE_WORKSPACE_SWIPE:;
|
||||
int invert = gesture_workspace_swipe_command_parse(binding->command);
|
||||
snap_workspace_scroll_percent(seatop->gestures.dx, invert);
|
||||
break;
|
||||
default:
|
||||
gesture_binding_execute(seat, binding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue