diff options
author | Reza Jelveh <[email protected]> | 2024-04-15 13:39:41 +0800 |
---|---|---|
committer | GitHub <[email protected]> | 2024-04-15 01:39:41 -0400 |
commit | fb86ed6b0588dfdebfb66ce875bc63cfa0a897f6 (patch) | |
tree | 29857a1769107adc58696f08d379f608aa4e29a2 /sway/input | |
parent | a5e79676c4bd22fc5902182acf0667907202a465 (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.c | 185 | ||||
-rw-r--r-- | sway/input/input-manager.c | 60 | ||||
-rw-r--r-- | sway/input/keyboard.c | 50 | ||||
-rw-r--r-- | sway/input/libinput.c | 81 | ||||
-rw-r--r-- | sway/input/seat.c | 167 | ||||
-rw-r--r-- | sway/input/seatop_default.c | 135 | ||||
-rw-r--r-- | sway/input/seatop_down.c | 131 | ||||
-rw-r--r-- | sway/input/seatop_move_tiling.c | 13 | ||||
-rw-r--r-- | sway/input/switch.c | 1 | ||||
-rw-r--r-- | sway/input/tablet.c | 14 |
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) { |