Support smooth scroll and horizontal scroll

note that this changes Scroll mousebinds from taking a "button"
attribute to taking a "direction" attribute
This commit is contained in:
bi4k8 2022-11-09 05:18:14 +00:00 committed by Johan Malm
parent 6164ba73ff
commit 2b753a98b8
7 changed files with 119 additions and 20 deletions

View file

@ -187,7 +187,7 @@ The rest of this man page describes configuration options.
*<mouse><doubleClickTime>* *<mouse><doubleClickTime>*
Set double click time in milliseconds. Default is 500. 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 Multiple *<mousebind>* can exist within one *<context>*; and multiple
*<action>* can exist within one *<mousebind>* *<action>* can exist within one *<mousebind>*
@ -219,8 +219,12 @@ The rest of this man page describes configuration options.
- Left - Left
- Middle - Middle
- Right - Right
- Up (scroll up)
- Down (scroll down) Supported scroll directions are:
- Up
- Down
- Left
- Right
Supported mouse actions include: Supported mouse actions include:
- Press: Pressing the specified button down in the context. - 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. - DoubleClick: Two presses within the doubleClickTime.
- Drag: Pressing the button within the context, then moving the cursor - Drag: Pressing the button within the context, then moving the cursor
- Scroll: Scrolling up or down in the context. - Scroll: Scrolling up or down in the context.
Scroll actions must have a *direction* specified instead of *button*.
*<mouse><default />* *<mouse><default />*
Load default mousebinds. This is an addition to the openbox Load default mousebinds. This is an addition to the openbox

View file

@ -301,10 +301,10 @@
<mousebind button="Middle" action="Press"> <mousebind button="Middle" action="Press">
<action name="ShowMenu"><menu>root-menu</menu></action> <action name="ShowMenu"><menu>root-menu</menu></action>
</mousebind> </mousebind>
<mousebind button="Up" action="Scroll"> <mousebind direction="Up" action="Scroll">
<action name="GoToDesktop" to="left"/> <action name="GoToDesktop" to="left"/>
</mousebind> </mousebind>
<mousebind button="Down" action="Scroll"> <mousebind direction="Down" action="Scroll">
<action name="GoToDesktop" to="right"/> <action name="GoToDesktop" to="right"/>
</mousebind> </mousebind>
</context> </context>

View file

