mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	tablet-v2 tool: Implement implicit grab
Implement the tablet-v2 tablet tool's implicit grab semantics for buttons and tip. This avoids losing focus (to other [sub]surfaces) when a button is held, or the tip is down. This should help when the device is used close to a surface's border and would otherwise have to be very precise.
This commit is contained in:
		
							parent
							
								
									d5950255de
								
							
						
					
					
						commit
						f64962ace8
					
				
					 3 changed files with 140 additions and 0 deletions
				
			
		| 
						 | 
					@ -240,6 +240,9 @@ struct wlr_tablet_tool_v2_grab_interface {
 | 
				
			||||||
void wlr_tablet_tool_v2_start_grab(struct wlr_tablet_v2_tablet_tool *tool, struct wlr_tablet_tool_v2_grab *grab);
 | 
					void wlr_tablet_tool_v2_start_grab(struct wlr_tablet_v2_tablet_tool *tool, struct wlr_tablet_tool_v2_grab *grab);
 | 
				
			||||||
void wlr_tablet_tool_v2_end_grab(struct wlr_tablet_v2_tablet_tool *tool);
 | 
					void wlr_tablet_tool_v2_end_grab(struct wlr_tablet_v2_tablet_tool *tool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_tablet_tool_v2_start_implicit_grab(struct wlr_tablet_v2_tablet_tool *tool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t wlr_send_tablet_v2_tablet_pad_enter(
 | 
					uint32_t wlr_send_tablet_v2_tablet_pad_enter(
 | 
				
			||||||
	struct wlr_tablet_v2_tablet_pad *pad,
 | 
						struct wlr_tablet_v2_tablet_pad *pad,
 | 
				
			||||||
	struct wlr_tablet_v2_tablet *tablet,
 | 
						struct wlr_tablet_v2_tablet *tablet,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -209,6 +209,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (event->state == WLR_TABLET_TOOL_TIP_DOWN) {
 | 
						if (event->state == WLR_TABLET_TOOL_TIP_DOWN) {
 | 
				
			||||||
		wlr_tablet_v2_tablet_tool_notify_down(roots_tool->tablet_v2_tool);
 | 
							wlr_tablet_v2_tablet_tool_notify_down(roots_tool->tablet_v2_tool);
 | 
				
			||||||
 | 
							wlr_tablet_tool_v2_start_implicit_grab(roots_tool->tablet_v2_tool);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		wlr_tablet_v2_tablet_tool_notify_up(roots_tool->tablet_v2_tool);
 | 
							wlr_tablet_v2_tablet_tool_notify_up(roots_tool->tablet_v2_tool);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -693,3 +693,139 @@ static const struct wlr_tablet_tool_v2_grab_interface default_tool_interface = {
 | 
				
			||||||
	.button = default_tool_button,
 | 
						.button = default_tool_button,
 | 
				
			||||||
	.cancel = default_tool_cancel,
 | 
						.cancel = default_tool_cancel,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct implicit_grab_state {
 | 
				
			||||||
 | 
						struct wlr_surface *original;
 | 
				
			||||||
 | 
						bool released;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_surface *focused;
 | 
				
			||||||
 | 
						struct wlr_tablet_v2_tablet *tablet;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void check_and_release_implicit_grab(struct wlr_tablet_tool_v2_grab *grab) {
 | 
				
			||||||
 | 
						struct implicit_grab_state *state = grab->data;
 | 
				
			||||||
 | 
						/* Still button or tip pressed. We should hold the grab */
 | 
				
			||||||
 | 
						if (grab->tool->is_down || grab->tool->num_buttons > 0 || state->released) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state->released = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We should still focus the same surface. Do nothing */
 | 
				
			||||||
 | 
						if (state->original == state->focused) {
 | 
				
			||||||
 | 
							wlr_tablet_tool_v2_end_grab(grab->tool);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_send_tablet_v2_tablet_tool_proximity_out(grab->tool);
 | 
				
			||||||
 | 
						if (state->focused) {
 | 
				
			||||||
 | 
							wlr_send_tablet_v2_tablet_tool_proximity_in(grab->tool,
 | 
				
			||||||
 | 
								state->tablet, state->focused);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_tablet_tool_v2_end_grab(grab->tool);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void implicit_tool_proximity_in(
 | 
				
			||||||
 | 
						struct wlr_tablet_tool_v2_grab *grab,
 | 
				
			||||||
 | 
						struct wlr_tablet_v2_tablet *tablet,
 | 
				
			||||||
 | 
						struct wlr_surface *surface) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* As long as we got an implicit grab, proximity won't change
 | 
				
			||||||
 | 
						 * But should track the currently focused surface to change to it when
 | 
				
			||||||
 | 
						 * the grab is released.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct implicit_grab_state *state = grab->data;
 | 
				
			||||||
 | 
						state->focused = surface;
 | 
				
			||||||
 | 
						state->tablet = tablet;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void implicit_tool_proximity_out(struct wlr_tablet_tool_v2_grab *grab) {
 | 
				
			||||||
 | 
						struct implicit_grab_state *state = grab->data;
 | 
				
			||||||
 | 
						state->focused = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void implicit_tool_down(struct wlr_tablet_tool_v2_grab *grab) {
 | 
				
			||||||
 | 
						wlr_send_tablet_v2_tablet_tool_down(grab->tool);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void implicit_tool_up(struct wlr_tablet_tool_v2_grab *grab) {
 | 
				
			||||||
 | 
						wlr_send_tablet_v2_tablet_tool_up(grab->tool);
 | 
				
			||||||
 | 
						check_and_release_implicit_grab(grab);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Only send the motion event, when we are over the surface for now */
 | 
				
			||||||
 | 
					static void implicit_tool_motion(
 | 
				
			||||||
 | 
						struct wlr_tablet_tool_v2_grab *grab, double x, double y) {
 | 
				
			||||||
 | 
						struct implicit_grab_state *state = grab->data;
 | 
				
			||||||
 | 
						if (state->focused != state->original) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_send_tablet_v2_tablet_tool_motion(grab->tool, x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void implicit_tool_button(
 | 
				
			||||||
 | 
						struct wlr_tablet_tool_v2_grab *grab, uint32_t button,
 | 
				
			||||||
 | 
						enum zwp_tablet_pad_v2_button_state state) {
 | 
				
			||||||
 | 
						wlr_send_tablet_v2_tablet_tool_button(grab->tool, button, state);
 | 
				
			||||||
 | 
						check_and_release_implicit_grab(grab);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void implicit_tool_cancel(struct wlr_tablet_tool_v2_grab *grab) {
 | 
				
			||||||
 | 
						check_and_release_implicit_grab(grab);
 | 
				
			||||||
 | 
						free(grab->data);
 | 
				
			||||||
 | 
						free(grab);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct wlr_tablet_tool_v2_grab_interface implicit_tool_interface = {
 | 
				
			||||||
 | 
						.proximity_in = implicit_tool_proximity_in,
 | 
				
			||||||
 | 
						.down = implicit_tool_down,
 | 
				
			||||||
 | 
						.up = implicit_tool_up,
 | 
				
			||||||
 | 
						.motion = implicit_tool_motion,
 | 
				
			||||||
 | 
						.pressure = default_tool_pressure,
 | 
				
			||||||
 | 
						.distance = default_tool_distance,
 | 
				
			||||||
 | 
						.tilt = default_tool_tilt,
 | 
				
			||||||
 | 
						.rotation = default_tool_rotation,
 | 
				
			||||||
 | 
						.slider = default_tool_slider,
 | 
				
			||||||
 | 
						.wheel = default_tool_wheel,
 | 
				
			||||||
 | 
						.proximity_out = implicit_tool_proximity_out,
 | 
				
			||||||
 | 
						.button = implicit_tool_button,
 | 
				
			||||||
 | 
						.cancel = implicit_tool_cancel,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool tool_has_implicit_grab(struct wlr_tablet_v2_tablet_tool *tool) {
 | 
				
			||||||
 | 
						return tool->grab->interface == &implicit_tool_interface;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wlr_tablet_tool_v2_start_implicit_grab(struct wlr_tablet_v2_tablet_tool *tool) {
 | 
				
			||||||
 | 
						/* Durr */
 | 
				
			||||||
 | 
						if (tool_has_implicit_grab(tool) || !tool->focused_surface) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* No current implicit grab */
 | 
				
			||||||
 | 
						if (!(tool->is_down || tool->num_buttons > 0)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_tablet_tool_v2_grab *grab =
 | 
				
			||||||
 | 
							calloc(1, sizeof(struct wlr_tablet_tool_v2_grab));
 | 
				
			||||||
 | 
						if (!grab) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						grab->interface = &implicit_tool_interface;
 | 
				
			||||||
 | 
						grab->tool = tool;
 | 
				
			||||||
 | 
						struct implicit_grab_state *state = calloc(1, sizeof(struct implicit_grab_state));
 | 
				
			||||||
 | 
						if (!state) {
 | 
				
			||||||
 | 
							free(grab);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state->original = tool->focused_surface;
 | 
				
			||||||
 | 
						grab->data = state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_tablet_tool_v2_start_grab(tool, grab);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue