summaryrefslogtreecommitdiff
path: root/sway/input
diff options
context:
space:
mode:
authorReza Jelveh <[email protected]>2024-04-15 13:39:41 +0800
committerGitHub <[email protected]>2024-04-15 01:39:41 -0400
commitfb86ed6b0588dfdebfb66ce875bc63cfa0a897f6 (patch)
tree29857a1769107adc58696f08d379f608aa4e29a2 /sway/input
parenta5e79676c4bd22fc5902182acf0667907202a465 (diff)
feat: 1.9 merge (#277)
Co-authored-by: William McKinnon <[email protected]> Co-authored-by: Erik Reider <[email protected]>
Diffstat (limited to 'sway/input')
-rw-r--r--sway/input/cursor.c185
-rw-r--r--sway/input/input-manager.c60
-rw-r--r--sway/input/keyboard.c50
-rw-r--r--sway/input/libinput.c81
-rw-r--r--sway/input/seat.c167
-rw-r--r--sway/input/seatop_default.c135
-rw-r--r--sway/input/seatop_down.c131
-rw-r--r--sway/input/seatop_move_tiling.c13
-rw-r--r--sway/input/switch.c1
-rw-r--r--sway/input/tablet.c14
10 files changed, 578 insertions, 259 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);
+}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index 39f4b795..288fddc4 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -3,7 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
-#include <wlr/backend/libinput.h>
+#include <wlr/config.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_input_inhibitor.h>
@@ -22,6 +22,10 @@
#include "list.h"
#include "log.h"
+#if WLR_HAS_LIBINPUT_BACKEND
+#include <wlr/backend/libinput.h>
+#endif
+
#define DEFAULT_SEAT "seat0"
struct input_config *current_input_config = NULL;
@@ -76,20 +80,13 @@ char *input_device_get_identifier(struct wlr_input_device *device) {
}
}
- const char *fmt = "%d:%d:%s";
- int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
- char *identifier = malloc(len);
- if (!identifier) {
- sway_log(SWAY_ERROR, "Unable to allocate unique input device name");
- return NULL;
- }
-
- snprintf(identifier, len, fmt, vendor, product, name);
+ char *identifier = format_str("%d:%d:%s", vendor, product, name);
free(name);
return identifier;
}
static bool device_is_touchpad(struct sway_input_device *device) {
+#if WLR_HAS_LIBINPUT_BACKEND
if (device->wlr_device->type != WLR_INPUT_DEVICE_POINTER ||
!wlr_input_device_is_libinput(device->wlr_device)) {
return false;
@@ -99,6 +96,9 @@ static bool device_is_touchpad(struct sway_input_device *device) {
wlr_libinput_get_device_handle(device->wlr_device);
return libinput_device_config_tap_get_finger_count(libinput_device) > 0;
+#else
+ return false;
+#endif
}
const char *input_device_get_type(struct sway_input_device *device) {
@@ -236,7 +236,11 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
apply_input_type_config(input_device);
+#if WLR_HAS_LIBINPUT_BACKEND
bool config_changed = sway_input_configure_libinput_device(input_device);
+#else
+ bool config_changed = false;
+#endif
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = handle_device_destroy;
@@ -491,6 +495,8 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) {
wl_signal_add(&input->keyboard_shortcuts_inhibit->events.new_inhibitor,
&input->keyboard_shortcuts_inhibit_new_inhibitor);
+ input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display);
+
return input;
}
@@ -528,11 +534,27 @@ static void retranslate_keysyms(struct input_config *input_config) {
return;
}
}
+
+ for (int i = 0; i < config->input_type_configs->length; ++i) {
+ struct input_config *ic = config->input_type_configs->items[i];
+ if (ic->xkb_layout || ic->xkb_file) {
+ // this is the first config with xkb_layout or xkb_file
+ if (ic->identifier == input_config->identifier) {
+ translate_keysyms(ic);
+ }
+
+ return;
+ }
+ }
}
static void input_manager_configure_input(
struct sway_input_device *input_device) {
+#if WLR_HAS_LIBINPUT_BACKEND
bool config_changed = sway_input_configure_libinput_device(input_device);
+#else
+ bool config_changed = false;
+#endif
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
seat_configure_device(seat, input_device);
@@ -542,10 +564,20 @@ static void input_manager_configure_input(
}
}
-void input_manager_configure_all_inputs(void) {
- struct sway_input_device *input_device = NULL;
+void input_manager_configure_all_input_mappings(void) {
+ struct sway_input_device *input_device;
wl_list_for_each(input_device, &server.input->devices, link) {
- input_manager_configure_input(input_device);
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat_configure_device_mapping(seat, input_device);
+ }
+
+#if WLR_HAS_LIBINPUT_BACKEND
+ // Input devices mapped to unavailable outputs get their libinput
+ // send_events setting switched to false. We need to re-enable this
+ // when the output appears.
+ sway_input_configure_libinput_device_send_events(input_device);
+#endif
}
}
@@ -567,7 +599,9 @@ void input_manager_apply_input_config(struct input_config *input_config) {
}
void input_manager_reset_input(struct sway_input_device *input_device) {
+#if WLR_HAS_LIBINPUT_BACKEND
sway_input_reset_libinput_device(input_device);
+#endif
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
seat_reset_device(seat, input_device);
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index c5a646c4..8927287f 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -1,10 +1,9 @@
#include <assert.h>
#include <limits.h>
#include <strings.h>
+#include <wlr/config.h>
#include <wlr/backend/multi.h>
-#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_keyboard.h>
-#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <xkbcommon/xkbcommon-names.h>
@@ -16,6 +15,10 @@
#include "sway/ipc-server.h"
#include "log.h"
+#if WLR_HAS_SESSION
+#include <wlr/backend/session.h>
+#endif
+
static struct modifier_key {
char *name;
uint32_t mod;
@@ -264,14 +267,12 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
xkb_keysym_t keysym = pressed_keysyms[i];
if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
keysym <= XKB_KEY_XF86Switch_VT_12) {
- if (wlr_backend_is_multi(server.backend)) {
- struct wlr_session *session =
- wlr_backend_get_session(server.backend);
- if (session) {
- unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
- wlr_session_change_vt(session, vt);
- }
+#if WLR_HAS_SESSION
+ if (server.session) {
+ unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
+ wlr_session_change_vt(server.session, vt);
}
+#endif
return true;
}
}
@@ -715,23 +716,11 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
static void handle_xkb_context_log(struct xkb_context *context,
enum xkb_log_level level, const char *format, va_list args) {
- va_list args_copy;
- va_copy(args_copy, args);
- size_t length = vsnprintf(NULL, 0, format, args_copy) + 1;
- va_end(args_copy);
-
- char *error = malloc(length);
- if (!error) {
- sway_log(SWAY_ERROR, "Failed to allocate libxkbcommon log message");
- return;
- }
+ char *error = vformat_str(format, args);
- va_copy(args_copy, args);
- vsnprintf(error, length, format, args_copy);
- va_end(args_copy);
-
- if (error[length - 2] == '\n') {
- error[length - 2] = '\0';
+ size_t len = strlen(error);
+ if (error[len - 1] == '\n') {
+ error[len - 1] = '\0';
}
sway_log_importance_t importance = SWAY_DEBUG;
@@ -752,7 +741,7 @@ static void handle_xkb_context_log(struct xkb_context *context,
struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic,
char **error) {
- struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV);
if (!sway_assert(context, "cannot create XKB context")) {
return NULL;
}
@@ -766,13 +755,8 @@ struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic,
if (!keymap_file) {
sway_log_errno(SWAY_ERROR, "cannot read xkb file %s", ic->xkb_file);
if (error) {
- size_t len = snprintf(NULL, 0, "cannot read xkb file %s: %s",
- ic->xkb_file, strerror(errno)) + 1;
- *error = malloc(len);
- if (*error) {
- snprintf(*error, len, "cannot read xkb_file %s: %s",
- ic->xkb_file, strerror(errno));
- }
+ *error = format_str("cannot read xkb file %s: %s",
+ ic->xkb_file, strerror(errno));
}
goto cleanup;
}
diff --git a/sway/input/libinput.c b/sway/input/libinput.c
index 53019301..0266c7a9 100644
--- a/sway/input/libinput.c
+++ b/sway/input/libinput.c
@@ -79,6 +79,16 @@ static bool set_accel_speed(struct libinput_device *device, double speed) {
return true;
}
+static bool set_rotation_angle(struct libinput_device *device, double angle) {
+ if (!libinput_device_config_rotation_is_available(device) ||
+ libinput_device_config_rotation_get_angle(device) == angle) {
+ return false;
+ }
+ sway_log(SWAY_DEBUG, "rotation_set_angle(%f)", angle);
+ log_status(libinput_device_config_rotation_set_angle(device, angle));
+ return true;
+}
+
static bool set_accel_profile(struct libinput_device *device,
enum libinput_config_accel_profile profile) {
if (!libinput_device_config_accel_is_available(device) ||
@@ -156,6 +166,18 @@ static bool set_scroll_button(struct libinput_device *dev, uint32_t button) {
return true;
}
+static bool set_scroll_button_lock(struct libinput_device *dev,
+ enum libinput_config_scroll_button_lock_state lock) {
+ uint32_t scroll = libinput_device_config_scroll_get_methods(dev);
+ if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 ||
+ libinput_device_config_scroll_get_button_lock(dev) == lock) {
+ return false;
+ }
+ sway_log(SWAY_DEBUG, "scroll_set_button_lock(%" PRIu32 ")", lock);
+ log_status(libinput_device_config_scroll_set_button_lock(dev, lock));
+ return true;
+}
+
static bool set_dwt(struct libinput_device *device, bool dwt) {
if (!libinput_device_config_dwt_is_available(device) ||
libinput_device_config_dwt_get_enabled(device) == dwt) {
@@ -197,35 +219,38 @@ static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
return changed;
}
-bool sway_input_configure_libinput_device(struct sway_input_device *input_device) {
- struct input_config *ic = input_device_get_config(input_device);
- if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
- return false;
- }
-
- struct libinput_device *device =
- wlr_libinput_get_device_handle(input_device->wlr_device);
- sway_log(SWAY_DEBUG, "sway_input_configure_libinput_device('%s' on '%s')",
- ic->identifier, input_device->identifier);
-
- bool changed = false;
+static bool configure_send_events(struct libinput_device *device,
+ struct input_config *ic) {
if (ic->mapped_to_output &&
+ strcmp("*", ic->mapped_to_output) != 0 &&
!output_by_name_or_id(ic->mapped_to_output)) {
sway_log(SWAY_DEBUG,
"%s '%s' is mapped to offline output '%s'; disabling input",
ic->input_type, ic->identifier, ic->mapped_to_output);
- changed |= set_send_events(device,
- LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
+ return set_send_events(device, LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
} else if (ic->send_events != INT_MIN) {
- changed |= set_send_events(device, ic->send_events);
+ return set_send_events(device, ic->send_events);
} else {
// Have to reset to the default mode here, otherwise if ic->send_events
// is unset and a mapped output just came online after being disabled,
// we'd remain stuck sending no events.
- changed |= set_send_events(device,
+ return set_send_events(device,
libinput_device_config_send_events_get_default_mode(device));
}
+}
+bool sway_input_configure_libinput_device(struct sway_input_device *input_device) {
+ struct input_config *ic = input_device_get_config(input_device);
+ if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
+ return false;
+ }
+
+ struct libinput_device *device =
+ wlr_libinput_get_device_handle(input_device->wlr_device);
+ sway_log(SWAY_DEBUG, "sway_input_configure_libinput_device('%s' on '%s')",
+ ic->identifier, input_device->identifier);
+
+ bool changed = configure_send_events(device, ic);
if (ic->tap != INT_MIN) {
changed |= set_tap(device, ic->tap);
}
@@ -241,6 +266,9 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device
if (ic->pointer_accel != FLT_MIN) {
changed |= set_accel_speed(device, ic->pointer_accel);
}
+ if (ic->rotation_angle != FLT_MIN) {
+ changed |= set_rotation_angle(device, ic->rotation_angle);
+ }
if (ic->accel_profile != INT_MIN) {
changed |= set_accel_profile(device, ic->accel_profile);
}
@@ -262,6 +290,9 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device
if (ic->scroll_button != INT_MIN) {
changed |= set_scroll_button(device, ic->scroll_button);
}
+ if (ic->scroll_button_lock != INT_MIN) {
+ changed |= set_scroll_button_lock(device, ic->scroll_button_lock);
+ }
if (ic->dwt != INT_MIN) {
changed |= set_dwt(device, ic->dwt);
}
@@ -275,6 +306,22 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device
return changed;
}
+void sway_input_configure_libinput_device_send_events(
+ struct sway_input_device *input_device) {
+ struct input_config *ic = input_device_get_config(input_device);
+ if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
+ return;
+ }
+
+ struct libinput_device *device =
+ wlr_libinput_get_device_handle(input_device->wlr_device);
+ bool changed = configure_send_events(device, ic);
+
+ if (changed) {
+ ipc_event_input("libinput_config", input_device);
+ }
+}
+
void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
if (!wlr_input_device_is_libinput(input_device->wlr_device)) {
return;
@@ -298,6 +345,8 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
libinput_device_config_tap_get_default_drag_lock_enabled(device));
changed |= set_accel_speed(device,
libinput_device_config_accel_get_default_speed(device));
+ changed |= set_rotation_angle(device,
+ libinput_device_config_rotation_get_default_angle(device));
changed |= set_accel_profile(device,
libinput_device_config_accel_get_default_profile(device));
changed |= set_natural_scroll(device,
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 28210bb5..43289598 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -4,9 +4,9 @@
#include <string.h>
#include <strings.h>
#include <time.h>
+#include <wlr/config.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_device.h>
-#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_output_layout.h>
@@ -99,22 +99,10 @@ void seat_destroy(struct sway_seat *seat) {
void seat_idle_notify_activity(struct sway_seat *seat,
enum sway_input_idle_source source) {
- uint32_t mask = seat->idle_inhibit_sources;
- struct wlr_idle_timeout *timeout;
- int ntimers = 0, nidle = 0;
- wl_list_for_each(timeout, &server.idle->idle_timers, link) {
- ++ntimers;
- if (timeout->idle_state) {
- ++nidle;
- }
- }
- if (nidle == ntimers) {
- mask = seat->idle_wake_sources;
- }
- if ((source & mask) > 0) {
- wlr_idle_notify_activity(server.idle, seat->wlr_seat);
- wlr_idle_notifier_v1_notify_activity(server.idle_notifier_v1, seat->wlr_seat);
+ if ((source & seat->idle_inhibit_sources) == 0) {
+ return;
}
+ wlr_idle_notifier_v1_notify_activity(server.idle_notifier_v1, seat->wlr_seat);
}
/**
@@ -366,7 +354,7 @@ static void handle_new_node(struct wl_listener *listener, void *data) {
}
static void drag_icon_damage_whole(struct sway_drag_icon *icon) {
- if (!icon->wlr_drag_icon->mapped) {
+ if (!icon->wlr_drag_icon->surface->mapped) {
return;
}
desktop_damage_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, true);
@@ -382,8 +370,8 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
case WLR_DRAG_GRAB_KEYBOARD:
return;
case WLR_DRAG_GRAB_KEYBOARD_POINTER:
- icon->x = cursor->x + wlr_icon->surface->sx;
- icon->y = cursor->y + wlr_icon->surface->sy;
+ icon->x = cursor->x + icon->dx;
+ icon->y = cursor->y + icon->dy;
break;
case WLR_DRAG_GRAB_KEYBOARD_TOUCH:;
struct wlr_touch_point *point =
@@ -391,8 +379,8 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
if (point == NULL) {
return;
}
- icon->x = seat->touch_x + wlr_icon->surface->sx;
- icon->y = seat->touch_y + wlr_icon->surface->sy;
+ icon->x = seat->touch_x + icon->dx;
+ icon->y = seat->touch_y + icon->dy;
}
drag_icon_damage_whole(icon);
@@ -402,6 +390,9 @@ static void drag_icon_handle_surface_commit(struct wl_listener *listener,
void *data) {
struct sway_drag_icon *icon =
wl_container_of(listener, icon, surface_commit);
+ struct wlr_drag_icon *wlr_icon = icon->wlr_drag_icon;
+ icon->dx += wlr_icon->surface->current.dx;
+ icon->dy += wlr_icon->surface->current.dy;
drag_icon_update_position(icon);
}
@@ -507,9 +498,9 @@ static void handle_start_drag(struct wl_listener *listener, void *data) {
icon->surface_commit.notify = drag_icon_handle_surface_commit;
wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit);
icon->unmap.notify = drag_icon_handle_unmap;
- wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap);
+ wl_signal_add(&wlr_drag_icon->surface->events.unmap, &icon->unmap);
icon->map.notify = drag_icon_handle_map;
- wl_signal_add(&wlr_drag_icon->events.map, &icon->map);
+ wl_signal_add(&wlr_drag_icon->surface->events.map, &icon->map);
icon->destroy.notify = drag_icon_handle_destroy;
wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy);
@@ -667,7 +658,7 @@ static void seat_update_capabilities(struct sway_seat *seat) {
} else {
wlr_seat_set_capabilities(seat->wlr_seat, caps);
if ((previous_caps & WL_SEAT_CAPABILITY_POINTER) == 0) {
- cursor_set_image(seat->cursor, "left_ptr", NULL);
+ cursor_set_image(seat->cursor, "default", NULL);
}
}
}
@@ -714,12 +705,21 @@ static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) {
}
}
-static void seat_apply_input_config(struct sway_seat *seat,
+static void seat_apply_input_mapping(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
struct input_config *ic =
input_device_get_config(sway_device->input_device);
- sway_log(SWAY_DEBUG, "Applying input config to %s",
+ switch (sway_device->input_device->wlr_device->type) {
+ case WLR_INPUT_DEVICE_POINTER:
+ case WLR_INPUT_DEVICE_TOUCH:
+ case WLR_INPUT_DEVICE_TABLET_TOOL:
+ break;
+ default:
+ return; // these devices don't support mappings
+ }
+
+ sway_log(SWAY_DEBUG, "Applying input mapping to %s",
sway_device->input_device->identifier);
const char *mapped_to_output = ic == NULL ? NULL : ic->mapped_to_output;
@@ -747,6 +747,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
mapped_to_output = NULL;
break;
}
+#if WLR_HAS_LIBINPUT_BACKEND
if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) &&
sway_libinput_device_is_builtin(sway_device->input_device)) {
mapped_to_output = get_builtin_output_name();
@@ -755,6 +756,10 @@ static void seat_apply_input_config(struct sway_seat *seat,
mapped_to_output, sway_device->input_device->identifier);
}
}
+#else
+ (void)is_touch_or_tablet_tool;
+ (void)get_builtin_output_name;
+#endif
if (mapped_to_output == NULL) {
return;
}
@@ -798,12 +803,9 @@ static void seat_apply_input_config(struct sway_seat *seat,
static void seat_configure_pointer(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
- if ((seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
- seat_configure_xcursor(seat);
- }
+ seat_configure_xcursor(seat);
wlr_cursor_attach_input_device(seat->cursor->cursor,
sway_device->input_device->wlr_device);
- seat_apply_input_config(seat, sway_device);
wl_event_source_timer_update(
seat->cursor->hide_source, cursor_get_timeout(seat->cursor));
}
@@ -838,7 +840,6 @@ static void seat_configure_switch(struct sway_seat *seat,
if (!seat_device->switch_device) {
sway_switch_create(seat, seat_device);
}
- seat_apply_input_config(seat, seat_device);
sway_switch_configure(seat_device->switch_device);
}
@@ -846,7 +847,6 @@ static void seat_configure_touch(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
wlr_cursor_attach_input_device(seat->cursor->cursor,
sway_device->input_device->wlr_device);
- seat_apply_input_config(seat, sway_device);
}
static void seat_configure_tablet_tool(struct sway_seat *seat,
@@ -857,7 +857,6 @@ static void seat_configure_tablet_tool(struct sway_seat *seat,
sway_configure_tablet(sway_device->tablet);
wlr_cursor_attach_input_device(seat->cursor->cursor,
sway_device->input_device->wlr_device);
- seat_apply_input_config(seat, sway_device);
}
static void seat_configure_tablet_pad(struct sway_seat *seat,
@@ -914,6 +913,18 @@ void seat_configure_device(struct sway_seat *seat,
seat_configure_tablet_pad(seat, seat_device);
break;
}
+
+ seat_apply_input_mapping(seat, seat_device);
+}
+
+void seat_configure_device_mapping(struct sway_seat *seat,
+ struct sway_input_device *input_device) {
+ struct sway_seat_device *seat_device = seat_get_device(seat, input_device);
+ if (!seat_device) {
+ return;
+ }
+
+ seat_apply_input_mapping(seat, seat_device);
}
void seat_reset_device(struct sway_seat *seat,
@@ -1030,7 +1041,7 @@ void seat_configure_xcursor(struct sway_seat *seat) {
wlr_xcursor_manager_load(server.xwayland.xcursor_manager, 1);
struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
- server.xwayland.xcursor_manager, "left_ptr", 1);
+ server.xwayland.xcursor_manager, "default", 1);
if (xcursor != NULL) {
struct wlr_xcursor_image *image = xcursor->images[0];
wlr_xwayland_set_cursor(
@@ -1056,26 +1067,27 @@ void seat_configure_xcursor(struct sway_seat *seat) {
sway_log(SWAY_ERROR,
"Cannot create XCursor manager for theme '%s'", cursor_theme);
}
- }
- for (int i = 0; i < root->outputs->length; ++i) {
- struct sway_output *sway_output = root->outputs->items[i];
- struct wlr_output *output = sway_output->wlr_output;
- bool result =
- wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
- output->scale);
- if (!result) {
- sway_log(SWAY_ERROR,
- "Cannot load xcursor theme for output '%s' with scale %f",
- output->name, output->scale);
+
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *sway_output = root->outputs->items[i];
+ struct wlr_output *output = sway_output->wlr_output;
+ bool result =
+ wlr_xcursor_manager_load(seat->cursor->xcursor_manager,
+ output->scale);
+ if (!result) {
+ sway_log(SWAY_ERROR,
+ "Cannot load xcursor theme for output '%s' with scale %f",
+ output->name, output->scale);
+ }
}
- }
- // Reset the cursor so that we apply it to outputs that just appeared
- cursor_set_image(seat->cursor, NULL, NULL);
- cursor_set_image(seat->cursor, "left_ptr", NULL);
- wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x,
- seat->cursor->cursor->y);
+ // Reset the cursor so that we apply it to outputs that just appeared
+ cursor_set_image(seat->cursor, NULL, NULL);
+ cursor_set_image(seat->cursor, "default", NULL);
+ wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x,
+ seat->cursor->cursor->y);
+ }
}
bool seat_is_input_allowed(struct sway_seat *seat,
@@ -1286,11 +1298,15 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n
}
void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
- if (seat->focused_layer) {
+ // Prevents the layer from losing focus if it has keyboard exclusivity
+ if (seat->has_exclusive_layer) {
struct wlr_layer_surface_v1 *layer = seat->focused_layer;
seat_set_focus_layer(seat, NULL);
seat_set_workspace_focus(seat, node);
seat_set_focus_layer(seat, layer);
+ } else if (seat->focused_layer) {
+ seat_set_focus_layer(seat, NULL);
+ seat_set_workspace_focus(seat, node);
} else {
seat_set_workspace_focus(seat, node);
}
@@ -1338,14 +1354,20 @@ void seat_set_focus_layer(struct sway_seat *seat,
seat_set_focus(seat, previous);
}
return;
- } else if (!layer || seat->focused_layer == layer) {
+ } else if (!layer) {
return;
}
- assert(layer->mapped);
- seat_set_focus_surface(seat, layer->surface, true);
- if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
- seat->focused_layer = layer;
+ assert(layer->surface->mapped);
+ if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
+ layer->current.keyboard_interactive
+ == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
+ seat->has_exclusive_layer = true;
}
+ if (seat->focused_layer == layer) {
+ return;
+ }
+ seat_set_focus_surface(seat, layer->surface, true);
+ seat->focused_layer = layer;
}
void seat_set_exclusive_client(struct sway_seat *seat,
@@ -1609,6 +1631,32 @@ void seatop_pointer_axis(struct sway_seat *seat,
}
}
+void seatop_touch_motion(struct sway_seat *seat, struct wlr_touch_motion_event *event,
+ double lx, double ly) {
+ if (seat->seatop_impl->touch_motion) {
+ seat->seatop_impl->touch_motion(seat, event, lx, ly);
+ }
+}
+
+void seatop_touch_up(struct sway_seat *seat, struct wlr_touch_up_event *event) {
+ if (seat->seatop_impl->touch_up) {
+ seat->seatop_impl->touch_up(seat, event);
+ }
+}
+
+void seatop_touch_down(struct sway_seat *seat, struct wlr_touch_down_event *event,
+ double lx, double ly) {
+ if (seat->seatop_impl->touch_down) {
+ seat->seatop_impl->touch_down(seat, event, lx, ly);
+ }
+}
+
+void seatop_touch_cancel(struct sway_seat *seat, struct wlr_touch_cancel_event *event) {
+ if (seat->seatop_impl->touch_cancel) {
+ seat->seatop_impl->touch_cancel(seat, event);
+ }
+}
+
void seatop_tablet_tool_tip(struct sway_seat *seat,
struct sway_tablet_tool *tool, uint32_t time_msec,
enum wlr_tablet_tool_tip_state state) {
@@ -1697,10 +1745,9 @@ void seatop_end(struct sway_seat *seat) {
seat->seatop_impl = NULL;
}
-void seatop_render(struct sway_seat *seat, struct sway_output *output,
- pixman_region32_t *damage) {
+void seatop_render(struct sway_seat *seat, struct fx_render_context *ctx) {
if (seat->seatop_impl->render) {
- seat->seatop_impl->render(seat, output, damage);
+ seat->seatop_impl->render(seat, ctx);
}
}
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
index 84acefdf..1dce6dae 100644
--- a/sway/input/seatop_default.c
+++ b/sway/input/seatop_default.c
@@ -2,6 +2,7 @@
#include <float.h>
#include <libevdev/libevdev.h>
#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include "gesture.h"
@@ -9,6 +10,7 @@
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/input/tablet.h"
+#include "sway/layers.h"
#include "sway/output.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@@ -228,14 +230,15 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
struct sway_container *cont = node && node->type == N_CONTAINER ?
node->sway_container : NULL;
- if (wlr_surface_is_layer_surface(surface)) {
+ struct wlr_layer_surface_v1 *layer;
+#if HAVE_XWAYLAND
+ struct wlr_xwayland_surface *xsurface;
+#endif
+ if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) &&
+ layer->current.keyboard_interactive) {
// Handle tapping a layer surface
- struct wlr_layer_surface_v1 *layer =
- wlr_layer_surface_v1_from_wlr_surface(surface);
- if (layer->current.keyboard_interactive) {
- seat_set_focus_layer(seat, layer);
- transaction_commit_dirty();
- }
+ seat_set_focus_layer(seat, layer);
+ transaction_commit_dirty();
} else if (cont) {
bool is_floating_or_child = container_is_floating_or_child(cont);
bool is_fullscreen_or_child = container_is_fullscreen_or_child(cont);
@@ -260,20 +263,17 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
// Handle tapping on a container surface
seat_set_focus_container(seat, cont);
- seatop_begin_down(seat, node->sway_container, time_msec, sx, sy);
+ seatop_begin_down(seat, node->sway_container, sx, sy);
}
#if HAVE_XWAYLAND
// Handle tapping on an xwayland unmanaged view
- else if (wlr_surface_is_xwayland_surface(surface)) {
- struct wlr_xwayland_surface *xsurface =
- wlr_xwayland_surface_from_wlr_surface(surface);
- if (xsurface->override_redirect &&
- wlr_xwayland_or_surface_wants_focus(xsurface)) {
- struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
- wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
- seat_set_focus_surface(seat, xsurface->surface, false);
- transaction_commit_dirty();
- }
+ else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
+ xsurface->override_redirect &&
+ wlr_xwayland_or_surface_wants_focus(xsurface)) {
+ struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
+ wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
+ seat_set_focus_surface(seat, xsurface->surface, false);
+ transaction_commit_dirty();
}
#endif
@@ -367,16 +367,15 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
return;
}
- // Handle clicking a layer surface
- if (surface && wlr_surface_is_layer_surface(surface)) {
- struct wlr_layer_surface_v1 *layer =
- wlr_layer_surface_v1_from_wlr_surface(surface);
+ // Handle clicking a layer surface and its popups/subsurfaces
+ struct wlr_layer_surface_v1 *layer = NULL;
+ if ((layer = toplevel_layer_surface_from_surface(surface))) {
if (layer->current.keyboard_interactive) {
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
}
if (state == WLR_BUTTON_PRESSED) {
- seatop_begin_down_on_surface(seat, surface, time_msec, sx, sy);
+ seatop_begin_down_on_surface(seat, surface, sx, sy);
}
seat_pointer_notify_button(seat, time_msec, button, state);
return;
@@ -501,7 +500,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle mousedown on a container surface
if (surface && cont && state == WLR_BUTTON_PRESSED) {
- seatop_begin_down(seat, cont, time_msec, sx, sy);
+ seatop_begin_down(seat, cont, sx, sy);
seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
return;
}
@@ -514,18 +513,16 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
#if HAVE_XWAYLAND
// Handle clicking on xwayland unmanaged view
- if (surface && wlr_surface_is_xwayland_surface(surface)) {
- struct wlr_xwayland_surface *xsurface =
- wlr_xwayland_surface_from_wlr_surface(surface);
- if (xsurface->override_redirect &&
- wlr_xwayland_or_surface_wants_focus(xsurface)) {
- struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
- wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
- seat_set_focus_surface(seat, xsurface->surface, false);
- transaction_commit_dirty();
- seat_pointer_notify_button(seat, time_msec, button, state);
- return;
- }
+ struct wlr_xwayland_surface *xsurface;
+ if (surface &&
+ (xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
+ xsurface->override_redirect &&
+ wlr_xwayland_or_surface_wants_focus(xsurface)) {
+ struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
+ wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
+ seat_set_focus_surface(seat, xsurface->surface, false);
+ transaction_commit_dirty();
+ seat_pointer_notify_button(seat, time_msec, button, state);
}
#endif
@@ -548,6 +545,21 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
if (wlr_output == NULL) {
return;
}
+
+ struct wlr_surface *surface = NULL;
+ double sx, sy;
+ node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y,
+ &surface, &sx, &sy);
+
+ // Focus topmost layer surface
+ struct wlr_layer_surface_v1 *layer = NULL;
+ if ((layer = toplevel_layer_surface_from_surface(surface)) &&
+ layer->current.keyboard_interactive) {
+ seat_set_focus_layer(seat, layer);
+ transaction_commit_dirty();
+ return;
+ }
+
struct sway_output *hovered_output = wlr_output->data;
if (focus && hovered_output != node_get_output(focus)) {
struct sway_workspace *ws = output_get_active_workspace(hovered_output);
@@ -653,6 +665,36 @@ static void handle_tablet_tool_motion(struct sway_seat *seat,
e->previous_node = node;
}
+static void handle_touch_down(struct sway_seat *seat,
+ struct wlr_touch_down_event *event, double lx, double ly) {
+ struct wlr_surface *surface = NULL;
+ struct wlr_seat *wlr_seat = seat->wlr_seat;
+ struct sway_cursor *cursor = seat->cursor;
+ double sx, sy;
+ node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy);
+
+ if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) {
+ if (seat_is_input_allowed(seat, surface)) {
+ cursor->simulating_pointer_from_touch = false;
+ seatop_begin_touch_down(seat, surface, event, sx, sy, lx, ly);
+ }
+ } 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 = seat->touch_x - cursor->cursor->x;
+ dy = seat->touch_y - 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);
+ }
+}
+
/*----------------------------------------\
* Functions used by handle_pointer_axis /
*--------------------------------------*/
@@ -726,7 +768,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
seat_get_active_tiling_child(seat, tabcontainer);
list_t *siblings = container_get_siblings(cont);
int desired = list_find(siblings, active->sway_container) +
- round(scroll_factor * event->delta_discrete / WLR_POINTER_AXIS_DISCRETE_STEP);
+ roundf(scroll_factor * event->delta_discrete / WLR_POINTER_AXIS_DISCRETE_STEP);
if (desired < 0) {
desired = 0;
} else if (desired >= siblings->length) {
@@ -761,7 +803,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
if (!handled) {
wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
event->orientation, scroll_factor * event->delta,
- round(scroll_factor * event->delta_discrete), event->source);
+ roundf(scroll_factor * event->delta_discrete), event->source);
}
}
@@ -907,7 +949,7 @@ static void handle_hold_begin(struct sway_seat *seat,
// ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_hold_begin(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
+ server.input->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers);
}
}
@@ -919,7 +961,7 @@ static void handle_hold_end(struct sway_seat *seat,
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) {
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_hold_end(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
+ server.input->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->cancelled);
return;
}
@@ -952,7 +994,7 @@ static void handle_pinch_begin(struct sway_seat *seat,
// ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_pinch_begin(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
+ server.input->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers);
}
}
@@ -968,7 +1010,7 @@ static void handle_pinch_update(struct sway_seat *seat,
// ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_pinch_update(
- cursor->pointer_gestures,
+ server.input->pointer_gestures,
cursor->seat->wlr_seat,
event->time_msec, event->dx, event->dy,
event->scale, event->rotation);
@@ -982,7 +1024,7 @@ static void handle_pinch_end(struct sway_seat *seat,
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_pinch_end(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
+ server.input->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->cancelled);
return;
}
@@ -1015,7 +1057,7 @@ static void handle_swipe_begin(struct sway_seat *seat,
// ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_swipe_begin(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
+ server.input->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers);
}
}
@@ -1032,7 +1074,7 @@ static void handle_swipe_update(struct sway_seat *seat,
// ... otherwise forward to client
struct sway_cursor *cursor = seat->cursor;
wlr_pointer_gestures_v1_send_swipe_update(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
+ server.input->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->dx, event->dy);
}
}
@@ -1043,7 +1085,7 @@ static void handle_swipe_end(struct sway_seat *seat,
struct seatop_default_event *seatop = seat->seatop_data;
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
struct sway_cursor *cursor = seat->cursor;
- wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures,
+ wlr_pointer_gestures_v1_send_swipe_end(server.input->pointer_gestures,
cursor->seat->wlr_seat, event->time_msec, event->cancelled);
return;
}
@@ -1100,6 +1142,7 @@ static const struct sway_seatop_impl seatop_impl = {
.swipe_begin = handle_swipe_begin,
.swipe_update = handle_swipe_update,
.swipe_end = handle_swipe_end,
+ .touch_down = handle_touch_down,
.rebase = handle_rebase,
.allow_set_cursor = true,
};
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c
index b40773d0..36f9bb60 100644
--- a/sway/input/seatop_down.c
+++ b/sway/input/seatop_down.c
@@ -2,12 +2,20 @@
#include <float.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_tablet_v2.h>
+#include <wlr/types/wlr_touch.h>
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/tree/view.h"
#include "sway/desktop/transaction.h"
#include "log.h"
+struct seatop_touch_point_event {
+ double ref_lx, ref_ly; // touch's x/y at start of op
+ double ref_con_lx, ref_con_ly; // container's x/y at start of op
+ int32_t touch_id;
+ struct wl_list link;
+};
+
struct seatop_down_event {
struct sway_container *con;
struct sway_seat *seat;
@@ -15,8 +23,109 @@ struct seatop_down_event {
struct wlr_surface *surface;
double ref_lx, ref_ly; // cursor's x/y at start of op
double ref_con_lx, ref_con_ly; // container's x/y at start of op
+ struct wl_list point_events; // seatop_touch_point_event::link
};
+static void handle_touch_motion(struct sway_seat *seat,
+ struct wlr_touch_motion_event *event, double lx, double ly) {
+ struct seatop_down_event *e = seat->seatop_data;
+
+ struct seatop_touch_point_event *point_event;
+ bool found = false;
+ wl_list_for_each(point_event, &e->point_events, link) {
+ if (point_event->touch_id == event->touch_id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return; // Probably not a point_event from this seatop_down
+ }
+
+ double moved_x = lx - point_event->ref_lx;
+ double moved_y = ly - point_event->ref_ly;
+ double sx = point_event->ref_con_lx + moved_x;
+ double sy = point_event->ref_con_ly + moved_y;
+
+ wlr_seat_touch_notify_motion(seat->wlr_seat, event->time_msec,
+ event->touch_id, sx, sy);
+}
+
+static void handle_touch_up(struct sway_seat *seat,
+ struct wlr_touch_up_event *event) {
+ struct seatop_down_event *e = seat->seatop_data;
+ struct seatop_touch_point_event *point_event, *tmp;
+
+ wl_list_for_each_safe(point_event, tmp, &e->point_events, link) {
+ if (point_event->touch_id == event->touch_id) {
+ wl_list_remove(&point_event->link);
+ free(point_event);
+ break;
+ }
+ }
+
+ wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec, event->touch_id);
+
+ if (wl_list_empty(&e->point_events)) {
+ seatop_begin_default(seat);
+ }
+}
+
+static void handle_touch_down(struct sway_seat *seat,
+ struct wlr_touch_down_event *event, double lx, double ly) {
+ struct seatop_down_event *e = seat->seatop_data;
+ double sx, sy;
+ struct wlr_surface *surface = NULL;
+ struct sway_node *focused_node = node_at_coords(seat, seat->touch_x,
+ seat->touch_y, &surface, &sx, &sy);
+
+ if (!surface || surface != e->surface) { // Must start from the initial surface
+ return;
+ }
+
+ struct seatop_touch_point_event *point_event =
+ calloc(1, sizeof(struct seatop_touch_point_event));
+ if (!sway_assert(point_event, "Unable to allocate point_event")) {
+ return;
+ }
+ point_event->touch_id = event->touch_id;
+ point_event->ref_lx = lx;
+ point_event->ref_ly = ly;
+ point_event->ref_con_lx = sx;
+ point_event->ref_con_ly = sy;
+
+ wl_list_insert(&e->point_events, &point_event->link);
+
+ wlr_seat_touch_notify_down(seat->wlr_seat, surface, event->time_msec,
+ event->touch_id, sx, sy);
+
+ if (focused_node) {
+ seat_set_focus(seat, focused_node);
+ }
+}
+
+static void handle_touch_cancel(struct sway_seat *seat,
+ struct wlr_touch_cancel_event *event) {
+ struct seatop_down_event *e = seat->seatop_data;
+ struct seatop_touch_point_event *point_event, *tmp;
+
+ wl_list_for_each_safe(point_event, tmp, &e->point_events, link) {
+ if (point_event->touch_id == event->touch_id) {
+ wl_list_remove(&point_event->link);
+ free(point_event);
+ break;
+ }
+ }
+
+ if (e->surface) {
+ wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface);
+ }
+
+ if (wl_list_empty(&e->point_events)) {
+ seatop_begin_default(seat);
+ }
+}
+
static void handle_pointer_axis(struct sway_seat *seat,
struct wlr_pointer_axis_event *event) {
struct sway_input_device *input_device =
@@ -28,7 +137,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
wlr_seat_pointer_notify_axis(seat->wlr_seat, event->time_msec,
event->orientation, scroll_factor * event->delta,
- round(scroll_factor * event->delta_discrete), event->source);
+ roundf(scroll_factor * event->delta_discrete), event->source);
}
static void handle_button(struct sway_seat *seat, uint32_t time_msec,
@@ -99,14 +208,18 @@ static const struct sway_seatop_impl seatop_impl = {
.pointer_axis = handle_pointer_axis,
.tablet_tool_tip = handle_tablet_tool_tip,
.tablet_tool_motion = handle_tablet_tool_motion,
+ .touch_motion = handle_touch_motion,
+ .touch_up = handle_touch_up,
+ .touch_down = handle_touch_down,
+ .touch_cancel = handle_touch_cancel,
.unref = handle_unref,
.end = handle_end,
.allow_set_cursor = true,
};
void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
- uint32_t time_msec, double sx, double sy) {
- seatop_begin_down_on_surface(seat, con->view->surface, time_msec, sx, sy);
+ double sx, double sy) {
+ seatop_begin_down_on_surface(seat, con->view->surface, sx, sy);
struct seatop_down_event *e = seat->seatop_data;
e->con = con;
@@ -114,13 +227,20 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
transaction_commit_dirty();
}
+void seatop_begin_touch_down(struct sway_seat *seat,
+ struct wlr_surface *surface, struct wlr_touch_down_event *event,
+ double sx, double sy, double lx, double ly) {
+ seatop_begin_down_on_surface(seat, surface, sx, sy);
+ handle_touch_down(seat, event, lx, ly);
+}
+
void seatop_begin_down_on_surface(struct sway_seat *seat,
- struct wlr_surface *surface, uint32_t time_msec, double sx, double sy) {
+ struct wlr_surface *surface, double sx, double sy) {
seatop_end(seat);
struct seatop_down_event *e =
calloc(1, sizeof(struct seatop_down_event));
- if (!e) {
+ if (!sway_assert(e, "Unable to allocate e")) {
return;
}
e->con = NULL;
@@ -132,6 +252,7 @@ void seatop_begin_down_on_surface(struct sway_seat *seat,
e->ref_ly = seat->cursor->cursor->y;
e->ref_con_lx = sx;
e->ref_con_ly = sy;
+ wl_list_init(&e->point_events);
seat->seatop_impl = &seatop_impl;
seat->seatop_data = e;
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c
index 4e4db18c..bbed01a8 100644
--- a/sway/input/seatop_move_tiling.c
+++ b/sway/input/seatop_move_tiling.c
@@ -31,20 +31,19 @@ struct seatop_move_tiling_event {
bool insert_after_target;
};
-static void handle_render(struct sway_seat *seat,
- struct sway_output *output, pixman_region32_t *damage) {
+static void handle_render(struct sway_seat *seat, struct fx_render_context *ctx) {
struct seatop_move_tiling_event *e = seat->seatop_data;
if (!e->threshold_reached) {
return;
}
- if (e->target_node && node_get_output(e->target_node) == output) {
+ if (e->target_node && node_get_output(e->target_node) == ctx->output) {
float color[4];
memcpy(&color, config->border_colors.focused.indicator,
sizeof(float) * 4);
premultiply_alpha(color, 0.5);
struct wlr_box box;
memcpy(&box, &e->drop_box, sizeof(struct wlr_box));
- scale_box(&box, output->wlr_output->scale);
+ scale_box(&box, ctx->output->wlr_output->scale);
// Render blur
pixman_region32_t opaque_region;
@@ -52,11 +51,11 @@ static void handle_render(struct sway_seat *seat,
struct decoration_data deco_data = get_undecorated_decoration_data();
deco_data.blur = e->con->blur_enabled;
deco_data.corner_radius = e->con->corner_radius;
- render_blur(false, output, damage, &box, &opaque_region, &deco_data, NULL);
+ struct wlr_fbox src_box = {0};
+ render_blur(ctx, NULL, &src_box, &box, false, &opaque_region, deco_data);
pixman_region32_fini(&opaque_region);
- render_rounded_rect(output, damage, &box, color,
- e->con->corner_radius * output->wlr_output->scale, ALL);
+ render_rounded_rect(ctx, &box, color, e->con->corner_radius * ctx->output->wlr_output->scale, ALL);
}
}
diff --git a/sway/input/switch.c b/sway/input/switch.c
index fc7dfaff..7a539801 100644
--- a/sway/input/switch.c
+++ b/sway/input/switch.c
@@ -1,6 +1,5 @@
#include "sway/config.h"
#include "sway/input/switch.h"
-#include <wlr/types/wlr_idle.h>
#include "log.h"
struct sway_switch *sway_switch_create(struct sway_seat *seat,
diff --git a/sway/input/tablet.c b/sway/input/tablet.c
index 884eba74..902cb7ed 100644
--- a/sway/input/tablet.c
+++ b/sway/input/tablet.c
@@ -1,6 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
-#include <wlr/backend/libinput.h>
+#include <wlr/config.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_tablet_pad.h>
@@ -9,6 +9,10 @@
#include "sway/input/seat.h"
#include "sway/input/tablet.h"
+#if WLR_HAS_LIBINPUT_BACKEND
+#include <wlr/backend/libinput.h>
+#endif
+
static void handle_pad_tablet_destroy(struct wl_listener *listener, void *data) {
struct sway_tablet_pad *pad =
wl_container_of(listener, pad, tablet_destroy);
@@ -54,15 +58,14 @@ void sway_configure_tablet(struct sway_tablet *tablet) {
tablet->seat_device->input_device->wlr_device;
struct sway_seat *seat = tablet->seat_device->sway_seat;
- if ((seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
- seat_configure_xcursor(seat);
- }
+ seat_configure_xcursor(seat);
if (!tablet->tablet_v2) {
tablet->tablet_v2 =
wlr_tablet_create(server.tablet_v2, seat->wlr_seat, device);
}
+#if WLR_HAS_LIBINPUT_BACKEND
/* Search for a sibling tablet pad */
if (!wlr_input_device_is_libinput(device)) {
/* We can only do this on libinput devices */
@@ -87,6 +90,7 @@ void sway_configure_tablet(struct sway_tablet *tablet) {
break;
}
}
+#endif
}
void sway_tablet_destroy(struct sway_tablet *tablet) {
@@ -287,6 +291,7 @@ void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) {
tablet_pad->ring.notify = handle_tablet_pad_ring;
wl_signal_add(&tablet_pad->wlr->events.ring, &tablet_pad->ring);
+#if WLR_HAS_LIBINPUT_BACKEND
/* Search for a sibling tablet */
if (!wlr_input_device_is_libinput(wlr_device)) {
/* We can only do this on libinput devices */
@@ -311,6 +316,7 @@ void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) {
break;
}
}
+#endif
}
void sway_tablet_pad_destroy(struct sway_tablet_pad *tablet_pad) {