mirror of
				https://github.com/swaywm/sway.git
				synced 2025-10-29 05:40:18 -04:00 
			
		
		
		
	swaybar: Fix scrolling with precise trackpads
This commit is contained in:
		
							parent
							
								
									f18bcfcd69
								
							
						
					
					
						commit
						4492e493e6
					
				
					 3 changed files with 91 additions and 12 deletions
				
			
		|  | @ -2,6 +2,7 @@ | ||||||
| #define _SWAYBAR_INPUT_H | #define _SWAYBAR_INPUT_H | ||||||
| 
 | 
 | ||||||
| #include <wayland-client.h> | #include <wayland-client.h> | ||||||
|  | #include <stdbool.h> | ||||||
| #include "list.h" | #include "list.h" | ||||||
| 
 | 
 | ||||||
| #define SWAY_SCROLL_UP KEY_MAX + 1 | #define SWAY_SCROLL_UP KEY_MAX + 1 | ||||||
|  | @ -9,6 +10,9 @@ | ||||||
| #define SWAY_SCROLL_LEFT KEY_MAX + 3 | #define SWAY_SCROLL_LEFT KEY_MAX + 3 | ||||||
| #define SWAY_SCROLL_RIGHT KEY_MAX + 4 | #define SWAY_SCROLL_RIGHT KEY_MAX + 4 | ||||||
| 
 | 
 | ||||||
|  | #define SWAY_CONTINUOUS_SCROLL_TIMEOUT 1000 | ||||||
|  | #define SWAY_CONTINUOUS_SCROLL_THRESHOLD 10000 | ||||||
|  | 
 | ||||||
| struct swaybar; | struct swaybar; | ||||||
| struct swaybar_output; | struct swaybar_output; | ||||||
| 
 | 
 | ||||||
