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