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_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(
 | 
			
		||||
	struct wlr_tablet_v2_tablet_pad *pad,
 | 
			
		||||
	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) {
 | 
			
		||||
		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 {
 | 
			
		||||
		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,
 | 
			
		||||
	.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