]> git.mdlowis.com Git - proto/labwc.git/commitdiff
Support smooth scroll and horizontal scroll
authorbi4k8 <bi4k8@github>
Wed, 9 Nov 2022 05:18:14 +0000 (05:18 +0000)
committerJohan Malm <johanmalm@users.noreply.github.com>
Tue, 15 Nov 2022 21:57:36 +0000 (21:57 +0000)
note that this changes Scroll mousebinds from taking a "button"
attribute to taking a "direction" attribute

docs/labwc-config.5.scd
docs/rc.xml.all
include/config/mousebind.h
include/labwc.h
src/config/mousebind.c
src/config/rcxml.c
src/cursor.c

index f85ac8a6524a91afe83175ba9e8fe3b8b6f08f95..7103be35cc56a905e77e630e25ebe11513c64f9c 100644 (file)
@@ -187,7 +187,7 @@ The rest of this man page describes configuration options.
 *<mouse><doubleClickTime>*
        Set double click time in milliseconds. Default is 500.
 
-*<mouse><context name=""><mousebind button=""><action>*
+*<mouse><context name=""><mousebind button="" direction=""><action>*
        Multiple *<mousebind>* can exist within one *<context>*; and multiple
        *<action>* can exist within one *<mousebind>*
 
@@ -219,8 +219,12 @@ The rest of this man page describes configuration options.
        - Left
        - Middle
        - Right
-       - Up (scroll up)
-       - Down (scroll down)
+
+       Supported scroll directions are:
+       - Up
+       - Down
+       - Left
+       - Right
 
        Supported mouse actions include:
        - Press: Pressing the specified button down in the context.
@@ -229,6 +233,7 @@ The rest of this man page describes configuration options.
        - DoubleClick: Two presses within the doubleClickTime.
        - Drag: Pressing the button within the context, then moving the cursor
        - Scroll: Scrolling up or down in the context.
+               Scroll actions must have a *direction* specified instead of *button*.
 
 *<mouse><default />*
        Load default mousebinds. This is an addition to the openbox
index f7c1a24b7d9fa8982dba281ecf14f13e7effd580..14e46d27a11cdc3b0b7e8cb0d7a8325e3a50736b 100644 (file)
       <mousebind button="Middle" action="Press">
         <action name="ShowMenu"><menu>root-menu</menu></action>
       </mousebind>
-      <mousebind button="Up" action="Scroll">
+      <mousebind direction="Up" action="Scroll">
         <action name="GoToDesktop" to="left"/>
       </mousebind>
-      <mousebind button="Down" action="Scroll">
+      <mousebind direction="Down" action="Scroll">
         <action name="GoToDesktop" to="right"/>
       </mousebind>
     </context>
index ca8d35f8671875d9c45c2433c15c974476690981..f7dec7de4723da12a4acf7cd70f1a9b1daee56b8 100644 (file)
@@ -16,12 +16,23 @@ enum mouse_event {
        MOUSE_ACTION_SCROLL,
 };
 
