commit ac63183
shrub
·
2026-08-06 18:33:20 +0000 UTC
parent fa87d67
drop evdev-only seat
5 files changed,
+7,
-704
+1,
-2
1@@ -18,7 +18,6 @@ neu features
2 - fullscreen
3 - double window borders
4 - screenshots
5-- evdev-only input backend
6 - layer shell support
7 - window decorations
8
9@@ -35,7 +34,7 @@ you will need:
10 - wayland-server, wayland-client
11 - libdrm, pixman, xkbcommon
12 - [neuwld](https://git.sr.ht/~shrub900/neuwld)
13-- on linux, either libinput or evdev, depending on your choice of input backend, neither on BSD
14+- libinput on Linux and wscons on BSD
15 - xcb, xcb-composite, xcb-ewmh and xcb-icccm if you want Xwayland support.
16
17 to build, i use muon and samu. you can probably do something similar with meson and ninja.
+0,
-1
1@@ -42,7 +42,6 @@ libswc_src = files(
2
3 input_backend == 'libinput' ? 'seat.c' : [],
4 input_backend == 'wscons' ? 'seat-ws.c' : [],
5- input_backend == 'evdev' ? 'seat-evdev.c' : [],
6
7 xwayland.found() ? ['xserver.c', 'xwm.c'] : [],
8 )
+0,
-691
1@@ -1,691 +0,0 @@
2-#include "compositor.h"
3-#include "data_device.h"
4-#include "event.h"
5-#include "internal.h"
6-#include "keyboard.h"
7-#include "launch.h"
8-#include "pointer.h"
9-#include "screen.h"
10-#include "seat.h"
11-#include "surface.h"
12-#include "util.h"
13-
14-#include <ctype.h>
15-#include <dirent.h>
16-#include <errno.h>
17-#include <fcntl.h>
18-#include <limits.h>
19-#include <stdbool.h>
20-#include <stdint.h>
21-#include <stdio.h>
22-#include <stdlib.h>
23-#include <string.h>
24-#include <sys/ioctl.h>
25-#include <unistd.h>
26-
27-#include <linux/input.h>
28-
29-struct seat {
30- struct swc_seat base;
31-
32- char *name;
33- uint32_t capabilities;
34-
35- int mouse_fd;
36- int kbd_fd;
37- bool ignore;
38-
39- struct xkb_rule_names names;
40-
41- struct wl_event_source *mouse_source;
42- struct wl_event_source *kbd_source;
43-
44- struct wl_listener swc_listener;
45-
46- struct wl_listener keyboard_focus_listener;
47- struct pointer pointer;
48- struct wl_listener data_device_listener;
49-
50- struct wl_global *global;
51- struct wl_list resources;
52-
53- wl_fixed_t abs_x;
54- wl_fixed_t abs_y;
55- bool abs_initialized;
56-
57- bool shared_fd;
58-};
59-
60-static void
61-handle_keyboard_focus_event(struct wl_listener *listener, void *data)
62-{
63- struct seat *seat =
64- wl_container_of(listener, seat, keyboard_focus_listener);
65- struct event *ev = data;
66- struct input_focus_event_data *event_data = ev->data;
67-
68- if (ev->type != INPUT_FOCUS_EVENT_CHANGED) {
69- return;
70- }
71-
72- if (event_data->new) {
73- struct wl_client *client =
74- wl_resource_get_client(event_data->new->surface->resource);
75-
76- /* offer the selection to the new focus */
77- data_device_offer_selection(seat->base.data_device, client);
78- }
79-}
80-
81-static void
82-handle_data_device_event(struct wl_listener *listener, void *data)
83-{
84- struct seat *seat = wl_container_of(listener, seat, data_device_listener);
85- struct event *ev = data;
86-
87- if (ev->type != DATA_DEVICE_EVENT_SELECTION_CHANGED) {
88- return;
89- }
90-
91- if (seat->base.keyboard->focus.client) {
92- data_device_offer_selection(seat->base.data_device,
93- seat->base.keyboard->focus.client);
94- }
95-}
96-
97-static void
98-handle_swc_event(struct wl_listener *listener, void *data)
99-{
100- struct seat *seat = wl_container_of(listener, seat, swc_listener);
101- struct event *ev = data;
102-
103- switch (ev->type) {
104- case SWC_EVENT_DEACTIVATED:
105- seat->ignore = true;
106- keyboard_reset(seat->base.keyboard);
107- break;
108- case SWC_EVENT_ACTIVATED:
109- seat->ignore = false;
110- break;
111- }
112-}
113-
114-/* da seat */
115-static void
116-get_pointer(struct wl_client *client, struct wl_resource *resource, uint32_t id)
117-{
118- struct seat *seat = wl_resource_get_user_data(resource);
119-
120- pointer_bind(&seat->pointer, client, wl_resource_get_version(resource), id);
121-}
122-
123-static void
124-get_keyboard(struct wl_client *client, struct wl_resource *resource,
125- uint32_t id)
126-{
127- struct seat *seat = wl_resource_get_user_data(resource);
128-
129- keyboard_bind(seat->base.keyboard, client,
130- wl_resource_get_version(resource), id);
131-}
132-
133-static void
134-get_touch(struct wl_client *client, struct wl_resource *resource, uint32_t id)
135-{
136-}
137-
138-static struct wl_seat_interface seat_impl = {
139- .get_pointer = get_pointer,
140- .get_keyboard = get_keyboard,
141- .get_touch = get_touch,
142-};
143-
144-static void
145-bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
146-{
147- struct seat *seat = data;
148- struct wl_resource *resource;
149-
150- if (version > 4) {
151- version = 4;
152- }
153-
154- resource = wl_resource_create(client, &wl_seat_interface, version, id);
155- wl_resource_set_implementation(resource, &seat_impl, seat,
156- &remove_resource);
157- wl_list_insert(&seat->resources, wl_resource_get_link(resource));
158-
159- if (version >= 2) {
160- wl_seat_send_name(resource, seat->name);
161- }
162-
163- wl_seat_send_capabilities(resource, seat->capabilities);
164-}
165-
166-static uint32_t
167-event_time_ms(const struct input_event *ev)
168-{
169- return (uint32_t)(ev->time.tv_sec * 1000 + ev->time.tv_usec / 1000);
170-}
171-
172-static void
173-handle_evdev_key(struct seat *seat, const struct input_event *ev)
174-{
175- uint32_t state;
176- uint32_t time = event_time_ms(ev);
177-
178- if (ev->value == 2) {
179- return;
180- }
181-
182- if (ev->code >= BTN_MISC) {
183- pointer_handle_button(seat->base.pointer, time, ev->code,
184- ev->value ? WL_POINTER_BUTTON_STATE_PRESSED
185- : WL_POINTER_BUTTON_STATE_RELEASED);
186- } else {
187- if (ev->code > 255) {
188- return;
189- }
190- state = (ev->value ? WL_KEYBOARD_KEY_STATE_PRESSED
191- : WL_KEYBOARD_KEY_STATE_RELEASED);
192- keyboard_handle_key(seat->base.keyboard, time, ev->code, state);
193- }
194-}
195-
196-static void
197-handle_evdev_rel(struct seat *seat, const struct input_event *ev)
198-{
199- uint32_t time = event_time_ms(ev);
200- wl_fixed_t value;
201-
202- switch (ev->code) {
203- case REL_X:
204- pointer_handle_relative_motion(seat->base.pointer, time,
205- wl_fixed_from_int(ev->value), 0);
206- break;
207- case REL_Y:
208- pointer_handle_relative_motion(seat->base.pointer, time, 0,
209- wl_fixed_from_int(ev->value));
210- break;
211- case REL_WHEEL:
212- value = wl_fixed_from_int(ev->value * 10);
213- pointer_handle_axis(
214- seat->base.pointer, time, WL_POINTER_AXIS_VERTICAL_SCROLL,
215- WL_POINTER_AXIS_SOURCE_WHEEL, value, ev->value * 120);
216- break;
217- case REL_HWHEEL:
218- value = wl_fixed_from_int(ev->value * 10);
219- pointer_handle_axis(
220- seat->base.pointer, time, WL_POINTER_AXIS_HORIZONTAL_SCROLL,
221- WL_POINTER_AXIS_SOURCE_WHEEL, value, ev->value * 120);
222- break;
223- default:
224- break;
225- }
226-}
227-
228-static void
229-handle_evdev_abs(struct seat *seat, const struct input_event *ev)
230-{
231- uint32_t time = event_time_ms(ev);
232-
233- switch (ev->code) {
234- case ABS_X:
235- seat->abs_x = wl_fixed_from_int(ev->value);
236- seat->abs_initialized = true;
237- break;
238- case ABS_Y:
239- seat->abs_y = wl_fixed_from_int(ev->value);
240- seat->abs_initialized = true;
241- break;
242- default:
243- return;
244- }
245-
246- if (seat->abs_initialized) {
247- pointer_handle_absolute_motion(seat->base.pointer, time, seat->abs_x,
248- seat->abs_y);
249- }
250-}
251-
252-static int
253-handle_evdev_data(int fd, uint32_t mask, void *data)
254-{
255- struct seat *seat = data;
256- struct input_event ev;
257- ssize_t n;
258-
259- while (!seat->ignore) {
260- n = read(fd, &ev, sizeof(ev));
261- if (n == -1) {
262- if (errno == EAGAIN || errno == EINTR) {
263- break;
264- }
265- return 0;
266- }
267- if (n != (ssize_t)sizeof(ev)) {
268- break;
269- }
270-
271- switch (ev.type) {
272- case EV_KEY:
273- handle_evdev_key(seat, &ev);
274- break;
275- case EV_REL:
276- handle_evdev_rel(seat, &ev);
277- break;
278- case EV_ABS:
279- handle_evdev_abs(seat, &ev);
280- break;
281- case EV_SYN:
282- if (ev.code == SYN_REPORT) {
283- pointer_handle_frame(seat->base.pointer);
284- }
285- break;
286- default:
287- break;
288- }
289- }
290-
291- return 0;
292-}
293-
294-static bool
295-test_bit(const unsigned long *bits, size_t bit)
296-{
297- return (bits[bit / (sizeof(unsigned long) * 8)] >>
298- (bit % (sizeof(unsigned long) * 8))) &
299- 1;
300-}
301-
302-static bool
303-contains_ci(const char *haystack, const char *needle)
304-{
305- size_t nlen;
306- const char *h;
307-
308- if (!haystack || !needle || !*needle) {
309- return false;
310- }
311-
312- nlen = strlen(needle);
313- for (h = haystack; *h; ++h) {
314- size_t i;
315- for (i = 0; i < nlen; ++i) {
316- unsigned char hc = (unsigned char)h[i];
317- unsigned char nc = (unsigned char)needle[i];
318- if (!h[i] || tolower(hc) != tolower(nc)) {
319- break;
320- }
321- }
322- if (i == nlen) {
323- return true;
324- }
325- }
326- return false;
327-}
328-
329-static bool
330-is_keyboard_device(int fd)
331-{
332- unsigned long ev_bits[(EV_MAX + 8 * sizeof(unsigned long) - 1) /
333- (8 * sizeof(unsigned long))];
334- unsigned long key_bits[(KEY_MAX + 8 * sizeof(unsigned long) - 1) /
335- (8 * sizeof(unsigned long))];
336-
337- memset(ev_bits, 0, sizeof(ev_bits));
338- memset(key_bits, 0, sizeof(key_bits));
339-
340- if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
341- return false;
342- }
343- if (!test_bit(ev_bits, EV_KEY)) {
344- return false;
345- }
346- if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) {
347- return false;
348- }
349-
350- return test_bit(key_bits, KEY_A) && test_bit(key_bits, KEY_Z) &&
351- test_bit(key_bits, KEY_ENTER) && test_bit(key_bits, KEY_ESC) &&
352- test_bit(key_bits, KEY_SPACE);
353-}
354-
355-static bool
356-is_pointer_device(int fd)
357-{
358- unsigned long ev_bits[(EV_MAX + 8 * sizeof(unsigned long) - 1) /
359- (8 * sizeof(unsigned long))];
360- unsigned long rel_bits[(REL_MAX + 8 * sizeof(unsigned long) - 1) /
361- (8 * sizeof(unsigned long))];
362- unsigned long key_bits[(KEY_MAX + 8 * sizeof(unsigned long) - 1) /
363- (8 * sizeof(unsigned long))];
364-
365- memset(ev_bits, 0, sizeof(ev_bits));
366- memset(rel_bits, 0, sizeof(rel_bits));
367- memset(key_bits, 0, sizeof(key_bits));
368-
369- if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
370- return false;
371- }
372-
373- if (test_bit(ev_bits, EV_REL)) {
374- if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) < 0) {
375- return false;
376- }
377- if (test_bit(rel_bits, REL_X) && test_bit(rel_bits, REL_Y)) {
378- return true;
379- }
380- }
381-
382- if (test_bit(ev_bits, EV_KEY)) {
383- if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) {
384- return false;
385- }
386- if (test_bit(key_bits, BTN_LEFT) && test_bit(key_bits, BTN_RIGHT)) {
387- return true;
388- }
389- }
390-
391- return false;
392-}
393-
394-static bool
395-get_ev_bits(int fd, unsigned long *ev_bits, size_t ev_bits_len)
396-{
397- memset(ev_bits, 0, ev_bits_len);
398- return ioctl(fd, EVIOCGBIT(0, ev_bits_len), ev_bits) >= 0;
399-}
400-
401-static int
402-score_candidate(int fd, bool want_keyboard, const char *id_name)
403-{
404- char name[256];
405- unsigned long ev_bits[(EV_MAX + 8 * sizeof(unsigned long) - 1) /
406- (8 * sizeof(unsigned long))];
407- bool is_kbd;
408- bool is_ptr;
409- int score = 10;
410-
411- is_kbd = is_keyboard_device(fd);
412- is_ptr = is_pointer_device(fd);
413-
414- if (want_keyboard && !is_kbd) {
415- return -1;
416- }
417- if (!want_keyboard && !is_ptr) {
418- return -1;
419- }
420-
421- if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
422- name[0] = '\0';
423- }
424-
425- if (!get_ev_bits(fd, ev_bits, sizeof(ev_bits))) {
426- memset(ev_bits, 0, sizeof(ev_bits));
427- }
428-
429- if (want_keyboard) {
430- if (is_ptr) {
431- score -= 6;
432- }
433- if (contains_ci(id_name, "mouse") || contains_ci(name, "mouse")) {
434- score -= 12;
435- }
436- if (contains_ci(id_name, "kbd") || contains_ci(id_name, "keyboard")) {
437- score += 4;
438- }
439- if (contains_ci(name, "keyboard")) {
440- score += 2;
441- }
442- if (test_bit(ev_bits, EV_LED)) {
443- score += 3;
444- }
445- if (test_bit(ev_bits, EV_REP)) {
446- score += 1;
447- }
448- } else {
449- if (contains_ci(id_name, "mouse") || contains_ci(name, "mouse")) {
450- score += 4;
451- }
452- if (contains_ci(id_name, "kbd") || contains_ci(id_name, "keyboard")) {
453- score -= 6;
454- }
455- if (contains_ci(name, "keyboard")) {
456- score -= 4;
457- }
458- }
459-
460- return score;
461-}
462-
463-static bool
464-pick_best_device(const char *dir_path, const char *name_prefix,
465- const char *name_substr, bool want_keyboard, char *out,
466- size_t out_len)
467-{
468- DIR *dir;
469- struct dirent *ent;
470- bool found = false;
471- int best_score = -1;
472- size_t prefix_len = name_prefix ? strlen(name_prefix) : 0;
473-
474- dir = opendir(dir_path);
475- if (!dir) {
476- return false;
477- }
478-
479- while ((ent = readdir(dir)) != NULL) {
480- char path[PATH_MAX];
481- int fd;
482- int score;
483-
484- if (ent->d_name[0] == '.') {
485- continue;
486- }
487- if (name_prefix && strncmp(ent->d_name, name_prefix, prefix_len) != 0) {
488- continue;
489- }
490- if (name_substr && !strstr(ent->d_name, name_substr)) {
491- continue;
492- }
493-
494- snprintf(path, sizeof(path), "%s/%s", dir_path, ent->d_name);
495- fd = launch_open_device(path, O_RDONLY | O_NONBLOCK);
496- if (fd == -1) {
497- continue;
498- }
499-
500- score = score_candidate(fd, want_keyboard, ent->d_name);
501- if (score < 0) {
502- close(fd);
503- continue;
504- }
505-
506- if (score > best_score) {
507- snprintf(out, out_len, "%s", path);
508- best_score = score;
509- found = true;
510- }
511-
512- close(fd);
513- }
514-
515- closedir(dir);
516- return found;
517-}
518-
519-static bool
520-initialize_evdev(struct seat *seat)
521-{
522- char kbd_path[PATH_MAX];
523- char mouse_path[PATH_MAX];
524- const char *kbd_dev = EVDEV_KBD_DEVICE;
525- const char *mouse_dev = EVDEV_POINTER_DEVICE;
526-
527- if (pick_best_device("/dev/input/by-id", NULL, "event-kbd", true, kbd_path,
528- sizeof(kbd_path))) {
529- kbd_dev = kbd_path;
530- } else if (pick_best_device("/dev/input/by-path", NULL, "event-kbd", true,
531- kbd_path, sizeof(kbd_path))) {
532- kbd_dev = kbd_path;
533- } else if (pick_best_device("/dev/input", "event", NULL, true, kbd_path,
534- sizeof(kbd_path))) {
535- kbd_dev = kbd_path;
536- }
537-
538- if (pick_best_device("/dev/input/by-id", NULL, "event-mouse", false,
539- mouse_path, sizeof(mouse_path))) {
540- mouse_dev = mouse_path;
541- } else if (pick_best_device("/dev/input/by-path", NULL, "event-mouse",
542- false, mouse_path, sizeof(mouse_path))) {
543- mouse_dev = mouse_path;
544- } else if (pick_best_device("/dev/input", "event", NULL, false, mouse_path,
545- sizeof(mouse_path))) {
546- mouse_dev = mouse_path;
547- }
548-
549- DEBUG("evdev devices: keyboard=%s pointer=%s\n", kbd_dev, mouse_dev);
550-
551- seat->kbd_fd = launch_open_device(kbd_dev, O_RDONLY | O_NONBLOCK);
552- if (seat->kbd_fd == -1) {
553- ERROR("Could not open evdev keyboard device %s\n", kbd_dev);
554- goto error0;
555- }
556-
557- if (strcmp(kbd_dev, mouse_dev) == 0) {
558- seat->mouse_fd = seat->kbd_fd;
559- seat->shared_fd = true;
560- return true;
561- }
562-
563- seat->mouse_fd = launch_open_device(mouse_dev, O_RDONLY | O_NONBLOCK);
564- if (seat->mouse_fd == -1) {
565- ERROR("Could not open evdev pointer device %s\n", mouse_dev);
566- goto error1;
567- }
568-
569- return true;
570-
571-error1:
572- close(seat->kbd_fd);
573-error0:
574- return false;
575-}
576-
577-struct swc_seat *
578-seat_create(struct wl_display *display, const char *seat_name)
579-{
580- struct seat *seat;
581-
582- seat = malloc(sizeof(*seat));
583- if (!seat) {
584- goto error0;
585- }
586-
587- memset(&seat->names, 0, sizeof(seat->names));
588- seat->names.rules = "base";
589- seat->names.model = "pc105";
590- seat->names.layout = "us";
591- seat->names.variant = "basic";
592- seat->shared_fd = false;
593-
594- seat->name = strdup(seat_name);
595- if (!seat->name) {
596- ERROR("Could not allocate seat name string\n");
597- goto error1;
598- }
599-
600- if (!initialize_evdev(seat)) {
601- goto error2;
602- }
603-
604- seat->global =
605- wl_global_create(display, &wl_seat_interface, 4, seat, &bind_seat);
606- if (!seat->global) {
607- goto error2;
608- }
609- seat->capabilities =
610- WL_SEAT_CAPABILITY_KEYBOARD | WL_SEAT_CAPABILITY_POINTER;
611- wl_list_init(&seat->resources);
612-
613- seat->swc_listener.notify = &handle_swc_event;
614- wl_signal_add(&swc.event_signal, &seat->swc_listener);
615-
616- seat->base.data_device = data_device_create();
617- if (!seat->base.data_device) {
618- ERROR("could not initialize data device\n");
619- goto error3;
620- }
621- seat->data_device_listener.notify = &handle_data_device_event;
622- wl_signal_add(&seat->base.data_device->event_signal,
623- &seat->data_device_listener);
624-
625- seat->base.keyboard = keyboard_create(&seat->names);
626- if (!seat->base.keyboard) {
627- ERROR("could not initialize keyboard\n");
628- goto error4;
629- }
630- seat->keyboard_focus_listener.notify = handle_keyboard_focus_event;
631- wl_signal_add(&seat->base.keyboard->focus.event_signal,
632- &seat->keyboard_focus_listener);
633-
634- if (!pointer_initialize(&seat->pointer)) {
635- ERROR("Could not initialize pointer\n");
636- goto error5;
637- }
638- seat->base.pointer = &seat->pointer;
639-
640- seat->kbd_source =
641- wl_event_loop_add_fd(swc.event_loop, seat->kbd_fd, WL_EVENT_READABLE,
642- &handle_evdev_data, seat);
643- if (!seat->shared_fd) {
644- seat->mouse_source =
645- wl_event_loop_add_fd(swc.event_loop, seat->mouse_fd,
646- WL_EVENT_READABLE, &handle_evdev_data, seat);
647- } else {
648- seat->mouse_source = NULL;
649- }
650-
651- seat->abs_initialized = false;
652-
653- return &seat->base;
654-
655-error5:
656- keyboard_destroy(seat->base.keyboard);
657-error4:
658- data_device_destroy(seat->base.data_device);
659-error3:
660- wl_global_destroy(seat->global);
661-error2:
662- free(seat->name);
663-error1:
664- free(seat);
665-error0:
666- return NULL;
667-}
668-
669-void
670-seat_destroy(struct swc_seat *seat_base)
671-{
672- struct seat *seat = wl_container_of(seat_base, seat, base);
673-
674- if (seat->mouse_source) {
675- wl_event_source_remove(seat->mouse_source);
676- }
677- wl_event_source_remove(seat->kbd_source);
678- if (seat->mouse_source) {
679- close(seat->mouse_fd);
680- seat->mouse_fd = -1;
681- }
682- close(seat->kbd_fd);
683- seat->kbd_fd = -1;
684-
685- pointer_finalize(&seat->pointer);
686- keyboard_destroy(seat->base.keyboard);
687- data_device_destroy(seat->base.data_device);
688-
689- wl_global_destroy(seat->global);
690- free(seat->name);
691- free(seat);
692-}
+5,
-7
1@@ -58,8 +58,11 @@ libinput = dependency('libinput', version: '>=0.4', required: input_backend == '
2
3 if input_backend == 'auto'
4 if os == 'linux'
5- input_backend = libinput.found() ? 'libinput' : 'evdev'
6- elif os == 'netbsd'
7+ if not libinput.found()
8+ error('libinput is required for the Linux input backend')
9+ endif
10+ input_backend = 'libinput'
11+ elif os == 'netbsd' or os == 'openbsd'
12 input_backend = 'wscons'
13 else
14 error('Failed to determine input backend for ' + os)
15@@ -72,11 +75,6 @@ if input_backend == 'libinput'
16 add_project_arguments('-DENABLE_LIBUDEV', language: 'c')
17 endif
18 requires_private += [libinput, udev]
19-elif input_backend == 'evdev'
20- add_project_arguments([
21- '-DEVDEV_KBD_DEVICE="@0@"'.format(get_option('evdev-keyboard')),
22- '-DEVDEV_POINTER_DEVICE="@0@"'.format(get_option('evdev-pointer')),
23- ], language: 'c')
24 endif
25
26 subdir('protocol')
+1,
-3
1@@ -1,7 +1,5 @@
2 option('xwayland', type: 'feature', value: 'auto', description: 'Automatic Xwayland handling')
3-option('input', type: 'combo', value: 'auto', choices: ['auto', 'libinput', 'evdev', 'wscons'], description: 'Input backend to use')
4+option('input', type: 'combo', value: 'auto', choices: ['auto', 'libinput', 'wscons'], description: 'Input backend to use')
5 option('udev', type: 'feature', value: 'auto', description: 'libinput libudev support')
6-option('evdev-keyboard', type: 'string', value: '/dev/input/event0', description: 'evdev keyboard device to use')
7-option('evdev-pointer', type: 'string', value: '/dev/input/event1', description: 'evdev pointer device to use')
8 option('extra', type: 'boolean', value: true, description: 'Build swc utility applications')
9 option('example', type: 'boolean', value: false, description: 'Build swc example compositor')