summaryrefslogtreecommitdiff
path: root/sway/input/cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r--sway/input/cursor.c185
1 files changed, 111 insertions, 74 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index a5f1204b..36aab93e 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -7,7 +7,7 @@
#include <time.h>
#include <strings.h>
#include <wlr/types/wlr_cursor.h>
-#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_tablet_v2.h>
@@ -53,12 +53,10 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
}
static bool surface_is_xdg_popup(struct wlr_surface *surface) {
- if (wlr_surface_is_xdg_surface(surface)) {
- struct wlr_xdg_surface *xdg_surface =
- wlr_xdg_surface_from_wlr_surface(surface);
- return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP;
- }
- return false;
+ struct wlr_xdg_surface *xdg_surface =
+ wlr_xdg_surface_try_from_wlr_surface(surface);
+ return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP &&
+ xdg_surface->popup != NULL;
}
static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
@@ -239,7 +237,7 @@ void cursor_update_image(struct sway_cursor *cursor,
// Try a node's resize edge
enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor);
if (edge == WLR_EDGE_NONE) {
- cursor_set_image(cursor, "left_ptr", NULL);
+ cursor_set_image(cursor, "default", NULL);
} else if (container_is_floating(node->sway_container)) {
cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
} else {
@@ -250,12 +248,12 @@ void cursor_update_image(struct sway_cursor *cursor,
}
}
} else {
- cursor_set_image(cursor, "left_ptr", NULL);
+ cursor_set_image(cursor, "default", NULL);
}
}
static void cursor_hide(struct sway_cursor *cursor) {
- wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
+ wlr_cursor_unset_image(cursor->cursor);
cursor->hidden = true;
wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat);
}
@@ -367,7 +365,7 @@ void cursor_unhide(struct sway_cursor *cursor) {
wl_event_source_timer_update(cursor->hide_source, cursor_get_timeout(cursor));
}
-static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
+void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel) {
wlr_relative_pointer_manager_v1_send_relative_motion(
@@ -482,43 +480,16 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
cursor_hide(cursor);
struct sway_seat *seat = cursor->seat;
- struct wlr_seat *wlr_seat = seat->wlr_seat;
- struct wlr_surface *surface = NULL;
double lx, ly;
wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
event->x, event->y, &lx, &ly);
- double sx, sy;
- struct sway_node *focused_node = node_at_coords(seat, lx, ly, &surface, &sx, &sy);
seat->touch_id = event->touch_id;
seat->touch_x = lx;
seat->touch_y = ly;
- if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) {
- if (seat_is_input_allowed(seat, surface)) {
- wlr_seat_touch_notify_down(wlr_seat, surface, event->time_msec,
- event->touch_id, sx, sy);
-
- if (focused_node) {
- seat_set_focus(seat, focused_node);
- }
- }
- } else if (!cursor->simulating_pointer_from_touch &&
- (!surface || seat_is_input_allowed(seat, surface))) {
- // Fallback to cursor simulation.
- // The pointer_touch_id state is needed, so drags are not aborted when over
- // a surface supporting touch and multi touch events don't interfere.
- cursor->simulating_pointer_from_touch = true;
- cursor->pointer_touch_id = seat->touch_id;
- double dx, dy;
- dx = lx - cursor->cursor->x;
- dy = ly - cursor->cursor->y;
- pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy,
- dx, dy);
- dispatch_cursor_button(cursor, &event->touch->base, event->time_msec,
- BTN_LEFT, WLR_BUTTON_PRESSED);
- }
+ seatop_touch_down(seat, event, lx, ly);
}
static void handle_touch_up(struct wl_listener *listener, void *data) {
@@ -526,7 +497,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
struct wlr_touch_up_event *event = data;
cursor_handle_activity_from_device(cursor, &event->touch->base);
- struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
+ struct sway_seat *seat = cursor->seat;
if (cursor->simulating_pointer_from_touch) {
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
@@ -535,7 +506,25 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
}
} else {
- wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id);
+ seatop_touch_up(seat, event);
+ }
+}
+
+static void handle_touch_cancel(struct wl_listener *listener, void *data) {
+ struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_cancel);
+ struct wlr_touch_cancel_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->touch->base);
+
+ struct sway_seat *seat = cursor->seat;
+
+ if (cursor->simulating_pointer_from_touch) {
+ if (cursor->pointer_touch_id == cursor->seat->touch_id) {
+ cursor->pointer_touch_up = true;
+ dispatch_cursor_button(cursor, &event->touch->base,
+ event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
+ }
+ } else {
+ seatop_touch_cancel(seat, event);
}
}
@@ -546,19 +535,14 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
cursor_handle_activity_from_device(cursor, &event->touch->base);
struct sway_seat *seat = cursor->seat;
- struct wlr_seat *wlr_seat = seat->wlr_seat;
- struct wlr_surface *surface = NULL;
double lx, ly;
wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
event->x, event->y, &lx, &ly);
- double sx, sy;
- node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
if (seat->touch_id == event->touch_id) {
seat->touch_x = lx;
seat->touch_y = ly;
-
struct sway_drag_icon *drag_icon;
wl_list_for_each(drag_icon, &root->drag_icons, link) {
if (drag_icon->seat == seat) {
@@ -575,9 +559,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
pointer_motion(cursor, event->time_msec, &event->touch->base,
dx, dy, dx, dy);
}
- } else if (surface) {
- wlr_seat_touch_notify_motion(wlr_seat, event->time_msec,
- event->touch_id, sx, sy);
+ } else {
+ seatop_touch_motion(seat, event, lx, ly);
}
}
@@ -836,7 +819,34 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
node_at_coords(cursor->seat, cursor->cursor->x, cursor->cursor->y,
&surface, &sx, &sy);
- if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
+ // TODO: floating resize should support graphics tablet events
+ struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat);
+ uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
+ bool mod_pressed = modifiers & config->floating_mod;
+
+ bool surface_supports_tablet_events =
+ surface && wlr_surface_accepts_tablet_v2(tablet_v2, surface);
+
+ // Simulate pointer when:
+ // 1. The modifier key is pressed, OR
+ // 2. The surface under the cursor does not support tablet events.
+ bool should_simulate_pointer = mod_pressed || !surface_supports_tablet_events;
+
+ // Similar to tool tip, we need to selectively simulate mouse events, but we
+ // want to make sure that it is always consistent. Because all tool buttons
+ // currently map to BTN_RIGHT, we need to keep count of how many tool
+ // buttons are currently pressed down so we can send consistent events.
+ //
+ // The logic follows:
+ // - If we are already simulating the pointer, we should continue to do so
+ // until at least no tool button is held down.
+ // - If we should simulate the pointer and no tool button is currently held
+ // down, begin simulating the pointer.
+ // - If neither of the above are true, send the tablet events.
+ if ((cursor->tool_buttons > 0 && cursor->simulating_pointer_from_tool_button)
+ || (cursor->tool_buttons == 0 && should_simulate_pointer)) {
+ cursor->simulating_pointer_from_tool_button = true;
+
// TODO: the user may want to configure which tool buttons are mapped to
// which simulated pointer buttons
switch (event->state) {
@@ -845,22 +855,35 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_RIGHT, event->state);
}
- cursor->tool_buttons++;
break;
case WLR_BUTTON_RELEASED:
- if (cursor->tool_buttons == 1) {
+ if (cursor->tool_buttons <= 1) {
dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_RIGHT, event->state);
}
- cursor->tool_buttons--;
break;
}
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
- return;
+ } else {
+ cursor->simulating_pointer_from_tool_button = false;
+
+ wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool,
+ event->button, (enum zwp_tablet_pad_v2_button_state)event->state);
}
- wlr_tablet_v2_tablet_tool_notify_button(sway_tool->tablet_v2_tool,
- event->button, (enum zwp_tablet_pad_v2_button_state)event->state);
+ // Update tool button count.
+ switch (event->state) {
+ case WLR_BUTTON_PRESSED:
+ cursor->tool_buttons++;
+ break;
+ case WLR_BUTTON_RELEASED:
+ if (cursor->tool_buttons == 0) {
+ sway_log(SWAY_ERROR, "inconsistent tablet tool button events");
+ } else {
+ cursor->tool_buttons--;
+ }
+ break;
+ }
}
static void check_constraint_region(struct sway_cursor *cursor) {
@@ -1046,10 +1069,9 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image,
}
if (!image) {
- wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
+ wlr_cursor_unset_image(cursor->cursor);
} else if (!current_image || strcmp(current_image, image) != 0) {
- wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
- cursor->cursor);
+ wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image);
}
}
@@ -1096,6 +1118,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
wl_list_remove(&cursor->frame.link);
wl_list_remove(&cursor->touch_down.link);
wl_list_remove(&cursor->touch_up.link);
+ wl_list_remove(&cursor->touch_cancel.link);
wl_list_remove(&cursor->touch_motion.link);
wl_list_remove(&cursor->touch_frame.link);
wl_list_remove(&cursor->tool_axis.link);
@@ -1132,9 +1155,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
wl_list_init(&cursor->image_surface_destroy.link);
cursor->image_surface_destroy.notify = handle_image_surface_destroy;
- // gesture events
- cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display);
-
wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin);
cursor->hold_begin.notify = handle_pointer_hold_begin;
wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end);
@@ -1177,6 +1197,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up);
cursor->touch_up.notify = handle_touch_up;
+ wl_signal_add(&wlr_cursor->events.touch_cancel, &cursor->touch_cancel);
+ cursor->touch_cancel.notify = handle_touch_cancel;
+
wl_signal_add(&wlr_cursor->events.touch_motion,
&cursor->touch_motion);
cursor->touch_motion.notify = handle_touch_motion;
@@ -1269,11 +1292,7 @@ uint32_t get_mouse_bindsym(const char *name, char **error) {
// Get event code from name
int code = libevdev_event_code_from_name(EV_KEY, name);
if (code == -1) {
- size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1;
- *error = malloc(len);
- if (*error) {
- snprintf(*error, len, "Unknown event %s", name);
- }
+ *error = format_str("Unknown event %s", name);
return 0;
}
return code;
@@ -1295,13 +1314,8 @@ uint32_t get_mouse_bindcode(const char *name, char **error) {
}
const char *event = libevdev_event_code_get_name(EV_KEY, code);
if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
- size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button",
- code, event ? event : "(null)") + 1;
- *error = malloc(len);
- if (*error) {
- snprintf(*error, len, "Event code %d (%s) is not a button",
- code, event ? event : "(null)");
- }
+ *error = format_str("Event code %d (%s) is not a button",
+ code, event ? event : "(null)");
return 0;
}
return code;
@@ -1454,3 +1468,26 @@ void sway_cursor_constrain(struct sway_cursor *cursor,
wl_signal_add(&constraint->surface->events.commit,
&cursor->constraint_commit);
}
+
+void handle_request_set_cursor_shape(struct wl_listener *listener, void *data) {
+ const struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
+ struct sway_seat *seat = event->seat_client->seat->data;
+
+ if (!seatop_allows_set_cursor(seat)) {
+ return;
+ }
+
+ struct wl_client *focused_client = NULL;
+ struct wlr_surface *focused_surface = seat->wlr_seat->pointer_state.focused_surface;
+ if (focused_surface != NULL) {
+ focused_client = wl_resource_get_client(focused_surface->resource);
+ }
+
+ // TODO: check cursor mode
+ if (focused_client == NULL || event->seat_client->client != focused_client) {
+ sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client");
+ return;
+ }
+
+ cursor_set_image(seat->cursor, wlr_cursor_shape_v1_name(event->shape), focused_client);
+}