diff --git a/include/sway/commands.h b/include/sway/commands.h index cfe2aa079..5883fa925 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -134,6 +134,7 @@ sway_cmd cmd_force_display_urgency_hint; sway_cmd cmd_force_focus_wrapping; sway_cmd cmd_fullscreen; sway_cmd cmd_gaps; +sway_cmd cmd_gesture; sway_cmd cmd_hide_edge_borders; sway_cmd cmd_include; sway_cmd cmd_inhibit_idle; @@ -184,6 +185,7 @@ sway_cmd cmd_titlebar_padding; sway_cmd cmd_unbindcode; sway_cmd cmd_unbindswitch; sway_cmd cmd_unbindsym; +sway_cmd cmd_touch; sway_cmd cmd_unmark; sway_cmd cmd_urgent; sway_cmd cmd_workspace; @@ -278,6 +280,18 @@ sway_cmd seat_cmd_fallback; sway_cmd seat_cmd_hide_cursor; sway_cmd seat_cmd_pointer_constraint; +sway_cmd touch_cmd_gesture; +sway_cmd touch_cmd_binding; +sway_cmd touch_cmd_target; + +sway_cmd touch_gesture_cmd_touch; +sway_cmd touch_gesture_cmd_threshold; +sway_cmd touch_gesture_cmd_target; +sway_cmd touch_gesture_cmd_swipe; +sway_cmd touch_gesture_cmd_pinch; +sway_cmd touch_gesture_cmd_rotate; +sway_cmd touch_gesture_cmd_delay; + sway_cmd cmd_ipc_cmd; sway_cmd cmd_ipc_events; sway_cmd cmd_ipc_event_cmd; diff --git a/include/sway/config.h b/include/sway/config.h index 864105442..751701579 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -91,6 +91,7 @@ struct sway_mode { list_t *keycode_bindings; list_t *mouse_bindings; list_t *switch_bindings; + list_t *gesture_bindings; bool pango; }; @@ -100,6 +101,17 @@ struct input_config_mapped_from_region { bool mm; }; +struct gesture_config { + char *identifier; + struct libtouch_gesture *gesture; + char *command; +}; + +struct gesture_target_config { + char *identifier; + struct libtouch_target *target; +}; + /** * options for input devices */ @@ -420,6 +432,8 @@ struct sway_config { list_t *output_configs; list_t *input_configs; list_t *input_type_configs; + list_t *gesture_configs; + list_t *gesture_target_configs; list_t *seat_configs; list_t *criteria; list_t *no_focus; @@ -508,6 +522,7 @@ struct sway_config { list_t *feature_policies; list_t *ipc_policies; + struct libtouch_engine *gesture_engine; // Context for command handlers struct { struct input_config *input_config; @@ -517,6 +532,10 @@ struct sway_config { struct sway_node *node; struct sway_container *container; struct sway_workspace *workspace; + + struct gesture_config *current_gesture; + struct libtouch_action *current_gesture_action; + bool using_criteria; struct { int argc; @@ -641,6 +660,20 @@ void free_bar_binding(struct bar_binding *binding); void free_workspace_config(struct workspace_config *wsc); +int gesture_identifier_cmp(const void *item, const void *data); + +int gesture_libtouch_cmp(const void *item, const void *data); + +int gesture_target_identifier_cmp(const void *item, const void *data); + +struct gesture_config *get_gesture_config(const char *identifier); + +struct gesture_config *new_gesture_config(const char *identifier); + +struct gesture_target_config *get_gesture_target_config(const char* identifier); + +struct gesture_target_config *create_gesture_target_config(const char* identifier); + /** * Updates the value of config->font_height based on the max title height * reported by each container. If recalculate is true, the containers will diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 516718c97..2185bc601 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -36,6 +36,7 @@ struct sway_cursor { struct wl_listener axis; struct wl_listener frame; + struct libtouch_progress_tracker *gesture_tracker; struct wl_listener touch_down; struct wl_listener touch_up; struct wl_listener touch_motion; diff --git a/meson.build b/meson.build index 9937eebe4..4628665f3 100644 --- a/meson.build +++ b/meson.build @@ -37,6 +37,7 @@ if is_freebsd add_project_arguments('-D_C11_SOURCE', language: 'c') endif +libtouch = dependency('libtouch') jsonc = dependency('json-c', version: '>=0.13') pcre = dependency('libpcre') wayland_server = dependency('wayland-server') diff --git a/sway/commands.c b/sway/commands.c index 237bfc281..a30590252 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -92,6 +92,7 @@ static struct cmd_handler handlers[] = { { "title_align", cmd_title_align }, { "titlebar_border_thickness", cmd_titlebar_border_thickness }, { "titlebar_padding", cmd_titlebar_padding }, + { "touch", cmd_touch }, { "unbindcode", cmd_unbindcode }, { "unbindswitch", cmd_unbindswitch }, { "unbindsym", cmd_unbindsym }, diff --git a/sway/commands/touch.c b/sway/commands/touch.c new file mode 100644 index 000000000..bd67bb7c8 --- /dev/null +++ b/sway/commands/touch.c @@ -0,0 +1,36 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +// Must be in alphabetical order for bsearch +static struct cmd_handler touch_handlers[] = { + { "binding", touch_cmd_binding }, + { "gesture", touch_cmd_gesture }, + { "target", touch_cmd_target }, +}; + +struct cmd_results *cmd_touch(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "touch", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if(!config->gesture_engine) { + config->gesture_engine = libtouch_engine_create(); + sway_log(SWAY_DEBUG, "Created a new gesture engine"); + } + + if (find_handler(argv[0], touch_handlers, sizeof(touch_handlers))) { + return config_subcommand( + argv,argc,touch_handlers, sizeof(touch_handlers)); + } + return cmd_results_new(CMD_INVALID, "Invalid subcommand: %s", argv[0]); +}; diff --git a/sway/commands/touch/binding.c b/sway/commands/touch/binding.c new file mode 100644 index 000000000..f23c986b3 --- /dev/null +++ b/sway/commands/touch/binding.c @@ -0,0 +1,29 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *touch_cmd_binding(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "binding", EXPECTED_AT_LEAST, 2))) { + return error; + } + + struct gesture_config *config = get_gesture_config(argv[0]); + if (!config) { + return cmd_results_new( + CMD_INVALID, "Unknown gesture %s", argv[0]); + } + + sway_log(SWAY_DEBUG, "libtouch: Bound gesture %s", argv[0]); + + config->command = join_args(argv + 1, argc - 1); + return cmd_results_new(CMD_SUCCESS, NULL); +}; diff --git a/sway/commands/touch/gesture.c b/sway/commands/touch/gesture.c new file mode 100644 index 000000000..db5e64e0e --- /dev/null +++ b/sway/commands/touch/gesture.c @@ -0,0 +1,49 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +static struct cmd_handler gesture_handlers[] = { + { "delay", touch_gesture_cmd_delay }, + { "pinch", touch_gesture_cmd_pinch }, + { "rotate", touch_gesture_cmd_rotate }, + { "swipe", touch_gesture_cmd_swipe }, + { "target", touch_gesture_cmd_target }, + { "threshold", touch_gesture_cmd_threshold }, + { "touch", touch_gesture_cmd_touch }, +}; + +struct cmd_results *touch_cmd_gesture(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "gesture", EXPECTED_AT_LEAST, 2))) { + return error; + } + + struct gesture_config *gesture = get_gesture_config(argv[0]); + + if(!gesture) { + return cmd_results_new(CMD_FAILURE, + "Could not create/find gesture config"); + } + + config->handler_context.current_gesture = gesture; + + struct cmd_handler *cmd = find_handler( + argv[1], gesture_handlers, sizeof(gesture_handlers)); + if (cmd) { + return config_subcommand( + argv + 1,argc - 1, + gesture_handlers, sizeof(gesture_handlers)); + } + + return cmd_results_new(CMD_FAILURE, + "Invalid Subcommand: %s", + argv[1]); +}; diff --git a/sway/commands/touch/gesture/delay.c b/sway/commands/touch/gesture/delay.c new file mode 100644 index 000000000..0d52f3deb --- /dev/null +++ b/sway/commands/touch/gesture/delay.c @@ -0,0 +1,38 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_delay(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "delay", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + long int delay = strtol(argv[0],NULL,10); + if(delay == 0) { + return cmd_results_new( + CMD_INVALID, "Invalid delay %s", argv[0]); + } + if(!config->handler_context.current_gesture) { + return cmd_results_new( + CMD_FAILURE, "No current gesture"); + } + + struct libtouch_gesture *gesture = + config->handler_context.current_gesture->gesture; + + struct libtouch_action *action = + libtouch_gesture_add_delay(gesture, delay); + + config->handler_context.current_gesture_action = action; + + return cmd_results_new(CMD_SUCCESS, NULL); +}; diff --git a/sway/commands/touch/gesture/pinch.c b/sway/commands/touch/gesture/pinch.c new file mode 100644 index 000000000..ae9eab7ae --- /dev/null +++ b/sway/commands/touch/gesture/pinch.c @@ -0,0 +1,38 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_pinch(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "pinch", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + uint32_t mode; + if(strcmp(argv[0],"in") == 0) { + mode = LIBTOUCH_PINCH_IN; + } else if (strcmp(argv[0],"out") == 0) { + mode = LIBTOUCH_PINCH_OUT; + } else { + return cmd_results_new(CMD_INVALID, "pinch: %s is not in or out", argv[0]); + } + + if(!config->handler_context.current_gesture) { + return cmd_results_new(CMD_FAILURE, "No current gesture"); + } + struct libtouch_gesture *gesture = config->handler_context.current_gesture->gesture; + + struct libtouch_action *action = libtouch_gesture_add_pinch(gesture, mode); + + config->handler_context.current_gesture_action = action; + + return cmd_results_new(CMD_SUCCESS, "Created new touch"); +}; diff --git a/sway/commands/touch/gesture/rotate.c b/sway/commands/touch/gesture/rotate.c new file mode 100644 index 000000000..3e450ef16 --- /dev/null +++ b/sway/commands/touch/gesture/rotate.c @@ -0,0 +1,45 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_rotate(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "rotate", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + uint32_t mode; + if(strcmp(argv[0],"clockwise") == 0) { + mode = LIBTOUCH_ROTATE_CLOCKWISE; + } else if (strcmp(argv[0],"counterclockwise") == 0) { + mode = LIBTOUCH_ROTATE_ANTICLOCKWISE; + } else { + return cmd_results_new( + CMD_INVALID, + "rotate %s is not (anti)clockwise", argv[0]); + } + + if(!config->handler_context.current_gesture) { + return cmd_results_new(CMD_FAILURE, "No current gesture"); + } else if (!config->handler_context.current_gesture->gesture) { + return cmd_results_new( + CMD_FAILURE, "No gesture in gesture config"); + } + struct libtouch_gesture *gesture = + config->handler_context.current_gesture->gesture; + + struct libtouch_action *action = + libtouch_gesture_add_rotate(gesture, mode); + + config->handler_context.current_gesture_action = action; + + return cmd_results_new(CMD_SUCCESS, "Created new rotation"); +}; diff --git a/sway/commands/touch/gesture/swipe.c b/sway/commands/touch/gesture/swipe.c new file mode 100644 index 000000000..be69dccf4 --- /dev/null +++ b/sway/commands/touch/gesture/swipe.c @@ -0,0 +1,45 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_swipe(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "swipe", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + uint32_t direction = 0; + if (strstr(argv[0], "west")) { + direction |= LIBTOUCH_MOVE_NEGATIVE_X; + } + if (strstr(argv[0], "east")) { + direction |= LIBTOUCH_MOVE_POSITIVE_X; + } + if (strstr(argv[0], "north")) { + direction |= LIBTOUCH_MOVE_POSITIVE_Y; + } + if (strstr(argv[0], "south")) { + direction |= LIBTOUCH_MOVE_NEGATIVE_Y; + } + + sway_log(SWAY_DEBUG, "Direction: %d", direction); + if (direction == 0) { + return cmd_results_new(CMD_INVALID, "Direction %s invalid", argv[0]); + } + + struct libtouch_gesture *gesture = config->handler_context.current_gesture->gesture; + + struct libtouch_action *action = libtouch_gesture_add_move(gesture, direction); + + config->handler_context.current_gesture_action = action; + + return cmd_results_new(CMD_SUCCESS, "Created new swipe"); +} diff --git a/sway/commands/touch/gesture/target.c b/sway/commands/touch/gesture/target.c new file mode 100644 index 000000000..3262e25ee --- /dev/null +++ b/sway/commands/touch/gesture/target.c @@ -0,0 +1,38 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_target(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "target", EXPECTED_AT_LEAST, 1))) { + return error; + } + + struct gesture_target_config *target = get_gesture_target_config(argv[0]); + + if(!target) { + return cmd_results_new(CMD_FAILURE, "Could not find gesture target %s", argv[0]); + } + + if(!config->handler_context.current_gesture_action) { + return cmd_results_new(CMD_FAILURE, + "No action created for target %s", argv[0]); + + } + + libtouch_action_set_target( + config->handler_context.current_gesture_action, + target->target); + + return cmd_results_new(CMD_SUCCESS, "Bound target %s to action", argv[0]); + + +} diff --git a/sway/commands/touch/gesture/threshold.c b/sway/commands/touch/gesture/threshold.c new file mode 100644 index 000000000..e4e1c7445 --- /dev/null +++ b/sway/commands/touch/gesture/threshold.c @@ -0,0 +1,33 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_threshold(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "touch", EXPECTED_EQUAL_TO, 1))) { + return error; + } + struct libtouch_action *current = + config->handler_context.current_gesture_action; + if(!current) { + return cmd_results_new(CMD_FAILURE, "No action created"); + } + + long int threshold = strtol(argv[0], NULL, 10); + if(threshold == 0) { + return cmd_results_new( + CMD_INVALID, "Invalid threshold: %s", argv[0]); + } + sway_log(SWAY_DEBUG, "Set threshold %ld", threshold); + libtouch_action_set_threshold(current, threshold); + return cmd_results_new(CMD_SUCCESS, + "Set threshold"); +} diff --git a/sway/commands/touch/gesture/touch.c b/sway/commands/touch/gesture/touch.c new file mode 100644 index 000000000..447f4a9b6 --- /dev/null +++ b/sway/commands/touch/gesture/touch.c @@ -0,0 +1,40 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_gesture_cmd_touch(int argc, char **argv) { + struct cmd_results *error = NULL; + if((error = checkarg(argc, "touch", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + uint32_t mode; + if(strcmp(argv[0],"down") == 0) { + mode = LIBTOUCH_TOUCH_DOWN; + } else if (strcmp(argv[0],"up") == 0) { + mode = LIBTOUCH_TOUCH_UP; + } else { + return cmd_results_new(CMD_FAILURE, "Touch: %s is not up or down", argv[0]); + } + + if(!config->handler_context.current_gesture) { + return cmd_results_new(CMD_FAILURE, "No current gesture"); + } else if (!config->handler_context.current_gesture->gesture) { + return cmd_results_new(CMD_FAILURE, "No gesture in gesture config"); + } + struct libtouch_gesture *gesture = config->handler_context.current_gesture->gesture; + + struct libtouch_action *action = libtouch_gesture_add_touch(gesture, mode); + + config->handler_context.current_gesture_action = action; + + return cmd_results_new(CMD_SUCCESS, "Created new touch"); +}; diff --git a/sway/commands/touch/target.c b/sway/commands/touch/target.c new file mode 100644 index 000000000..86ca8121f --- /dev/null +++ b/sway/commands/touch/target.c @@ -0,0 +1,50 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include + +struct cmd_results *touch_cmd_target(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "target", EXPECTED_EQUAL_TO, 5))) { + return error; + } + sway_log(SWAY_DEBUG, "Trying to convert"); + double x = strtod(argv[1], NULL); + double y = strtod(argv[2], NULL); + double w = strtod(argv[3], NULL); + double h = strtod(argv[4], NULL); + sway_log(SWAY_DEBUG, "Converted: %f, %f, %f, %f", x,y,w,h); + + if(!config->gesture_engine) { + return cmd_results_new(CMD_FAILURE, "No engine exists!"); + } + + struct gesture_target_config *conf = get_gesture_target_config(argv[0]); + + if(!conf) { + return cmd_results_new( + CMD_FAILURE, "Could not create target: %s", argv[0]); + } + + if(conf->target != NULL) { + return cmd_results_new( + CMD_FAILURE, "target %s already bound", argv[0]); + } + + struct libtouch_target *target = + libtouch_target_create(config->gesture_engine, x,y,w,h); + + if(!target) { + return cmd_results_new(CMD_FAILURE, "Could not create target"); + } + + conf->target = target; + return cmd_results_new(CMD_SUCCESS, "Created target: %s", argv[0]); +}; diff --git a/sway/config.c b/sway/config.c index e14ea83a8..8c4d03ac0 100644 --- a/sway/config.c +++ b/sway/config.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,7 @@ void free_config(struct sway_config *config) { free(config->floating_scroll_left_cmd); free(config->floating_scroll_right_cmd); free(config->font); + free(config->gesture_engine); free(config->swaybg_command); free(config->swaynag_command); free((char *)config->current_config_path); @@ -188,7 +190,8 @@ static void config_defaults(struct sway_config *config) { "--button-no-terminal 'Exit sway' 'swaymsg exit' " "--button-no-terminal 'Reload sway' 'swaymsg reload'"; config->swaynag_config_errors.detailed = true; - + if (!(config->gesture_configs = create_list())) goto cleanup; + if (!(config->gesture_target_configs = create_list())) goto cleanup; if (!(config->symbols = create_list())) goto cleanup; if (!(config->modes = create_list())) goto cleanup; if (!(config->bars = create_list())) goto cleanup; @@ -312,6 +315,7 @@ static void config_defaults(struct sway_config *config) { set_color(config->border_colors.background, 0xFFFFFF); + if (!(config->gesture_engine = libtouch_engine_create())) goto cleanup; // Security if (!(config->command_policies = create_list())) goto cleanup; if (!(config->feature_policies = create_list())) goto cleanup; diff --git a/sway/config/gesture.c b/sway/config/gesture.c new file mode 100644 index 000000000..362878e5d --- /dev/null +++ b/sway/config/gesture.c @@ -0,0 +1,51 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/config.h" +#include "log.h" +#include + +struct gesture_config *get_gesture_config(const char *identifier) { + int i = list_seq_find( + config->gesture_configs, gesture_identifier_cmp, identifier); + + struct gesture_config *cfg = NULL; + if(i >= 0) { + sway_log(SWAY_DEBUG, "Retrieving existing gesture"); + cfg = config->gesture_configs->items[i]; + } else { + sway_log(SWAY_DEBUG, "Adding new gesture"); + cfg = new_gesture_config(identifier); + } + + return cfg; +} + +struct gesture_config *new_gesture_config(const char *identifier) { + struct gesture_config *cfg = calloc(sizeof(struct gesture_config), 1); + if (!cfg) { + sway_log(SWAY_ERROR, "Failed to allocate gesture_config"); + return NULL; + } + cfg->identifier = strdup(identifier); + cfg->gesture = libtouch_gesture_create(config->gesture_engine); + + return cfg; +} + +int gesture_identifier_cmp(const void *item, const void *data) { + const struct gesture_config *gc = item; + const char *identifier = data; + return strcmp(gc->identifier, identifier); +} + +int gesture_libtouch_cmp(const void *item, const void *data) { + const struct gesture_config *gc = item; + const struct libtouch_gesture *g = data; + if(gc->gesture == g) { + return 0; + } else { + return -1; + } +} diff --git a/sway/config/target.c b/sway/config/target.c new file mode 100644 index 000000000..d1848b4a6 --- /dev/null +++ b/sway/config/target.c @@ -0,0 +1,39 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "sway/config.h" +#include "log.h" +#include + +struct gesture_target_config *get_gesture_target_config(const char* identifier) { + int i = list_seq_find(config->gesture_target_configs, gesture_target_identifier_cmp, identifier); + struct gesture_target_config *cfg = NULL; + if(i >= 0) { + cfg = config->gesture_target_configs->items[i]; + } else { + cfg = create_gesture_target_config(identifier); + list_add(config->gesture_target_configs, cfg); + } + + return cfg; +} + +struct gesture_target_config *create_gesture_target_config(const char* identifier) { + struct gesture_target_config *cfg = + calloc(sizeof(struct gesture_target_config), 1); + if (!cfg) { + sway_log( + SWAY_ERROR, "Could not allocate gesture_target_config"); + } + cfg->identifier = strdup(identifier); + + return cfg; +} + +int gesture_target_identifier_cmp(const void *item, const void *data) { + const struct gesture_target_config *tc = item; + const char* identifier = data; + + return strcmp(identifier, tc->identifier); +} diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 610844479..a7aa44611 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -28,6 +28,7 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "wlr-layer-shell-unstable-v1-protocol.h" +#include static uint32_t get_current_time_msec(void) { struct timespec now; @@ -331,11 +332,28 @@ static void handle_cursor_frame(struct wl_listener *listener, void *data) { wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); } +static void handle_gestures(struct libtouch_progress_tracker *tracker, struct sway_seat *seat) { + struct libtouch_gesture *complete; + while ((complete = libtouch_handle_finished_gesture(tracker)) != NULL) { + int idx = list_seq_find(config->gesture_configs, + gesture_libtouch_cmp, complete); + if (idx >= 0) { + struct gesture_config *cfg; + cfg = config->gesture_configs->items[idx]; + if (cfg->command) { + execute_command(cfg->command, seat, NULL); + } + } else { + sway_log(SWAY_ERROR, "Gesture unbound!"); + } + } +} + static void handle_touch_down(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down); wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); struct wlr_event_touch_down *event = data; - + struct sway_seat *seat = cursor->seat; struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_surface *surface = NULL; @@ -350,6 +368,14 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { seat->touch_x = lx; seat->touch_y = ly; + libtouch_progress_register_touch( + cursor->gesture_tracker, + event->time_msec, + event->touch_id, LIBTOUCH_TOUCH_DOWN, + lx, ly); + + handle_gestures(cursor->gesture_tracker, seat); + if (!surface) { return; } @@ -360,6 +386,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { event->touch_id, sx, sy); cursor_set_image(cursor, NULL, NULL); } + } static void handle_touch_up(struct wl_listener *listener, void *data) { @@ -369,6 +396,10 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { struct wlr_seat *seat = cursor->seat->wlr_seat; // TODO: fall back to cursor simulation if client has not bound to touch wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id); + + libtouch_progress_register_touch(cursor->gesture_tracker, event->time_msec, + event->touch_id, LIBTOUCH_TOUCH_UP, 0, 0); + handle_gestures(cursor->gesture_tracker, cursor->seat); } static void handle_touch_motion(struct wl_listener *listener, void *data) { @@ -376,7 +407,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { wl_container_of(listener, cursor, touch_motion); wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat); struct wlr_event_touch_motion *event = data; - + struct sway_seat *seat = cursor->seat; struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_surface *surface = NULL; @@ -387,6 +418,12 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { double sx, sy; node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy); + sway_log(SWAY_DEBUG, "move gesture"); + libtouch_progress_register_move(cursor->gesture_tracker, event->time_msec, + event->touch_id, lx,ly); + + handle_gestures(cursor->gesture_tracker, seat); + if (seat->touch_id == event->touch_id) { seat->touch_x = lx; seat->touch_y = ly; diff --git a/sway/input/seat.c b/sway/input/seat.c index ce009d7e4..251d1892e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -24,6 +24,7 @@ #include "sway/tree/root.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" +#include static void seat_device_destroy(struct sway_seat_device *seat_device) { if (!seat_device) { @@ -1189,7 +1190,17 @@ void seat_apply_config(struct sway_seat *seat, wl_list_for_each(seat_device, &seat->devices, link) { seat_configure_device(seat, seat_device->input_device); } - + + if(config->gesture_engine) { + sway_log(SWAY_DEBUG, "gesture engine exists"); + if(seat->cursor->gesture_tracker) { + free(seat->cursor->gesture_tracker); + } + sway_log(SWAY_DEBUG, "Gesture progress tracker created"); + seat->cursor->gesture_tracker = libtouch_progress_tracker_create( + config->gesture_engine); + + } cursor_handle_activity(seat->cursor); } diff --git a/sway/meson.build b/sway/meson.build index 0f943a1f3..1406ae1b2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -36,7 +36,9 @@ sway_sources = files( 'config/output.c', 'config/seat.c', 'config/input.c', - + 'config/gesture.c', + 'config/target.c', + 'commands/assign.c', 'commands/bar.c', 'commands/bind.c', @@ -62,6 +64,7 @@ sway_sources = files( 'commands/force_focus_wrapping.c', 'commands/fullscreen.c', 'commands/gaps.c', + 'commands/touch.c', 'commands/hide_edge_borders.c', 'commands/inhibit_idle.c', 'commands/kill.c', @@ -175,6 +178,17 @@ sway_sources = files( 'commands/output/subpixel.c', 'commands/output/transform.c', + 'commands/touch/binding.c', + 'commands/touch/gesture.c', + 'commands/touch/target.c', + 'commands/touch/gesture/touch.c', + 'commands/touch/gesture/threshold.c', + 'commands/touch/gesture/target.c', + 'commands/touch/gesture/swipe.c', + 'commands/touch/gesture/rotate.c', + 'commands/touch/gesture/pinch.c', + 'commands/touch/gesture/delay.c', + 'tree/arrange.c', 'tree/container.c', 'tree/node.c', @@ -185,6 +199,7 @@ sway_sources = files( ) sway_deps = [ + libtouch, cairo, jsonc, libevdev,