aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/seatop_default.c
diff options
context:
space:
mode:
authorLibravatar Florian Franzen <Florian.Franzen@gmail.com>2022-04-23 10:27:47 +0200
committerLibravatar Simon Ser <contact@emersion.fr>2022-05-30 12:20:43 +0200
commitcab2189aa64d04ba79dc2cbf19400435b47cdbd2 (patch)
tree450ac51fbc75c73ed1dc6728bc05b08366ace785 /sway/input/seatop_default.c
parentAdd a Hindi (हिन्दी) translation to the README (diff)
downloadsway-cab2189aa64d04ba79dc2cbf19400435b47cdbd2.tar.gz
sway-cab2189aa64d04ba79dc2cbf19400435b47cdbd2.tar.zst
sway-cab2189aa64d04ba79dc2cbf19400435b47cdbd2.zip
sway: add bindgesture command
Co-authored-by: Michael Weiser <michael.weiser@gmx.de>
Diffstat (limited to 'sway/input/seatop_default.c')
-rw-r--r--sway/input/seatop_default.c310
1 files changed, 309 insertions, 1 deletions
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
index 15d1ca8b..2684e55a 100644
--- a/sway/input/seatop_default.c
+++ b/sway/input/seatop_default.c
@@ -4,6 +4,7 @@
4#include <wlr/types/wlr_cursor.h> 4#include <wlr/types/wlr_cursor.h>
5#include <wlr/types/wlr_tablet_v2.h> 5#include <wlr/types/wlr_tablet_v2.h>
6#include <wlr/types/wlr_xcursor_manager.h> 6#include <wlr/types/wlr_xcursor_manager.h>
7#include "gesture.h"
7#include "sway/desktop/transaction.h" 8#include "sway/desktop/transaction.h"
8#include "sway/input/cursor.h" 9#include "sway/input/cursor.h"
9#include "sway/input/seat.h" 10#include "sway/input/seat.h"
@@ -20,6 +21,7 @@ struct seatop_default_event {
20 struct sway_node *previous_node; 21 struct sway_node *previous_node;
21 uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; 22 uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
22 size_t pressed_button_count; 23 size_t pressed_button_count;
24 struct gesture_tracker gestures;
23}; 25};
24 26
25/*-----------------------------------------\ 27/*-----------------------------------------\
@@ -750,6 +752,304 @@ static void handle_pointer_axis(struct sway_seat *seat,
750 } 752 }
751} 753}
752 754
755/*------------------------------------\
756 * Functions used by gesture support /
757 *----------------------------------*/
758
759/**
760 * Check gesture binding for a specific gesture type and finger count.
761 * Returns true if binding is present, false otherwise
762 */
763static bool gesture_binding_check(list_t *bindings, enum gesture_type type,
764 uint8_t fingers, struct sway_input_device *device) {
765 char *input =
766 device ? input_device_get_identifier(device->wlr_device) : strdup("*");
767
768 for (int i = 0; i < bindings->length; ++i) {
769 struct sway_gesture_binding *binding = bindings->items[i];
770
771 // Check type and finger count
772 if (!gesture_check(&binding->gesture, type, fingers)) {
773 continue;
774 }
775
776 // Check that input matches
777 if (strcmp(binding->input, "*") != 0 &&
778 strcmp(binding->input, input) != 0) {
779 continue;
780 }
781
782 free(input);
783
784 return true;
785 }
786
787 free(input);
788
789 return false;
790}
791
792/**
793 * Return the gesture binding which matches gesture type, finger count
794 * and direction, otherwise return null.
795 */
796static struct sway_gesture_binding* gesture_binding_match(
797 list_t *bindings, struct gesture *gesture, const char *input) {
798 struct sway_gesture_binding *current = NULL;
799
800 // Find best matching binding
801 for (int i = 0; i < bindings->length; ++i) {
802 struct sway_gesture_binding *binding = bindings->items[i];
803 bool exact = binding->flags & BINDING_EXACT;
804
805 // Check gesture matching
806 if (!gesture_match(&binding->gesture, gesture, exact)) {
807 continue;
808 }
809
810 // Check input matching
811 if (strcmp(binding->input, "*") != 0 &&
812 strcmp(binding->input, input) != 0) {
813 continue;
814 }
815
816 // If we already have a match ...
817 if (current) {
818 // ... check if input matching is equivalent
819 if (strcmp(current->input, binding->input) == 0) {
820
821 // ... - do not override an exact binding
822 if (!exact && current->flags & BINDING_EXACT) {
823 continue;
824 }
825
826 // ... - and ensure direction matching is better or equal
827 if (gesture_compare(&current->gesture, &binding->gesture) > 0) {
828 continue;
829 }
830 } else if (strcmp(binding->input, "*") == 0) {
831 // ... do not accept worse input match
832 continue;
833 }
834 }
835
836 // Accept newer or better match
837 current = binding;
838
839 // If exact binding and input is found, quit search
840 if (strcmp(current->input, input) == 0 &&
841 gesture_compare(&current->gesture, gesture) == 0) {
842 break;
843 }
844 } // for all gesture bindings
845
846 return current;
847}
848
849// Wrapper around gesture_tracker_end to use tracker with sway bindings
850static struct sway_gesture_binding* gesture_tracker_end_and_match(
851 struct gesture_tracker *tracker, struct sway_input_device* device) {
852 // Determine name of input that received gesture
853 char *input = device
854 ? input_device_get_identifier(device->wlr_device)
855 : strdup("*");
856
857 // Match tracking result to binding
858 struct gesture *gesture = gesture_tracker_end(tracker);
859 struct sway_gesture_binding *binding = gesture_binding_match(
860 config->current_mode->gesture_bindings, gesture, input);
861 free(gesture);
862 free(input);
863
864 return binding;
865}
866
867// Small wrapper around seat_execute_command to work on gesture bindings
868static void gesture_binding_execute(struct sway_seat *seat,
869 struct sway_gesture_binding *binding) {
870 struct sway_binding *dummy_binding =
871 calloc(1, sizeof(struct sway_binding));
872 dummy_binding->type = BINDING_GESTURE;
873 dummy_binding->command = binding->command;
874
875 char *description = gesture_to_string(&binding->gesture);
876 sway_log(SWAY_DEBUG, "executing gesture binding: %s", description);
877 free(description);
878
879 seat_execute_command(seat, dummy_binding);
880
881 free(dummy_binding);
882}
883
884static void handle_hold_begin(struct sway_seat *seat,
885 struct wlr_pointer_hold_begin_event *event) {
886 // Start tracking gesture if there is a matching binding ...
887 struct sway_input_device *device =
888 event->pointer ? event->pointer->base.data : NULL;
889 list_t *bindings = config->current_mode->gesture_bindings;
890 if (gesture_binding_check(bindings, GESTURE_TYPE_HOLD, event->fingers, device)) {
891 struct seatop_default_event *seatop = seat->seatop_data;
892 gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_HOLD, event->fingers);
893 } else {
894 // ... otherwise forward to client
895 struct sway_cursor *cursor = seat->cursor;
896 wlr_pointer_gestures_v1_send_hold_begin(
897 cursor->pointer_gestures, cursor->seat->wlr_seat,
898 event->time_msec, event->fingers);
899 }
900}
901
902static void handle_hold_end(struct sway_seat *seat,
903 struct wlr_pointer_hold_end_event *event) {
904 // Ensure that gesture is being tracked and was not cancelled
905 struct seatop_default_event *seatop = seat->seatop_data;
906 if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) {
907 struct sway_cursor *cursor = seat->cursor;
908 wlr_pointer_gestures_v1_send_hold_end(
909 cursor->pointer_gestures, cursor->seat->wlr_seat,
910 event->time_msec, event->cancelled);
911 return;
912 }
913 if (event->cancelled) {
914 gesture_tracker_cancel(&seatop->gestures);
915 return;
916 }
917
918 // End gesture tracking and execute matched binding
919 struct sway_input_device *device =
920 event->pointer ? event->pointer->base.data : NULL;
921 struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
922 &seatop->gestures, device);
923
924 if (binding) {
925 gesture_binding_execute(seat, binding);
926 }
927}
928
929static void handle_pinch_begin(struct sway_seat *seat,
930 struct wlr_pointer_pinch_begin_event *event) {
931 // Start tracking gesture if there is a matching binding ...
932 struct sway_input_device *device =
933 event->pointer ? event->pointer->base.data : NULL;
934 list_t *bindings = config->current_mode->gesture_bindings;
935 if (gesture_binding_check(bindings, GESTURE_TYPE_PINCH, event->fingers, device)) {
936 struct seatop_default_event *seatop = seat->seatop_data;
937 gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_PINCH, event->fingers);
938 } else {
939 // ... otherwise forward to client
940 struct sway_cursor *cursor = seat->cursor;
941 wlr_pointer_gestures_v1_send_pinch_begin(
942 cursor->pointer_gestures, cursor->seat->wlr_seat,
943 event->time_msec, event->fingers);
944 }
945}
946
947static void handle_pinch_update(struct sway_seat *seat,
948 struct wlr_pointer_pinch_update_event *event) {
949 // Update any ongoing tracking ...
950 struct seatop_default_event *seatop = seat->seatop_data;
951 if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
952 gesture_tracker_update(&seatop->gestures, event->dx, event->dy,
953 event->scale, event->rotation);
954 } else {
955 // ... otherwise forward to client
956 struct sway_cursor *cursor = seat->cursor;
957 wlr_pointer_gestures_v1_send_pinch_update(
958 cursor->pointer_gestures,
959 cursor->seat->wlr_seat,
960 event->time_msec, event->dx, event->dy,
961 event->scale, event->rotation);
962 }
963}
964
965static void handle_pinch_end(struct sway_seat *seat,
966 struct wlr_pointer_pinch_end_event *event) {
967 // Ensure that gesture is being tracked and was not cancelled
968 struct seatop_default_event *seatop = seat->seatop_data;
969 if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
970 struct sway_cursor *cursor = seat->cursor;
971 wlr_pointer_gestures_v1_send_pinch_end(
972 cursor->pointer_gestures, cursor->seat->wlr_seat,
973 event->time_msec, event->cancelled);
974 return;
975 }
976 if (event->cancelled) {
977 gesture_tracker_cancel(&seatop->gestures);
978 return;
979 }
980
981 // End gesture tracking and execute matched binding
982 struct sway_input_device *device =
983 event->pointer ? event->pointer->base.data : NULL;
984 struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
985 &seatop->gestures, device);
986
987 if (binding) {
988 gesture_binding_execute(seat, binding);
989 }
990}
991
992static void handle_swipe_begin(struct sway_seat *seat,
993 struct wlr_pointer_swipe_begin_event *event) {
994 // Start tracking gesture if there is a matching binding ...
995 struct sway_input_device *device =
996 event->pointer ? event->pointer->base.data : NULL;
997 list_t *bindings = config->current_mode->gesture_bindings;
998 if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) {
999 struct seatop_default_event *seatop = seat->seatop_data;
1000 gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers);
1001 } else {
1002 // ... otherwise forward to client
1003 struct sway_cursor *cursor = seat->cursor;
1004 wlr_pointer_gestures_v1_send_swipe_begin(
1005 cursor->pointer_gestures, cursor->seat->wlr_seat,
1006 event->time_msec, event->fingers);
1007 }
1008}
1009
1010static void handle_swipe_update(struct sway_seat *seat,
1011 struct wlr_pointer_swipe_update_event *event) {
1012
1013 // Update any ongoing tracking ...
1014 struct seatop_default_event *seatop = seat->seatop_data;
1015 if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
1016 gesture_tracker_update(&seatop->gestures,
1017 event->dx, event->dy, NAN, NAN);
1018 } else {
1019 // ... otherwise forward to client
1020 struct sway_cursor *cursor = seat->cursor;
1021 wlr_pointer_gestures_v1_send_swipe_update(
1022 cursor->pointer_gestures, cursor->seat->wlr_seat,
1023 event->time_msec, event->dx, event->dy);
1024 }
1025}
1026
1027static void handle_swipe_end(struct sway_seat *seat,
1028 struct wlr_pointer_swipe_end_event *event) {
1029 // Ensure gesture is being tracked and was not cancelled
1030 struct seatop_default_event *seatop = seat->seatop_data;
1031 if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
1032 struct sway_cursor *cursor = seat->cursor;
1033 wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures,
1034 cursor->seat->wlr_seat, event->time_msec, event->cancelled);
1035 return;
1036 }
1037 if (event->cancelled) {
1038 gesture_tracker_cancel(&seatop->gestures);
1039 return;
1040 }
1041
1042 // End gesture tracking and execute matched binding
1043 struct sway_input_device *device =
1044 event->pointer ? event->pointer->base.data : NULL;
1045 struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
1046 &seatop->gestures, device);
1047
1048 if (binding) {
1049 gesture_binding_execute(seat, binding);
1050 }
1051}
1052
753/*----------------------------------\ 1053/*----------------------------------\
754 * Functions used by handle_rebase / 1054 * Functions used by handle_rebase /
755 *--------------------------------*/ 1055 *--------------------------------*/
@@ -779,6 +1079,14 @@ static const struct sway_seatop_impl seatop_impl = {
779 .pointer_axis = handle_pointer_axis, 1079 .pointer_axis = handle_pointer_axis,
780 .tablet_tool_tip = handle_tablet_tool_tip, 1080 .tablet_tool_tip = handle_tablet_tool_tip,
781 .tablet_tool_motion = handle_tablet_tool_motion, 1081 .tablet_tool_motion = handle_tablet_tool_motion,
1082 .hold_begin = handle_hold_begin,
1083 .hold_end = handle_hold_end,
1084 .pinch_begin = handle_pinch_begin,
1085 .pinch_update = handle_pinch_update,
1086 .pinch_end = handle_pinch_end,
1087 .swipe_begin = handle_swipe_begin,
1088 .swipe_update = handle_swipe_update,
1089 .swipe_end = handle_swipe_end,
782 .rebase = handle_rebase, 1090 .rebase = handle_rebase,
783 .allow_set_cursor = true, 1091 .allow_set_cursor = true,
784}; 1092};
@@ -789,8 +1097,8 @@ void seatop_begin_default(struct sway_seat *seat) {
789 struct seatop_default_event *e = 1097 struct seatop_default_event *e =
790 calloc(1, sizeof(struct seatop_default_event)); 1098 calloc(1, sizeof(struct seatop_default_event));
791 sway_assert(e, "Unable to allocate seatop_default_event"); 1099 sway_assert(e, "Unable to allocate seatop_default_event");
1100
792 seat->seatop_impl = &seatop_impl; 1101 seat->seatop_impl = &seatop_impl;
793 seat->seatop_data = e; 1102 seat->seatop_data = e;
794
795 seatop_rebase(seat, 0); 1103 seatop_rebase(seat, 0);
796} 1104}