@ -16,12 +16,23 @@ enum mouse_event {
MOUSE_ACTION_SCROLL, MOUSE_ACTION_SCROLL,
}; };
enum direction {
LAB_DIRECTION_INVALID = 0,
LAB_DIRECTION_LEFT,
LAB_DIRECTION_RIGHT,
LAB_DIRECTION_UP,
LAB_DIRECTION_DOWN,
};
struct mousebind { struct mousebind {
enum ssd_part_type context; enum ssd_part_type context;
/* ex: BTN_LEFT, BTN_RIGHT from linux/input_event_codes.h */ /* ex: BTN_LEFT, BTN_RIGHT from linux/input_event_codes.h */
uint32_t button; uint32_t button;
/* scroll direction; considered instead of button for scroll events */
enum direction direction;
/* ex: WLR_MODIFIER_SHIFT | WLR_MODIFIER_LOGO */ /* ex: WLR_MODIFIER_SHIFT | WLR_MODIFIER_LOGO */
uint32_t modifiers; uint32_t modifiers;
@ -35,6 +46,7 @@ struct mousebind {
enum mouse_event mousebind_event_from_str(const char *str); enum mouse_event mousebind_event_from_str(const char *str);
uint32_t mousebind_button_from_str(const char *str, uint32_t *modifiers); 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); struct mousebind *mousebind_create(const char *context);
#endif /* __LABWC_MOUSEBIND_H */ #endif /* __LABWC_MOUSEBIND_H */

View file

@ -107,6 +107,9 @@ struct seat {
enum lab_cursors server_cursor; enum lab_cursors server_cursor;
struct wlr_cursor *cursor; struct wlr_cursor *cursor;
struct wlr_xcursor_manager *xcursor_manager; struct wlr_xcursor_manager *xcursor_manager;
struct {
double x, y;
} smooth_scroll_offset;
struct wlr_pointer_constraint_v1 *current_constraint; struct wlr_pointer_constraint_v1 *current_constraint;
struct wlr_idle *wlr_idle; struct wlr_idle *wlr_idle;

View file

@ -34,16 +34,44 @@ mousebind_button_from_str(const char *str, uint32_t *modifiers)
return BTN_RIGHT; return BTN_RIGHT;
} else if (!strcasecmp(str, "Middle")) { } else if (!strcasecmp(str, "Middle")) {
return BTN_MIDDLE; return BTN_MIDDLE;
} else if (!strcasecmp(str, "Up")) {
return BTN_GEAR_UP;
} else if (!strcasecmp(str, "Down")) {
return BTN_GEAR_DOWN;
} }
invalid: invalid:
wlr_log(WLR_ERROR, "unknown button (%s)", str); wlr_log(WLR_ERROR, "unknown button (%s)", str);
return UINT32_MAX; 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 enum mouse_event
mousebind_event_from_str(const char *str) mousebind_event_from_str(const char *str)
{ {

View file

@ -131,6 +131,9 @@ fill_mousebind(char *nodename, char *content)
} else if (!strcmp(nodename, "button")) { } else if (!strcmp(nodename, "button")) {
current_mousebind->button = mousebind_button_from_str(content, current_mousebind->button = mousebind_button_from_str(content,
&current_mousebind->modifiers); &current_mousebind->modifiers);
} else if (!strcmp(nodename, "direction")) {
current_mousebind->direction = mousebind_direction_from_str(content,
&current_mousebind->modifiers);
} else if (!strcmp(nodename, "action")) { } else if (!strcmp(nodename, "action")) {
/* <mousebind button="" action="EVENT"> */ /* <mousebind button="" action="EVENT"> */
current_mousebind->mouse_event = current_mousebind->mouse_event =
@ -621,9 +624,14 @@ load_default_mouse_bindings(void)
|| strcmp(current->event, mouse_combos[i - 1].event)) { || strcmp(current->event, mouse_combos[i - 1].event)) {
/* Create new mousebind */ /* Create new mousebind */
m = mousebind_create(current->context); m = mousebind_create(current->context);
m->button = mousebind_button_from_str(current->button,
&m->modifiers);
m->mouse_event = mousebind_event_from_str(current->event); 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++; count++;
} }
@ -649,6 +657,7 @@ merge_mouse_bindings(void)
} }
if (existing->context == current->context if (existing->context == current->context
&& existing->button == current->button && existing->button == current->button
&& existing->direction == current->direction
&& existing->mouse_event == current->mouse_event) { && existing->mouse_event == current->mouse_event) {
wl_list_remove(&existing->link); wl_list_remove(&existing->link);
action_list_free(&existing->actions); action_list_free(&existing->actions);

View 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 bool
handle_cursor_axis(struct server *server, struct cursor_context *ctx, handle_cursor_axis(struct server *server, struct cursor_context *ctx,
struct wlr_pointer_axis_event *event) 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( uint32_t modifiers = wlr_keyboard_get_modifiers(
&server->seat.keyboard_group->keyboard); &server->seat.keyboard_group->keyboard);
uint32_t button = 0; enum direction direction = LAB_DIRECTION_INVALID;
if (event->delta_discrete < 0) { if (event->orientation == WLR_AXIS_ORIENTATION_HORIZONTAL) {
button = BTN_GEAR_UP; int rel = compare_delta(event, &server->seat.smooth_scroll_offset.x);
} else if (event->delta_discrete > 0) { if (rel < 0) {
button = BTN_GEAR_DOWN; 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 if (direction == LAB_DIRECTION_INVALID) {
|| event->orientation != WLR_AXIS_ORIENTATION_VERTICAL) {
wlr_log(WLR_DEBUG, "Failed to handle cursor axis event");
return false; return false;
} }
wl_list_for_each(mousebind, &rc.mousebinds, link) { wl_list_for_each(mousebind, &rc.mousebinds, link) {
if (ssd_part_contains(mousebind->context, ctx->type) if (ssd_part_contains(mousebind->context, ctx->type)
&& mousebind->button == button && mousebind->direction == direction
&& modifiers == mousebind->modifiers && modifiers == mousebind->modifiers
&& mousebind->mouse_event == MOUSE_ACTION_SCROLL) { && mousebind->mouse_event == MOUSE_ACTION_SCROLL) {
handled = true; handled = true;