|  | @ -50,6 +54,12 @@ struct swaybar_hotspot { | ||||||
| 	void *data; | 	void *data; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct swaybar_scroll_axis { | ||||||
|  | 	wl_fixed_t value; | ||||||
|  | 	uint32_t discrete_steps; | ||||||
|  | 	uint32_t update_time; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct swaybar_seat { | struct swaybar_seat { | ||||||
| 	struct swaybar *bar; | 	struct swaybar *bar; | ||||||
| 	uint32_t wl_name; | 	uint32_t wl_name; | ||||||
|  | @ -57,6 +67,7 @@ struct swaybar_seat { | ||||||
| 	struct swaybar_pointer pointer; | 	struct swaybar_pointer pointer; | ||||||
| 	struct swaybar_touch touch; | 	struct swaybar_touch touch; | ||||||
| 	struct wl_list link; // swaybar_seat:link
 | 	struct wl_list link; // swaybar_seat:link
 | ||||||
|  | 	struct swaybar_scroll_axis axis[2]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern const struct wl_seat_listener seat_listener; | extern const struct wl_seat_listener seat_listener; | ||||||
|  |  | ||||||
|  | @ -340,7 +340,7 @@ static void handle_global(void *data, struct wl_registry *registry, | ||||||
| 		} | 		} | ||||||
| 		seat->bar = bar; | 		seat->bar = bar; | ||||||
| 		seat->wl_name = name; | 		seat->wl_name = name; | ||||||
| 		seat->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 3); | 		seat->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 5); | ||||||
| 		wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); | 		wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); | ||||||
| 		wl_list_insert(&bar->seats, &seat->link); | 		wl_list_insert(&bar->seats, &seat->link); | ||||||
| 	} else if (strcmp(interface, wl_shm_interface.name) == 0) { | 	} else if (strcmp(interface, wl_shm_interface.name) == 0) { | ||||||
|  |  | ||||||
|  | @ -211,18 +211,17 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output, | ||||||
| 
 | 
 | ||||||
| 	if (new) { | 	if (new) { | ||||||
| 		ipc_send_workspace_command(bar, new->name); | 		ipc_send_workspace_command(bar, new->name); | ||||||
|  | 
 | ||||||
|  | 		// Since we're asking Sway to switch to 'new', it should become visible.
 | ||||||
|  | 		// Marking it visible right now allows calling workspace_next in a loop.
 | ||||||
|  | 		new->visible = true; | ||||||
|  | 		active->visible = false; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, | static void process_discrete_scroll(struct swaybar_seat *seat, | ||||||
| 		uint32_t time, uint32_t axis, wl_fixed_t value) { | 		struct swaybar_output *output, struct swaybar_pointer *pointer, | ||||||
| 	struct swaybar_seat *seat = data; | 		uint32_t axis, wl_fixed_t value) { | ||||||
| 	struct swaybar_pointer *pointer = &seat->pointer; |  | ||||||
| 	struct swaybar_output *output = pointer->current; |  | ||||||
| 	if (!sway_assert(output, "axis with no active output")) { |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// If there is a button press binding, execute it, skip default behavior,
 | 	// If there is a button press binding, execute it, skip default behavior,
 | ||||||
| 	// and check button release bindings
 | 	// and check button release bindings
 | ||||||
| 	uint32_t button = wl_axis_to_button(axis, value); | 	uint32_t button = wl_axis_to_button(axis, value); | ||||||
|  | @ -252,8 +251,72 @@ static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, | ||||||
| 	check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_RELEASED); | 	check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_RELEASED); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void process_continuous_scroll(struct swaybar_seat *seat, | ||||||
|  | 		struct swaybar_output *output, struct swaybar_pointer *pointer, | ||||||
|  | 		uint32_t axis) { | ||||||
|  | 	while (abs(seat->axis[axis].value) > SWAY_CONTINUOUS_SCROLL_THRESHOLD) { | ||||||
|  | 		if (seat->axis[axis].value > 0) { | ||||||
|  | 			process_discrete_scroll(seat, output, pointer, axis, | ||||||
|  | 				SWAY_CONTINUOUS_SCROLL_THRESHOLD); | ||||||
|  | 			seat->axis[axis].value -= SWAY_CONTINUOUS_SCROLL_THRESHOLD; | ||||||
|  | 		} else { | ||||||
|  | 			process_discrete_scroll(seat, output, pointer, axis, | ||||||
|  | 				-SWAY_CONTINUOUS_SCROLL_THRESHOLD); | ||||||
|  | 			seat->axis[axis].value += SWAY_CONTINUOUS_SCROLL_THRESHOLD; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, | ||||||
|  | 		uint32_t time, uint32_t axis, wl_fixed_t value) { | ||||||
|  | 	struct swaybar_seat *seat = data; | ||||||
|  | 	struct swaybar_pointer *pointer = &seat->pointer; | ||||||
|  | 	struct swaybar_output *output = pointer->current; | ||||||
|  | 	if (!sway_assert(output, "axis with no active output")) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!sway_assert(axis < 2, "axis out of range")) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// If there's a while since the last scroll event,
 | ||||||
|  | 	// set 'value' to zero as if to reset the "virtual scroll wheel"
 | ||||||
|  | 	if (seat->axis[axis].discrete_steps == 0 && | ||||||
|  | 			time - seat->axis[axis].update_time > SWAY_CONTINUOUS_SCROLL_TIMEOUT) { | ||||||
|  | 		seat->axis[axis].value = 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	seat->axis[axis].value += value; | ||||||
|  | 	seat->axis[axis].update_time = time; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { | static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { | ||||||
| 	// Who cares
 | 	struct swaybar_seat *seat = data; | ||||||
|  | 	struct swaybar_pointer *pointer = &seat->pointer; | ||||||
|  | 	struct swaybar_output *output = pointer->current; | ||||||
|  | 
 | ||||||
|  | 	if (output == NULL) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (uint32_t axis = 0; axis < 2; ++axis) { | ||||||
|  | 		if (seat->axis[axis].discrete_steps) { | ||||||
|  | 			for (uint32_t step = 0; step < seat->axis[axis].discrete_steps; ++step) { | ||||||
|  | 				// Honestly, it would probabyl make sense to pass in
 | ||||||
|  | 				// 'seat->axis[axis].value / seat->axis[axi].discrete_steps' here,
 | ||||||
|  | 				// but it's only used to check whether it's positive or negative
 | ||||||
|  | 				// so I don't think it's worth the risk of rounding errors.
 | ||||||
|  | 				process_discrete_scroll(seat, output, pointer, axis, | ||||||
|  | 					seat->axis[axis].value); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			seat->axis[axis].value = 0; | ||||||
|  | 			seat->axis[axis].discrete_steps = 0; | ||||||
|  | 		} else { | ||||||
|  | 			process_continuous_scroll(seat, output, pointer, axis); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, | static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, | ||||||
|  | @ -268,7 +331,12 @@ static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, | ||||||
| 
 | 
 | ||||||
| static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, | static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, | ||||||
| 		uint32_t axis, int32_t discrete) { | 		uint32_t axis, int32_t discrete) { | ||||||
| 	// Who cares
 | 	struct swaybar_seat *seat = data; | ||||||
|  | 	if (!sway_assert(axis < 2, "axis out of range")) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	seat->axis[axis].discrete_steps += abs(discrete); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct wl_pointer_listener pointer_listener = { | static struct wl_pointer_listener pointer_listener = { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Martin Dørum
						Martin Dørum