aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_tablet_v2.h3
-rw-r--r--rootston/seat.c1
-rw-r--r--types/tablet_v2/wlr_tablet_v2_tool.c136
3 files changed, 140 insertions, 0 deletions
diff --git a/include/wlr/types/wlr_tablet_v2.h b/include/wlr/types/wlr_tablet_v2.h
index 3d06bf56..e2a39392 100644
--- a/include/wlr/types/wlr_tablet_v2.h
+++ b/include/wlr/types/wlr_tablet_v2.h
@@ -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,
diff --git a/rootston/seat.c b/rootston/seat.c
index 343720ae..f308da52 100644
--- a/rootston/seat.c
+++ b/rootston/seat.c
@@ -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);
}
diff --git a/types/tablet_v2/wlr_tablet_v2_tool.c b/types/tablet_v2/wlr_tablet_v2_tool.c
index 9165fb23..81c518ab 100644
--- a/types/tablet_v2/wlr_tablet_v2_tool.c
+++ b/types/tablet_v2/wlr_tablet_v2_tool.c
@@ -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);
+}