+enum direction {
+       LAB_DIRECTION_INVALID = 0,
+       LAB_DIRECTION_LEFT,
+       LAB_DIRECTION_RIGHT,
+       LAB_DIRECTION_UP,
+       LAB_DIRECTION_DOWN,
+};
+
 struct mousebind {
        enum ssd_part_type context;
 
        /* ex: BTN_LEFT, BTN_RIGHT from linux/input_event_codes.h */
        uint32_t button;
 
+       /* scroll direction; considered instead of button for scroll events */
+       enum direction direction;
+
        /* ex: WLR_MODIFIER_SHIFT | WLR_MODIFIER_LOGO */
        uint32_t modifiers;
 
@@ -35,6 +46,7 @@ struct mousebind {
 
 enum mouse_event mousebind_event_from_str(const char *str);
 uint32_t mousebind_button_from_str(const char *str, uint32_t *modifiers);
+enum direction mousebind_direction_from_str(const char *str, uint32_t *modifiers);
 struct mousebind *mousebind_create(const char *context);
 
 #endif /* __LABWC_MOUSEBIND_H */
index 0325bcf4f24dfa369cd302c403a2fe1464c4ef45..c16cc036f4bbc2b993c5192db59573eb8bc07146 100644 (file)
@@ -107,6 +107,9 @@ struct seat {
        enum lab_cursors server_cursor;
        struct wlr_cursor *cursor;
        struct wlr_xcursor_manager *xcursor_manager;
+       struct {
+               double x, y;
+       } smooth_scroll_offset;
 
        struct wlr_pointer_constraint_v1 *current_constraint;
        struct wlr_idle *wlr_idle;
index 52640a970e7e2867adee06e69616363b8971612d..4c37ad5f8cbceb81ac14c37a21ba1cc18d68c4c2 100644 (file)
@@ -34,16 +34,44 @@ mousebind_button_from_str(const char *str, uint32_t *modifiers)
                return BTN_RIGHT;
        } else if (!strcasecmp(str, "Middle")) {
                return BTN_MIDDLE;
-       } else if (!strcasecmp(str, "Up")) {
-               return BTN_GEAR_UP;
-       } else if (!strcasecmp(str, "Down")) {
-               return BTN_GEAR_DOWN;
        }
 invalid:
        wlr_log(WLR_ERROR, "unknown button (%s)", str);
        return UINT32_MAX;
 }
 
+enum direction
+mousebind_direction_from_str(const char *str, uint32_t *modifiers)
+{
+       assert(str);
+
+       if (modifiers) {
+               *modifiers = 0;
+               while (strlen(str) >= 2 && str[1] == '-') {
+                       char modname[2] = {str[0], 0};
+                       uint32_t parsed_modifier = parse_modifier(modname);
+                       if (!parsed_modifier) {
+                               goto invalid;
+                       }
+                       *modifiers |= parsed_modifier;
+                       str += 2;
+               }
+       }
+
+       if (!strcasecmp(str, "Left")) {
+               return LAB_DIRECTION_LEFT;
+       } else if (!strcasecmp(str, "Right")) {
+               return LAB_DIRECTION_RIGHT;
+       } else if (!strcasecmp(str, "Up")) {
+               return LAB_DIRECTION_UP;
+       } else if (!strcasecmp(str, "Down")) {
+               return LAB_DIRECTION_DOWN;
+       }
+invalid:
+       wlr_log(WLR_ERROR, "unknown direction (%s)", str);
+       return LAB_DIRECTION_INVALID;
+}
+
 enum mouse_event
 mousebind_event_from_str(const char *str)
 {
index 01d35e4f6cb5d9bfed4a433b70e289e4d0667ca5..e5db0f6afaae807e9dac472c2d86fa13ae985c6f 100644 (file)
@@ -131,6 +131,9 @@ fill_mousebind(char *nodename, char *content)
        } else if (!strcmp(nodename, "button")) {
                current_mousebind->button = mousebind_button_from_str(content,
                        &current_mousebind->modifiers);
+       } else if (!strcmp(nodename, "direction")) {
+               current_mousebind->direction = mousebind_direction_from_str(content,
+                       &current_mousebind->modifiers);
        } else if (!strcmp(nodename, "action")) {
                /* <mousebind button="" action="EVENT"> */
                current_mousebind->mouse_event =
@@ -621,9 +624,14 @@ load_default_mouse_bindings(void)
                                || strcmp(current->event, mouse_combos[i - 1].event)) {
                        /* Create new mousebind */
                        m = mousebind_create(current->context);
-                       m->button = mousebind_button_from_str(current->button,
-                               &m->modifiers);
                        m->mouse_event = mousebind_event_from_str(current->event);
+                       if (m->mouse_event == MOUSE_ACTION_SCROLL) {
+                               m->direction = mousebind_direction_from_str(current->button,
+                                       &m->modifiers);
+                       } else {
+                               m->button = mousebind_button_from_str(current->button,
+                                       &m->modifiers);
+                       }
                        count++;
                }
 
@@ -649,6 +657,7 @@ merge_mouse_bindings(void)
                        }
                        if (existing->context == current->context
                                        && existing->button == current->button
+                                       && existing->direction == current->direction
                                        && existing->mouse_event == current->mouse_event) {
                                wl_list_remove(&existing->link);
                                action_list_free(&existing->actions);
index fe4aae509232c686f106577a9e2f8071c289f40e..e5c906339444dba0f39bcbaf5248b28ac24b6633 100644 (file)
@@ -889,6 +889,38 @@ cursor_button(struct wl_listener *listener, void *data)
        }
 }
 
