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
					
				|  | @ -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…
	
		Reference in New Issue