diff options
Diffstat (limited to 'sway/input')
-rw-r--r-- | sway/input/cursor.c | 181 | ||||
-rw-r--r-- | sway/input/input-manager.c | 293 | ||||
-rw-r--r-- | sway/input/input.c | 77 | ||||
-rw-r--r-- | sway/input/keyboard.c | 123 | ||||
-rw-r--r-- | sway/input/seat.c | 253 |
5 files changed, 850 insertions, 77 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c new file mode 100644 index 00000000..3b5cfce5 --- /dev/null +++ b/sway/input/cursor.c @@ -0,0 +1,181 @@ +#define _XOPEN_SOURCE 700 +#ifdef __linux__ +#include <linux/input-event-codes.h> +#elif __FreeBSD__ +#include <dev/evdev/input-event-codes.h> +#endif +#include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_xcursor_manager.h> +#include "sway/input/cursor.h" +#include "sway/view.h" +#include "list.h" +#include "log.h" + +static void cursor_update_position(struct sway_cursor *cursor) { + double x = cursor->cursor->x; + double y = cursor->cursor->y; + + cursor->x = x; + cursor->y = y; +} + +static void cursor_send_pointer_motion(struct sway_cursor *cursor, + uint32_t time) { + struct wlr_seat *seat = cursor->seat->wlr_seat; + struct wlr_surface *surface = NULL; + double sx, sy; + swayc_t *swayc = + swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy); + if (swayc) { + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } else { + wlr_seat_pointer_clear_focus(seat); + } +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, motion); + struct wlr_event_pointer_motion *event = data; + wlr_cursor_move(cursor->cursor, event->device, + event->delta_x, event->delta_y); + cursor_update_position(cursor); + cursor_send_pointer_motion(cursor, event->time_msec); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); + cursor_update_position(cursor); + cursor_send_pointer_motion(cursor, event->time_msec); +} + +static void handle_cursor_button(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, button); + struct wlr_event_pointer_button *event = data; + + if (event->button == BTN_LEFT) { + struct wlr_surface *surface = NULL; + double sx, sy; + swayc_t *swayc = + swayc_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy); + + sway_seat_set_focus(cursor->seat, swayc); + } + + wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, + event->button, event->state); +} + +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, axis); + struct wlr_event_pointer_axis *event = data; + wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, + event->orientation, event->delta); +} + +static void handle_touch_down(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, touch_down); + struct wlr_event_touch_down *event = data; + sway_log(L_DEBUG, "TODO: handle touch down event: %p", event); +} + +static void handle_touch_up(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, touch_up); + struct wlr_event_touch_up *event = data; + sway_log(L_DEBUG, "TODO: handle touch up event: %p", event); +} + +static void handle_touch_motion(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, touch_motion); + struct wlr_event_touch_motion *event = data; + sway_log(L_DEBUG, "TODO: handle touch motion event: %p", event); +} + +static void handle_tool_axis(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, tool_axis); + struct wlr_event_tablet_tool_axis *event = data; + sway_log(L_DEBUG, "TODO: handle tool axis event: %p", event); +} + +static void handle_tool_tip(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, tool_tip); + struct wlr_event_tablet_tool_tip *event = data; + sway_log(L_DEBUG, "TODO: handle tool tip event: %p", event); +} + +static void handle_request_set_cursor(struct wl_listener *listener, + void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, request_set_cursor); + struct wlr_seat_pointer_request_set_cursor_event *event = data; + sway_log(L_DEBUG, "TODO: handle request set cursor event: %p", event); +} + +struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { + struct sway_cursor *cursor = calloc(1, sizeof(struct sway_cursor)); + if (!sway_assert(cursor, "could not allocate sway cursor")) { + return NULL; + } + + struct wlr_cursor *wlr_cursor = wlr_cursor_create(); + if (!sway_assert(wlr_cursor, "could not allocate wlr cursor")) { + free(cursor); + return NULL; + } + + cursor->seat = seat; + wlr_cursor_attach_output_layout(wlr_cursor, + root_container.sway_root->output_layout); + + // input events + wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); + cursor->motion.notify = handle_cursor_motion; + + wl_signal_add(&wlr_cursor->events.motion_absolute, + &cursor->motion_absolute); + cursor->motion_absolute.notify = handle_cursor_motion_absolute; + + wl_signal_add(&wlr_cursor->events.button, &cursor->button); + cursor->button.notify = handle_cursor_button; + + wl_signal_add(&wlr_cursor->events.axis, &cursor->axis); + cursor->axis.notify = handle_cursor_axis; + + wl_signal_add(&wlr_cursor->events.touch_down, &cursor->touch_down); + cursor->touch_down.notify = handle_touch_down; + + 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_motion, + &cursor->touch_motion); + cursor->touch_motion.notify = handle_touch_motion; + + wl_signal_add(&wlr_cursor->events.tablet_tool_axis, + &cursor->tool_axis); + cursor->tool_axis.notify = handle_tool_axis; + + wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip); + cursor->tool_tip.notify = handle_tool_tip; + + wl_signal_add(&seat->wlr_seat->events.request_set_cursor, + &cursor->request_set_cursor); + cursor->request_set_cursor.notify = handle_request_set_cursor; + + cursor->cursor = wlr_cursor; + + return cursor; +} diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c new file mode 100644 index 00000000..4459c43b --- /dev/null +++ b/sway/input/input-manager.c @@ -0,0 +1,293 @@ +#define _XOPEN_SOURCE 700 +#include <ctype.h> +#include <float.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <libinput.h> +#include <math.h> +#include "sway/config.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/server.h" +#include "stringop.h" +#include "list.h" +#include "log.h" + +static const char *default_seat = "seat0"; + +// TODO make me not global +struct sway_input_manager *input_manager; + +struct input_config *current_input_config = NULL; +struct seat_config *current_seat_config = NULL; + +static struct sway_seat *input_manager_get_seat( + struct sway_input_manager *input, const char *seat_name) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (strcmp(seat->wlr_seat->name, seat_name) == 0) { + return seat; + } + } + + return sway_seat_create(input, seat_name); +} + +static char *get_device_identifier(struct wlr_input_device *device) { + int vendor = device->vendor; + int product = device->product; + char *name = strdup(device->name); + name = strip_whitespace(name); + + char *p = name; + for (; *p; ++p) { + if (*p == ' ') { + *p = '_'; + } + } + + const char *fmt = "%d:%d:%s"; + int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1; + char *identifier = malloc(len); + if (!identifier) { + sway_log(L_ERROR, "Unable to allocate unique input device name"); + return NULL; + } + + snprintf(identifier, len, fmt, vendor, product, name); + free(name); + return identifier; +} + +static struct sway_input_device *input_sway_device_from_wlr( + struct sway_input_manager *input, struct wlr_input_device *device) { + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + if (input_device->wlr_device == device) { + return input_device; + } + } + return NULL; +} + +static bool input_has_seat_configuration(struct sway_input_manager *input) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (seat->config) { + return true; + } + } + + return false; +} + +static void input_add_notify(struct wl_listener *listener, void *data) { + struct sway_input_manager *input = + wl_container_of(listener, input, input_add); + struct wlr_input_device *device = data; + + struct sway_input_device *input_device = + calloc(1, sizeof(struct sway_input_device)); + if (!sway_assert(input_device, "could not allocate input device")) { + return; + } + + input_device->wlr_device = device; + input_device->identifier = get_device_identifier(device); + wl_list_insert(&input->devices, &input_device->link); + + sway_log(L_DEBUG, "adding device: '%s'", + input_device->identifier); + + // find config + for (int i = 0; i < config->input_configs->length; ++i) { + struct input_config *input_config = config->input_configs->items[i]; + if (strcmp(input_config->identifier, input_device->identifier) == 0) { + input_device->config = input_config; + break; + } + } + + struct sway_seat *seat = NULL; + if (!input_has_seat_configuration(input)) { + sway_log(L_DEBUG, "no seat configuration, using default seat"); + seat = input_manager_get_seat(input, default_seat); + sway_seat_add_device(seat, input_device); + return; + } + + bool added = false; + wl_list_for_each(seat, &input->seats, link) { + bool has_attachment = seat->config && + (seat_config_get_attachment(seat->config, input_device->identifier) || + seat_config_get_attachment(seat->config, "*")); + + if (has_attachment) { + sway_seat_add_device(seat, input_device); + added = true; + } + } + + if (!added) { + wl_list_for_each(seat, &input->seats, link) { + if (seat->config && seat->config->fallback == 1) { + sway_seat_add_device(seat, input_device); + added = true; + } + } + } + + if (!added) { + sway_log(L_DEBUG, + "device '%s' is not configured on any seats", + input_device->identifier); + } +} + +static void input_remove_notify(struct wl_listener *listener, void *data) { + struct sway_input_manager *input = + wl_container_of(listener, input, input_remove); + struct wlr_input_device *device = data; + + struct sway_input_device *input_device = + input_sway_device_from_wlr(input, device); + + if (!sway_assert(input_device, "could not find sway device")) { + return; + } + + sway_log(L_DEBUG, "removing device: '%s'", + input_device->identifier); + + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + sway_seat_remove_device(seat, input_device); + } + + wl_list_remove(&input_device->link); + free(input_device->identifier); + free(input_device); +} + +struct sway_input_manager *sway_input_manager_create( + struct sway_server *server) { + struct sway_input_manager *input = + calloc(1, sizeof(struct sway_input_manager)); + if (!input) { + return NULL; + } + input->server = server; + + wl_list_init(&input->devices); + wl_list_init(&input->seats); + + // create the default seat + input_manager_get_seat(input, default_seat); + + input->input_add.notify = input_add_notify; + wl_signal_add(&server->backend->events.input_add, &input->input_add); + + input->input_remove.notify = input_remove_notify; + wl_signal_add(&server->backend->events.input_remove, &input->input_remove); + + return input; +} + +bool sway_input_manager_has_focus(struct sway_input_manager *input, + swayc_t *container) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (seat->focus == container) { + return true; + } + } + + return false; +} + +void sway_input_manager_set_focus(struct sway_input_manager *input, + swayc_t *container) { + struct sway_seat *seat ; + wl_list_for_each(seat, &input->seats, link) { + sway_seat_set_focus(seat, container); + } +} + +void sway_input_manager_apply_input_config(struct sway_input_manager *input, + struct input_config *input_config) { + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + if (strcmp(input_device->identifier, input_config->identifier) == 0) { + input_device->config = input_config; + + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + sway_seat_configure_device(seat, input_device); + } + } + } +} + +void sway_input_manager_apply_seat_config(struct sway_input_manager *input, + struct seat_config *seat_config) { + sway_log(L_DEBUG, "applying new seat config for seat %s", + seat_config->name); + struct sway_seat *seat = input_manager_get_seat(input, seat_config->name); + if (!seat) { + return; + } + + sway_seat_set_config(seat, seat_config); + + // for every device, try to add it to a seat and if no seat has it + // attached, add it to the fallback seats. + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + list_t *seat_list = create_list(); + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (!seat->config) { + continue; + } + if (seat_config_get_attachment(seat->config, "*") || + seat_config_get_attachment(seat->config, + input_device->identifier)) { + list_add(seat_list, seat); + } + } + + if (seat_list->length) { + wl_list_for_each(seat, &input->seats, link) { + bool attached = false; + for (int i = 0; i < seat_list->length; ++i) { + if (seat == seat_list->items[i]) { + attached = true; + break; + } + } + if (attached) { + sway_seat_add_device(seat, input_device); + } else { + sway_seat_remove_device(seat, input_device); + } + } + } else { + wl_list_for_each(seat, &input->seats, link) { + if (seat->config && seat->config->fallback == 1) { + sway_seat_add_device(seat, input_device); + } else { + sway_seat_remove_device(seat, input_device); + } + } + } + list_free(seat_list); + } +} + +void sway_input_manager_configure_xcursor(struct sway_input_manager *input) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + sway_seat_configure_xcursor(seat); + } +} diff --git a/sway/input/input.c b/sway/input/input.c deleted file mode 100644 index 02b4995e..00000000 --- a/sway/input/input.c +++ /dev/null @@ -1,77 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include <ctype.h> -#include <float.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <libinput.h> -#include "sway/config.h" -#include "sway/input.h" -#include "sway/server.h" -#include "list.h" -#include "log.h" - -struct input_config *current_input_config = NULL; - -struct sway_input *sway_input_create(struct sway_server *server) { - struct sway_input *input = calloc(1, sizeof(struct sway_input)); - if (!input) { - return NULL; - } - return input; -} - -struct input_config *new_input_config(const char* identifier) { - struct input_config *input = calloc(1, sizeof(struct input_config)); - if (!input) { - sway_log(L_DEBUG, "Unable to allocate input config"); - return NULL; - } - sway_log(L_DEBUG, "new_input_config(%s)", identifier); - if (!(input->identifier = strdup(identifier))) { - free(input); - sway_log(L_DEBUG, "Unable to allocate input config"); - return NULL; - } - - input->tap = INT_MIN; - input->drag_lock = INT_MIN; - input->dwt = INT_MIN; - input->send_events = INT_MIN; - input->click_method = INT_MIN; - input->middle_emulation = INT_MIN; - input->natural_scroll = INT_MIN; - input->accel_profile = INT_MIN; - input->pointer_accel = FLT_MIN; - input->scroll_method = INT_MIN; - input->left_handed = INT_MIN; - - return input; -} - -char *libinput_dev_unique_id(struct libinput_device *device) { - int vendor = libinput_device_get_id_vendor(device); - int product = libinput_device_get_id_product(device); - char *name = strdup(libinput_device_get_name(device)); - - char *p = name; - for (; *p; ++p) { - if (*p == ' ') { - *p = '_'; - } - } - - sway_log(L_DEBUG, "rewritten name %s", name); - - int len = strlen(name) + sizeof(char) * 6; - char *identifier = malloc(len); - if (!identifier) { - sway_log(L_ERROR, "Unable to allocate unique input device name"); - return NULL; - } - - const char *fmt = "%d:%d:%s"; - snprintf(identifier, len, fmt, vendor, product, name); - free(name); - return identifier; -} diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c new file mode 100644 index 00000000..724941d8 --- /dev/null +++ b/sway/input/keyboard.c @@ -0,0 +1,123 @@ +#include "sway/input/seat.h" +#include "sway/input/keyboard.h" +#include "sway/input/input-manager.h" +#include "log.h" + +static void handle_keyboard_key(struct wl_listener *listener, void *data) { + struct sway_keyboard *keyboard = + wl_container_of(listener, keyboard, keyboard_key); + struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + struct wlr_input_device *wlr_device = + keyboard->seat_device->input_device->wlr_device; + struct wlr_event_keyboard_key *event = data; + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, + event->keycode, event->state); +} + +static void handle_keyboard_modifiers(struct wl_listener *listener, + void *data) { + struct sway_keyboard *keyboard = + wl_container_of(listener, keyboard, keyboard_modifiers); + struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + struct wlr_input_device *wlr_device = + keyboard->seat_device->input_device->wlr_device; + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_modifiers(wlr_seat); +} + +struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, + struct sway_seat_device *device) { + struct sway_keyboard *keyboard = + calloc(1, sizeof(struct sway_keyboard)); + if (!sway_assert(keyboard, "could not allocate sway keyboard")) { + return NULL; + } + + keyboard->seat_device = device; + device->keyboard = keyboard; + + wl_list_init(&keyboard->keyboard_key.link); + wl_list_init(&keyboard->keyboard_modifiers.link); + + return keyboard; +} + +void sway_keyboard_configure(struct sway_keyboard *keyboard) { + struct xkb_rule_names rules; + memset(&rules, 0, sizeof(rules)); + struct input_config *input_config = + keyboard->seat_device->input_device->config; + struct wlr_input_device *wlr_device = + keyboard->seat_device->input_device->wlr_device; + + if (input_config && input_config->xkb_layout) { + rules.layout = input_config->xkb_layout; + } else { + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + } + if (input_config && input_config->xkb_model) { + rules.model = input_config->xkb_model; + } else { + rules.model = getenv("XKB_DEFAULT_MODEL"); + } + + if (input_config && input_config->xkb_options) { + rules.options = input_config->xkb_options; + } else { + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + } + + if (input_config && input_config->xkb_rules) { + rules.rules = input_config->xkb_rules; + } else { + rules.rules = getenv("XKB_DEFAULT_RULES"); + } + + if (input_config && input_config->xkb_variant) { + rules.variant = input_config->xkb_variant; + } else { + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + } + + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!sway_assert(context, "cannot create XKB context")) { + return; + } + + struct xkb_keymap *keymap = + xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!keymap) { + sway_log(L_DEBUG, "cannot configure keyboard: keymap does not exist"); + xkb_context_unref(context); + return; + } + + xkb_keymap_unref(keyboard->keymap); + keyboard->keymap = keymap; + wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap); + + wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600); + xkb_context_unref(context); + struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat; + wlr_seat_set_keyboard(seat, wlr_device); + + wl_list_remove(&keyboard->keyboard_key.link); + wl_signal_add(&wlr_device->keyboard->events.key, &keyboard->keyboard_key); + keyboard->keyboard_key.notify = handle_keyboard_key; + + wl_list_remove(&keyboard->keyboard_modifiers.link); + wl_signal_add( &wlr_device->keyboard->events.modifiers, + &keyboard->keyboard_modifiers); + keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; +} + +void sway_keyboard_destroy(struct sway_keyboard *keyboard) { + if (!keyboard) { + return; + } + wl_list_remove(&keyboard->keyboard_key.link); + wl_list_remove(&keyboard->keyboard_modifiers.link); + free(keyboard); +} diff --git a/sway/input/seat.c b/sway/input/seat.c new file mode 100644 index 00000000..fe90565a --- /dev/null +++ b/sway/input/seat.c @@ -0,0 +1,253 @@ +#define _XOPEN_SOURCE 700 +#include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_xcursor_manager.h> +#include "sway/input/seat.h" +#include "sway/input/cursor.h" +#include "sway/input/input-manager.h" +#include "sway/input/keyboard.h" +#include "sway/output.h" +#include "sway/view.h" +#include "log.h" + +static void seat_device_destroy(struct sway_seat_device *seat_device) { + if (!seat_device) { + return; + } + + sway_keyboard_destroy(seat_device->keyboard); + wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor, + seat_device->input_device->wlr_device); + wl_list_remove(&seat_device->link); + free(seat_device); +} + +struct sway_seat *sway_seat_create(struct sway_input_manager *input, + const char *seat_name) { + struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); + if (!seat) { + return NULL; + } + + seat->wlr_seat = wlr_seat_create(input->server->wl_display, seat_name); + if (!sway_assert(seat->wlr_seat, "could not allocate seat")) { + free(seat); + return NULL; + } + + seat->cursor = sway_cursor_create(seat); + if (!seat->cursor) { + wlr_seat_destroy(seat->wlr_seat); + free(seat); + return NULL; + } + + seat->input = input; + wl_list_init(&seat->devices); + + wlr_seat_set_capabilities(seat->wlr_seat, + WL_SEAT_CAPABILITY_KEYBOARD | + WL_SEAT_CAPABILITY_POINTER | + WL_SEAT_CAPABILITY_TOUCH); + + sway_seat_configure_xcursor(seat); + + wl_list_insert(&input->seats, &seat->link); + + return seat; +} + +static void seat_configure_pointer(struct sway_seat *seat, + struct sway_seat_device *sway_device) { + // TODO pointer configuration + wlr_cursor_attach_input_device(seat->cursor->cursor, + sway_device->input_device->wlr_device); +} + +static void seat_configure_keyboard(struct sway_seat *seat, + struct sway_seat_device *seat_device) { + if (!seat_device->keyboard) { + sway_keyboard_create(seat, seat_device); + } + sway_keyboard_configure(seat_device->keyboard); + wlr_seat_set_keyboard(seat->wlr_seat, + seat_device->input_device->wlr_device); + if (seat->focus) { + // force notify reenter to pick up the new configuration + wlr_seat_keyboard_clear_focus(seat->wlr_seat); + wlr_seat_keyboard_notify_enter(seat->wlr_seat, seat->focus->sway_view->surface); + } +} + +static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + struct sway_seat_device *seat_device = NULL; + wl_list_for_each(seat_device, &seat->devices, link) { + if (seat_device->input_device == input_device) { + return seat_device; + } + } + + return NULL; +} + +void sway_seat_configure_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + struct sway_seat_device *seat_device = + sway_seat_get_device(seat, input_device); + if (!seat_device) { + return; + } + + if (seat->config) { + seat_device->attachment_config = + seat_config_get_attachment(seat->config, input_device->identifier); + } + + switch (input_device->wlr_device->type) { + case WLR_INPUT_DEVICE_POINTER: + seat_configure_pointer(seat, seat_device); + break; + case WLR_INPUT_DEVICE_KEYBOARD: + seat_configure_keyboard(seat, seat_device); + break; + case WLR_INPUT_DEVICE_TOUCH: + case WLR_INPUT_DEVICE_TABLET_PAD: + case WLR_INPUT_DEVICE_TABLET_TOOL: + sway_log(L_DEBUG, "TODO: configure other devices"); + break; + } +} + +void sway_seat_add_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + if (sway_seat_get_device(seat, input_device)) { + sway_seat_configure_device(seat, input_device); + return; + } + + struct sway_seat_device *seat_device = + calloc(1, sizeof(struct sway_seat_device)); + if (!seat_device) { + sway_log(L_DEBUG, "could not allocate seat device"); + return; + } + + sway_log(L_DEBUG, "adding device %s to seat %s", + input_device->identifier, seat->wlr_seat->name); + + seat_device->sway_seat = seat; + seat_device->input_device = input_device; + wl_list_insert(&seat->devices, &seat_device->link); + + sway_seat_configure_device(seat, input_device); +} + +void sway_seat_remove_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + struct sway_seat_device *seat_device = + sway_seat_get_device(seat, input_device); + + if (!seat_device) { + return; + } + + sway_log(L_DEBUG, "removing device %s from seat %s", + input_device->identifier, seat->wlr_seat->name); + + seat_device_destroy(seat_device); +} + +void sway_seat_configure_xcursor(struct sway_seat *seat) { + // TODO configure theme and size + const char *cursor_theme = "default"; + + if (!seat->cursor->xcursor_manager) { + seat->cursor->xcursor_manager = + wlr_xcursor_manager_create("default", 24); + if (sway_assert(seat->cursor->xcursor_manager, + "Cannot create XCursor manager for theme %s", + cursor_theme)) { + return; + } + } + + for (int i = 0; i < root_container.children->length; ++i) { + swayc_t *output_container = root_container.children->items[i]; + struct wlr_output *output = + output_container->sway_output->wlr_output; + bool result = + wlr_xcursor_manager_load(seat->cursor->xcursor_manager, + output->scale); + + sway_assert(!result, + "Cannot load xcursor theme for output '%s' with scale %f", + // TODO: Fractional scaling + output->name, (double)output->scale); + } + + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + "left_ptr", seat->cursor->cursor); + wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, + seat->cursor->cursor->y); +} + +static void handle_focus_destroy(struct wl_listener *listener, void *data) { + struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy); + //swayc_t *container = data; + + // TODO set new focus based on the state of the tree + sway_seat_set_focus(seat, NULL); +} + +void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { + swayc_t *last_focus = seat->focus; + + if (last_focus == container) { + return; + } + + if (last_focus) { + wl_list_remove(&seat->focus_destroy.link); + } + + if (container) { + struct sway_view *view = container->sway_view; + view->iface.set_activated(view, true); + wl_signal_add(&container->events.destroy, &seat->focus_destroy); + seat->focus_destroy.notify = handle_focus_destroy; + wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface); + } + + seat->focus = container; + + if (last_focus && + !sway_input_manager_has_focus(seat->input, last_focus)) { + struct sway_view *view = last_focus->sway_view; + view->iface.set_activated(view, false); + + } +} + +void sway_seat_set_config(struct sway_seat *seat, + struct seat_config *seat_config) { + // clear configs + seat->config = NULL; + + struct sway_seat_device *seat_device = NULL; + wl_list_for_each(seat_device, &seat->devices, link) { + seat_device->attachment_config = NULL; + } + + if (!seat_config) { + return; + } + + // add configs + seat->config = seat_config; + + wl_list_for_each(seat_device, &seat->devices, link) { + seat_device->attachment_config = + seat_config_get_attachment(seat_config, + seat_device->input_device->identifier); + } +} |