swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

seat.c (14809B)


      1 /* swc: libswc/seat.c
      2  *
      3  * Copyright (c) 2013-2020 Michael Forney
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be included in
     13  * all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  */
     23 
     24 #include "seat.h"
     25 #include "compositor.h"
     26 #include "data_device.h"
     27 #include "event.h"
     28 #include "internal.h"
     29 #include "keyboard.h"
     30 #include "launch.h"
     31 #include "pointer.h"
     32 #include "screen.h"
     33 #include "surface.h"
     34 #include "touch.h"
     35 #include "util.h"
     36 
     37 #include <dirent.h>
     38 #include <errno.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <unistd.h>
     43 
     44 #include <libinput.h>
     45 #include <linux/input.h>
     46 #ifdef ENABLE_LIBUDEV
     47 # include <libudev.h>
     48 #endif
     49 
     50 #ifndef NETLINK_MASK
     51 # define NETLINK_MASK 4
     52 #endif
     53 
     54 struct seat {
     55 	struct swc_seat base;
     56 
     57 	char *name;
     58 	uint32_t capabilities;
     59 
     60 	struct libinput *libinput;
     61 	struct wl_event_source *libinput_source;
     62 
     63 #ifdef ENABLE_LIBUDEV
     64 	struct udev *udev;
     65 #endif
     66 
     67 	struct wl_listener swc_listener;
     68 
     69 	struct wl_listener keyboard_focus_listener;
     70 	struct pointer pointer;
     71 	struct wl_listener data_device_listener;
     72 
     73 	struct wl_global *global;
     74 	struct wl_list resources;
     75 };
     76 
     77 static void
     78 handle_keyboard_focus_event(struct wl_listener *listener, void *data)
     79 {
     80 	struct seat *seat = wl_container_of(listener, seat, keyboard_focus_listener);
     81 	struct event *ev = data;
     82 	struct input_focus_event_data *event_data = ev->data;
     83 
     84 	if (ev->type != INPUT_FOCUS_EVENT_CHANGED)
     85 		return;
     86 
     87 	if (event_data->new) {
     88 		struct wl_client *client = wl_resource_get_client(event_data->new->surface->resource);
     89 
     90 		/* Offer the selection to the new focus. */
     91 		data_device_offer_selection(seat->base.data_device, client);
     92 	}
     93 }
     94 
     95 static void
     96 handle_data_device_event(struct wl_listener *listener, void *data)
     97 {
     98 	struct seat *seat = wl_container_of(listener, seat, data_device_listener);
     99 	struct event *ev = data;
    100 
    101 	if (ev->type != DATA_DEVICE_EVENT_SELECTION_CHANGED)
    102 		return;
    103 
    104 	if (seat->base.keyboard->focus.client)
    105 		data_device_offer_selection(seat->base.data_device, seat->base.keyboard->focus.client);
    106 }
    107 
    108 static void
    109 handle_swc_event(struct wl_listener *listener, void *data)
    110 {
    111 	struct seat *seat = wl_container_of(listener, seat, swc_listener);
    112 	struct event *ev = data;
    113 
    114 	switch (ev->type) {
    115 	case SWC_EVENT_DEACTIVATED:
    116 		libinput_suspend(seat->libinput);
    117 		keyboard_reset(seat->base.keyboard);
    118 		break;
    119 	case SWC_EVENT_ACTIVATED:
    120 		if (libinput_resume(seat->libinput) != 0)
    121 			WARNING("Failed to resume libinput context\n");
    122 		break;
    123 	}
    124 }
    125 
    126 /* Wayland Seat Interface */
    127 static void
    128 get_pointer(struct wl_client *client, struct wl_resource *resource, uint32_t id)
    129 {
    130 	struct seat *seat = wl_resource_get_user_data(resource);
    131 
    132 	if (!pointer_bind(&seat->pointer, client, wl_resource_get_version(resource), id))
    133 		wl_resource_post_no_memory(resource);
    134 }
    135 
    136 static void
    137 get_keyboard(struct wl_client *client, struct wl_resource *resource, uint32_t id)
    138 {
    139 	struct seat *seat = wl_resource_get_user_data(resource);
    140 
    141 	if (!keyboard_bind(seat->base.keyboard, client, wl_resource_get_version(resource), id))
    142 		wl_resource_post_no_memory(resource);
    143 }
    144 
    145 static void
    146 get_touch(struct wl_client *client, struct wl_resource *resource, uint32_t id)
    147 {
    148 	struct seat *seat = wl_resource_get_user_data(resource);
    149 
    150 	if (!touch_bind(seat->base.touch, client, wl_resource_get_version(resource), id))
    151 		wl_resource_post_no_memory(resource);
    152 }
    153 
    154 static const struct wl_seat_interface seat_impl = {
    155 	.get_pointer = get_pointer,
    156 	.get_keyboard = get_keyboard,
    157 	.get_touch = get_touch,
    158 };
    159 
    160 static void
    161 bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
    162 {
    163 	struct seat *seat = data;
    164 	struct wl_resource *resource;
    165 
    166 	resource = wl_resource_create(client, &wl_seat_interface, version, id);
    167 	if (!resource) {
    168 		wl_client_post_no_memory(client);
    169 		return;
    170 	}
    171 	wl_resource_set_implementation(resource, &seat_impl, seat, &remove_resource);
    172 	wl_list_insert(&seat->resources, wl_resource_get_link(resource));
    173 
    174 	if (version >= 2)
    175 		wl_seat_send_name(resource, seat->name);
    176 
    177 	wl_seat_send_capabilities(resource, seat->capabilities);
    178 }
    179 
    180 static void
    181 update_capabilities(struct seat *seat, uint32_t capabilities)
    182 {
    183 	struct wl_resource *resource;
    184 
    185 	if (!(~seat->capabilities & capabilities))
    186 		return;
    187 
    188 	seat->capabilities |= capabilities;
    189 	wl_list_for_each(resource, &seat->resources, link)
    190 		wl_seat_send_capabilities(resource, seat->capabilities);
    191 }
    192 
    193 static int
    194 open_restricted(const char *path, int flags, void *user_data)
    195 {
    196 	return launch_open_device(path, flags);
    197 }
    198 
    199 static void
    200 close_restricted(int fd, void *user_data)
    201 {
    202 	close(fd);
    203 }
    204 
    205 const struct libinput_interface libinput_interface = {
    206 	.open_restricted = open_restricted,
    207 	.close_restricted = close_restricted,
    208 };
    209 
    210 static uint32_t
    211 device_capabilities(struct libinput_device *device)
    212 {
    213 	uint32_t capabilities = 0;
    214 
    215 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
    216 		capabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
    217 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER))
    218 		capabilities |= WL_SEAT_CAPABILITY_POINTER;
    219 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
    220 		capabilities |= WL_SEAT_CAPABILITY_TOUCH;
    221 	
    222 
    223 	return capabilities;
    224 }
    225 
    226 static void
    227 handle_libinput_axis_event(struct seat *seat, struct libinput_event_pointer *event, enum libinput_pointer_axis axis)
    228 {
    229 	wl_fixed_t amount;
    230 
    231 	if (!libinput_event_pointer_has_axis(event, axis))
    232 		return;
    233 
    234 	amount = wl_fixed_from_double(libinput_event_pointer_get_axis_value(event, axis));
    235 	pointer_handle_axis(&seat->pointer, libinput_event_pointer_get_time(event), axis, amount);
    236 }
    237 
    238 static int
    239 handle_libinput_data(int fd, uint32_t mask, void *data)
    240 {
    241 	struct seat *seat = data;
    242 	struct screen *screen;
    243 	struct swc_rectangle *rect;
    244 	struct libinput_event *generic_event;
    245 	struct libinput_device *device;
    246 	union {
    247 		struct libinput_event_keyboard *k;
    248 		struct libinput_event_pointer *p;
    249 		struct libinput_event_touch *t;
    250 	} event;
    251 	wl_fixed_t x, y;
    252 	uint32_t time, key, slot, state;
    253 
    254 	if (libinput_dispatch(seat->libinput) != 0) {
    255 		WARNING("libinput_dispatch failed: %s\n", strerror(errno));
    256 		return 0;
    257 	}
    258 
    259 	while ((generic_event = libinput_get_event(seat->libinput))) {
    260 		switch (libinput_event_get_type(generic_event)) {
    261 		case LIBINPUT_EVENT_DEVICE_ADDED:
    262 			device = libinput_event_get_device(generic_event);
    263 			update_capabilities(seat, device_capabilities(device));
    264 			if (swc.manager->new_device)
    265 				swc.manager->new_device(device);
    266 			break;
    267 		case LIBINPUT_EVENT_KEYBOARD_KEY:
    268 			event.k = libinput_event_get_keyboard_event(generic_event);
    269 			time = libinput_event_keyboard_get_time(event.k);
    270 			key = libinput_event_keyboard_get_key(event.k);
    271 			state = libinput_event_keyboard_get_key_state(event.k);
    272 			keyboard_handle_key(seat->base.keyboard, time, key, state);
    273 			break;
    274 		case LIBINPUT_EVENT_POINTER_MOTION:
    275 			event.p = libinput_event_get_pointer_event(generic_event);
    276 			time = libinput_event_pointer_get_time(event.p);
    277 			x = wl_fixed_from_double(libinput_event_pointer_get_dx(event.p));
    278 			y = wl_fixed_from_double(libinput_event_pointer_get_dy(event.p));
    279 			pointer_handle_relative_motion(&seat->pointer, time, x, y);
    280 			break;
    281 		case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
    282 			screen = wl_container_of(swc.screens.next, screen, link);
    283 			rect = &screen->base.geometry;
    284 			event.p = libinput_event_get_pointer_event(generic_event);
    285 			time = libinput_event_pointer_get_time(event.p);
    286 			x = wl_fixed_from_double(libinput_event_pointer_get_absolute_x_transformed(event.p, rect->width));
    287 			y = wl_fixed_from_double(libinput_event_pointer_get_absolute_y_transformed(event.p, rect->height));
    288 			pointer_handle_absolute_motion(&seat->pointer, time, x, y);
    289 			break;
    290 		case LIBINPUT_EVENT_POINTER_BUTTON:
    291 			event.p = libinput_event_get_pointer_event(generic_event);
    292 			time = libinput_event_pointer_get_time(event.p);
    293 			key = libinput_event_pointer_get_button(event.p);
    294 			state = libinput_event_pointer_get_button_state(event.p);
    295 			pointer_handle_button(&seat->pointer, time, key, state);
    296 			if (state == LIBINPUT_BUTTON_STATE_PRESSED) {
    297 		                /* qemu generates GEAR_UP/GEAR_DOWN events on scroll, so pass
    298 				 * those through as axis events. */
    299 				switch (key) {
    300 				case BTN_GEAR_DOWN:
    301 					pointer_handle_axis(&seat->pointer, time, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(10));
    302 					break;
    303 				case BTN_GEAR_UP:
    304 					pointer_handle_axis(&seat->pointer, time, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_int(-10));
    305 					break;
    306 				}
    307 			}
    308 			break;
    309 		case LIBINPUT_EVENT_POINTER_AXIS:
    310 			event.p = libinput_event_get_pointer_event(generic_event);
    311 			handle_libinput_axis_event(seat, event.p, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
    312 			handle_libinput_axis_event(seat, event.p, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
    313 			break;
    314 		case LIBINPUT_EVENT_TOUCH_DOWN:
    315 			screen = wl_container_of(swc.screens.next, screen, link);
    316 			rect = &screen->base.geometry;
    317 			event.t = libinput_event_get_touch_event(generic_event);
    318 			time = libinput_event_touch_get_time(event.t);
    319 			slot = libinput_event_touch_get_seat_slot(event.t);
    320 			x = wl_fixed_from_double(libinput_event_touch_get_x_transformed(event.t, rect->width));
    321 			y = wl_fixed_from_double(libinput_event_touch_get_y_transformed(event.t, rect->height));
    322 			touch_handle_down(seat->base.touch, time, slot, x, y);
    323 			break;
    324 		case LIBINPUT_EVENT_TOUCH_UP:
    325 			event.t = libinput_event_get_touch_event(generic_event);
    326 			time = libinput_event_touch_get_time(event.t);
    327 			slot = libinput_event_touch_get_seat_slot(event.t);
    328 			touch_handle_up(seat->base.touch, time, slot);
    329 			break;
    330 		case LIBINPUT_EVENT_TOUCH_MOTION:
    331 			screen = wl_container_of(swc.screens.next, screen, link);
    332 			rect = &screen->base.geometry;
    333 			event.t = libinput_event_get_touch_event(generic_event);
    334 			time = libinput_event_touch_get_time(event.t);
    335 			slot = libinput_event_touch_get_seat_slot(event.t);
    336 			x = wl_fixed_from_double(libinput_event_touch_get_x_transformed(event.t, rect->width));
    337 			y = wl_fixed_from_double(libinput_event_touch_get_y_transformed(event.t, rect->height));
    338 			touch_handle_motion(seat->base.touch, time, slot, x, y);
    339 			break;
    340 		case LIBINPUT_EVENT_TOUCH_FRAME:
    341 			touch_handle_frame(seat->base.touch);
    342 			break;
    343 		case LIBINPUT_EVENT_TOUCH_CANCEL:
    344 			touch_handle_cancel(seat->base.touch);
    345 			break;
    346 		default:
    347 			break;
    348 		}
    349 
    350 		libinput_event_destroy(generic_event);
    351 	}
    352 
    353 	return 0;
    354 }
    355 
    356 bool
    357 initialize_libinput(struct seat *seat)
    358 {
    359 #ifdef ENABLE_LIBUDEV
    360 	if (!(seat->udev = udev_new())) {
    361 		ERROR("Could not create udev context\n");
    362 		goto error0;
    363 	}
    364 
    365 	seat->libinput = libinput_udev_create_context(&libinput_interface, NULL, seat->udev);
    366 #else
    367 	seat->libinput = libinput_netlink_create_context(&libinput_interface, NULL, NETLINK_MASK);
    368 #endif
    369 
    370 	if (!seat->libinput) {
    371 		ERROR("Could not create libinput context\n");
    372 		goto error1;
    373 	}
    374 
    375 #ifdef ENABLE_LIBUDEV
    376 	if (libinput_udev_assign_seat(seat->libinput, seat->name) != 0) {
    377 		ERROR("Failed to assign seat to libinput context\n");
    378 		goto error2;
    379 	}
    380 #else
    381 	if (libinput_netlink_assign_seat(seat->libinput, seat->name) != 0) {
    382 		ERROR("Failed to assign seat to libinput context\n");
    383 		goto error2;
    384 	}
    385 #endif
    386 
    387 	seat->libinput_source = wl_event_loop_add_fd(swc.event_loop, libinput_get_fd(seat->libinput), WL_EVENT_READABLE, &handle_libinput_data, seat);
    388 	if (!seat->libinput_source) {
    389 		ERROR("Could not create event source for libinput\n");
    390 		goto error2;
    391 	}
    392 
    393 	if (!swc.active)
    394 		libinput_suspend(seat->libinput);
    395 
    396 	return true;
    397 
    398 error2:
    399 	libinput_unref(seat->libinput);
    400 error1:
    401 #ifdef ENABLE_LIBUDEV
    402 	udev_unref(seat->udev);
    403 error0:
    404 #endif
    405 	return false;
    406 }
    407 
    408 struct swc_seat *
    409 seat_create(struct wl_display *display, const char *seat_name)
    410 {
    411 	struct seat *seat;
    412 
    413 	seat = malloc(sizeof(*seat));
    414 	if (!seat)
    415 		goto error0;
    416 	seat->name = strdup(seat_name);
    417 	if (!seat->name) {
    418 		ERROR("Could not allocate seat name string\n");
    419 		goto error1;
    420 	}
    421 	seat->global = wl_global_create(display, &wl_seat_interface, 4, seat, &bind_seat);
    422 	if (!seat->global)
    423 		goto error2;
    424 	seat->capabilities = 0;
    425 	wl_list_init(&seat->resources);
    426 
    427 	seat->swc_listener.notify = &handle_swc_event;
    428 	wl_signal_add(&swc.event_signal, &seat->swc_listener);
    429 
    430 	seat->base.data_device = data_device_create();
    431 	if (!seat->base.data_device) {
    432 		ERROR("Could not initialize data device\n");
    433 		goto error3;
    434 	}
    435 	seat->data_device_listener.notify = &handle_data_device_event;
    436 	wl_signal_add(&seat->base.data_device->event_signal, &seat->data_device_listener);
    437 
    438 	seat->base.keyboard = keyboard_create(NULL);
    439 	if (!seat->base.keyboard) {
    440 		ERROR("Could not initialize keyboard\n");
    441 		goto error4;
    442 	}
    443 	seat->keyboard_focus_listener.notify = handle_keyboard_focus_event;
    444 	wl_signal_add(&seat->base.keyboard->focus.event_signal, &seat->keyboard_focus_listener);
    445 
    446 	if (!pointer_initialize(&seat->pointer)) {
    447 		ERROR("Could not initialize pointer\n");
    448 		goto error5;
    449 	}
    450 	seat->base.pointer = &seat->pointer;
    451 
    452 	seat->base.touch = touch_create();
    453 	if (!seat->base.touch) {
    454 		ERROR("Could not initialize touch\n");
    455 		goto error6;
    456 	}
    457 
    458 	seat->base.input_method = NULL;
    459 
    460 	if (!initialize_libinput(seat))
    461 		goto error7;
    462 
    463 	return &seat->base;
    464 
    465 error7:
    466 	touch_destroy(seat->base.touch);
    467 error6:
    468 	pointer_finalize(&seat->pointer);
    469 error5:
    470 	keyboard_destroy(seat->base.keyboard);
    471 error4:
    472 	data_device_destroy(seat->base.data_device);
    473 error3:
    474 	wl_global_destroy(seat->global);
    475 error2:
    476 	free(seat->name);
    477 error1:
    478 	free(seat);
    479 error0:
    480 	return NULL;
    481 }
    482 
    483 void
    484 seat_destroy(struct swc_seat *seat_base)
    485 {
    486 	struct seat *seat = wl_container_of(seat_base, seat, base);
    487 
    488 	wl_event_source_remove(seat->libinput_source);
    489 	libinput_unref(seat->libinput);
    490 #ifdef ENABLE_LIBUDEV
    491 	udev_unref(seat->udev);
    492 #endif
    493 
    494 	pointer_finalize(&seat->pointer);
    495 	keyboard_destroy(seat->base.keyboard);
    496 	data_device_destroy(seat->base.data_device);
    497 
    498 	wl_global_destroy(seat->global);
    499 	free(seat->name);
    500 	free(seat);
    501 }