aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/wm/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/wm/input.c')
-rw-r--r--src/cmd/wm/input.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/src/cmd/wm/input.c b/src/cmd/wm/input.c
new file mode 100644
index 0000000..4c6bfd4
--- /dev/null
+++ b/src/cmd/wm/input.c
@@ -0,0 +1,316 @@
+#include "wm.h"
+
+// -----------------------------------------------------------------------
+// keyboard
+
+static
+void
+keymodifier(struct wl_listener *l, void *data)
+{
+ Keyboard *keyboard = wl_container_of(l, keyboard, event.modify);
+
+ wlr_seat_set_keyboard(server.input.seat, keyboard->device);
+ wlr_seat_keyboard_notify_modifiers(server.input.seat, &keyboard->device->keyboard->modifiers);
+}
+
+static
+int
+keybinding(uint32 modifier, xkb_keysym_t sym)
+{
+ Key *key;
+
+ for(key=cfg·binding; key!=cfg·endbinding; ++key) {
+ if(modifier == key->modifier && sym == key->sym && key->action){
+ key->action(&key->arg);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static
+void
+keypress(struct wl_listener *l, void *data)
+{
+ int i,h,n;
+ uint32 keycode, modifier;
+ const xkb_keysym_t *syms;
+ struct Keyboard *keyboard = wl_container_of(l, keyboard, event.press);
+ struct wlr_event_keyboard_key *event = data;
+
+ keycode = event->keycode + 8;
+
+ h = 0;
+ n = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, keycode, &syms);
+
+ modifier = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
+ if(event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ for(i=0; i<n; i++)
+ h=keybinding(modifier, syms[i]);
+ }
+
+ if(!h) {
+ wlr_seat_set_keyboard(server.input.seat, keyboard->device);
+ wlr_seat_keyboard_notify_key(server.input.seat, event->time_msec, event->keycode, event->state);
+ }
+}
+
+static
+void
+free_keyboard(struct wl_listener *l, void *data)
+{
+ struct wlr_input_device *device = data;
+ Keyboard *keyboard = device->data;
+
+ /* XXX: debug
+ wl_list_remove(&keyboard->link);
+ wl_list_remove(&keyboard->event.modify.link);
+ wl_list_remove(&keyboard->event.press.link);
+ wl_list_remove(&keyboard->event.destroy.link);
+
+ free(keyboard);
+ */
+}
+
+static
+void
+make_keyboard(struct wlr_input_device *device)
+{
+ Keyboard *keyboard;
+ struct xkb_context *context;
+ struct xkb_keymap *keymap;
+
+ keyboard = device->data = calloc(1, sizeof(*keyboard));
+ keyboard->device = device;
+
+ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ keymap = xkb_keymap_new_from_names(context, nil, XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ wlr_keyboard_set_keymap(device->keyboard, keymap);
+
+ xkb_keymap_unref(keymap);
+ xkb_context_unref(context);
+
+ wlr_keyboard_set_repeat_info(device->keyboard, cfg·repeat_rate, cfg·repeat_delay);
+
+ keyboard->event.modify.notify = keymodifier;
+ wl_signal_add(&device->keyboard->events.modifiers, &keyboard->event.modify);
+
+ keyboard->event.press.notify = keypress;
+ wl_signal_add(&device->keyboard->events.key, &keyboard->event.press);
+
+ keyboard->event.destroy.notify = free_keyboard;
+ wl_signal_add(&device->keyboard->events.destroy, &keyboard->event.destroy);
+
+ wlr_seat_set_keyboard(server.input.seat, device);
+
+ wl_list_insert(&server.input.keyboards, &keyboard->link);
+}
+
+// -----------------------------------------------------------------------
+// cursor
+
+static
+void
+focus_surface(Client *client, struct wlr_surface *surface, double sx, double sy, uint32 time)
+{
+ struct timespec now;
+ int lift = time;
+
+ if(client && !surface)
+ surface = client->xdg->surface;
+
+ if(!surface){
+ wlr_seat_pointer_notify_clear_focus(server.input.seat);
+ return;
+ }
+
+ if(!time) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ time = now.tv_sec * 1000 + now.tv_nsec / 1000000;
+ }
+
+ if(surface == server.input.seat->pointer_state.focused_surface) {
+ wlr_seat_pointer_notify_motion(server.input.seat, time, sx, sy);
+ return;
+ }
+
+ wlr_seat_pointer_notify_enter(server.input.seat, surface, sx, sy);
+
+ if(cfg·sloppyfocus && lift)
+ focus(client, 0);
+}
+
+void
+notify_move(uint32 time)
+{
+ double sx, sy;
+ Client *client;
+ struct wlr_box box;
+ struct wlr_surface *surface;
+
+ if(time) {
+ wlr_idle_notify_activity(server.input.idle, server.input.seat);
+ if(cfg·sloppyfocus)
+ server.monitor.selected = monitor_at(server.cursor.dot->x, server.cursor.dot->y);
+ }
+
+ if(server.cursor.mode == CursorMove) {
+ resize(server.grab.client,
+ server.cursor.dot->x - server.grab.x,
+ server.cursor.dot->y - server.grab.y,
+ server.grab.client->geometry.width,
+ server.grab.client->geometry.height,
+ 1
+ );
+ return;
+ }
+
+ if(server.cursor.mode == CursorResize) {
+ wlr_xdg_surface_get_geometry(server.grab.client->xdg, &box);
+ resize(server.grab.client,
+ server.grab.box.x - box.x,
+ server.grab.box.y - box.y,
+ server.cursor.dot->x - server.grab.x - server.grab.box.x,
+ server.cursor.dot->y - server.grab.y - server.grab.box.y,
+ 1
+ );
+ return;
+ }
+
+ /* otherwise, find the client under the pointer and send the event along. */
+ client = client_at(server.cursor.dot->x, server.cursor.dot->y);
+ if(!client) {
+ wlr_xcursor_manager_set_cursor_image(server.cursor.manager, "left_ptr", server.cursor.dot);
+ return;
+ }
+
+ surface = client_surface_at(
+ client,
+ server.cursor.dot->x - client->geometry.x - client->border,
+ server.cursor.dot->y - client->geometry.y - client->border,
+ &sx, &sy
+ );
+
+ focus_surface(client, surface, sx, sy, time);
+}
+
+void
+cursor_move(struct wl_listener *l, void *data)
+{
+ struct wlr_event_pointer_motion *event = data;
+ wlr_cursor_move(server.cursor.dot, event->device, event->delta_x, event->delta_y);
+ notify_move(event->time_msec);
+}
+
+void
+cursor_move_abs(struct wl_listener *l, void *data)
+{
+ struct wlr_event_pointer_motion_absolute *event = data;
+ wlr_cursor_warp_absolute(server.cursor.dot, event->device, event->x, event->y);
+ notify_move(event->time_msec);
+}
+
+void
+cursor_button(struct wl_listener *l, void *data)
+{
+ Client *client;
+ uint32 modifier;
+ Button *button;
+ struct wlr_keyboard *keyboard;
+ struct wlr_event_pointer_button *event = data;
+
+ wlr_idle_notify_activity(server.input.idle, server.input.seat);
+
+ switch(event->state) {
+ case WLR_BUTTON_PRESSED:
+ if((client=client_at(server.cursor.dot->x, server.cursor.dot->y)))
+ focus(client,1);
+
+ keyboard = wlr_seat_get_keyboard(server.input.seat);
+ modifier = wlr_keyboard_get_modifiers(keyboard);
+ for(button=cfg·button; button != cfg·endbutton; ++button) {
+ if(modifier == button->modifier && event->button == button->code && button->function) {
+ button->function(&button->arg);
+ return;
+ }
+ }
+ break;
+ case WLR_BUTTON_RELEASED:
+ if(server.cursor.mode != CursorNormal) {
+ wlr_xcursor_manager_set_cursor_image(server.cursor.manager, "left_ptr", server.cursor.dot);
+ server.cursor.mode = CursorNormal;
+ /* Drop the window off on its new monitor */
+ server.monitor.selected = monitor_at(server.cursor.dot->x, server.cursor.dot->y);
+ attach(server.grab.client, server.monitor.selected, 0);
+ return;
+ }
+ }
+
+ wlr_seat_pointer_notify_button(server.input.seat, event->time_msec, event->button, event->state);
+}
+
+void
+cursor_axis(struct wl_listener *l, void *data)
+{
+ struct wlr_event_pointer_axis *event = data;
+ /* Notify the client with pointer focus of the axis event. */
+ wlr_seat_pointer_notify_axis(server.input.seat,
+ event->time_msec, event->orientation, event->delta,
+ event->delta_discrete, event->source);
+}
+
+void
+cursor_frame(struct wl_listener *l, void *data)
+{
+ wlr_seat_pointer_notify_frame(server.input.seat);
+}
+
+void
+request_cursor(struct wl_listener *l, void *data)
+{
+ struct wlr_seat_pointer_request_set_cursor_event *event = data;
+ struct wlr_seat_client *focused = server.input.seat->pointer_state.focused_client;
+ if(focused == event->seat_client)
+ wlr_cursor_set_surface(server.cursor.dot, event->surface, event->hotspot_x, event->hotspot_y);
+}
+
+void
+request_set_selection(struct wl_listener *l, void *data)
+{
+ struct wlr_seat_request_set_selection_event *event = data;
+ wlr_seat_set_selection(server.input.seat, event->source, event->serial);
+}
+
+static
+void
+make_pointer(struct wlr_input_device *device)
+{
+ wlr_cursor_attach_input_device(server.cursor.dot, device);
+}
+
+// -----------------------------------------------------------------------
+// generic input
+
+void
+make_input(struct wl_listener *l, void *data)
+{
+ uint32 capability;
+ struct wlr_input_device *device = data;
+
+ switch(device->type) {
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ make_keyboard(device);
+ break;
+ case WLR_INPUT_DEVICE_POINTER:
+ make_pointer(device);
+ /* fallthrough */
+ default:
+ break;
+ }
+
+ capability = WL_SEAT_CAPABILITY_POINTER;
+ if(!wl_list_empty(&server.input.keyboards))
+ capability |= WL_SEAT_CAPABILITY_KEYBOARD;
+ wlr_seat_set_capabilities(server.input.seat, capability);
+}