+static int
+compare_delta(const struct wlr_pointer_axis_event *event, double *accum)
+{
+       /*
+        * Smooth scroll deltas are in surface space, so treating each unit as a
+        * scroll event would result in too-fast scrolling.
+        *
+        * This fudge factor (inherited from various historic projects, incl. Weston)
+        * produces events at a more reasonable rate.
+        *
+        * For historic context, see:
+        * https://lists.freedesktop.org/archives/wayland-devel/2019-April/040377.html
+        */
+       const double SCROLL_THRESHOLD = 10.0;
+
+       if (event->delta == 0.0) {
+               /* Delta 0 marks the end of a scroll */
+               *accum = 0.0;
+       } else {
+               /* Accumulate smooth scrolling until we hit threshold */
+               *accum += event->delta;
+       }
+       if (event->delta_discrete < 0 || *accum < -SCROLL_THRESHOLD) {
+               *accum = fmod(*accum, SCROLL_THRESHOLD);
+               return -1;
+       } else if (event->delta_discrete > 0 || *accum > SCROLL_THRESHOLD) {
+               *accum = fmod(*accum, SCROLL_THRESHOLD);
+               return 1;
+       }
+       return 0;
+}
+
 bool
 handle_cursor_axis(struct server *server, struct cursor_context *ctx,
                struct wlr_pointer_axis_event *event)
@@ -899,22 +931,32 @@ handle_cursor_axis(struct server *server, struct cursor_context *ctx,
        uint32_t modifiers = wlr_keyboard_get_modifiers(
                        &server->seat.keyboard_group->keyboard);
 
-       uint32_t button = 0;
-       if (event->delta_discrete < 0) {
-               button = BTN_GEAR_UP;
-       } else if (event->delta_discrete > 0) {
-               button = BTN_GEAR_DOWN;
+       enum direction direction = LAB_DIRECTION_INVALID;
+       if (event->orientation == WLR_AXIS_ORIENTATION_HORIZONTAL) {
+               int rel = compare_delta(event, &server->seat.smooth_scroll_offset.x);
+               if (rel < 0) {
+                       direction = LAB_DIRECTION_LEFT;
+               } else if (rel > 0) {
+                       direction = LAB_DIRECTION_RIGHT;
+               }
+       } else if (event->orientation == WLR_AXIS_ORIENTATION_VERTICAL) {
+               int rel = compare_delta(event, &server->seat.smooth_scroll_offset.y);
+               if (rel < 0) {
+                       direction = LAB_DIRECTION_UP;
+               } else if (rel > 0) {
+                       direction = LAB_DIRECTION_DOWN;
+               }
+       } else {
+               wlr_log(WLR_DEBUG, "Failed to handle cursor axis event");
        }
 
-       if (!button || event->source != WLR_AXIS_SOURCE_WHEEL
-                       || event->orientation != WLR_AXIS_ORIENTATION_VERTICAL) {
-               wlr_log(WLR_DEBUG, "Failed to handle cursor axis event");
+       if (direction == LAB_DIRECTION_INVALID) {
                return false;
        }
 
        wl_list_for_each(mousebind, &rc.mousebinds, link) {
                if (ssd_part_contains(mousebind->context, ctx->type)
-                               && mousebind->button == button
+                               && mousebind->direction == direction
                                && modifiers == mousebind->modifiers
                                && mousebind->mouse_event == MOUSE_ACTION_SCROLL) {
                        handled = true;