mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-02 03:45:58 +01: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…
Reference in a new issue