From c1565f3ca663aa4ba4316d7248737ab817116fbd Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sat, 21 Feb 2015 11:53:59 -0800 Subject: [PATCH 1/8] xwayland-input: Remove our XYToWindow handler This was built as a hack for simple Wayland compositors like Weston which were lazy and didn't want to configure windows server-side when moved. Since comboboxes and menus are separate toplevel O-R windows, this hack breaks input as it needs to be traced normally, not simply sent to the focused window. X11 toolkits really do need their windows to be configured correctly for their O-R windows comboboxes or menus other things, so let's fix the lazy compositors and remove this. I have tested this patch with both Weston and Mutter and neither of them require any changes, and it fixes comboboxes and menus. If somebody then wants to revert 73698d4, that's fine by me, so we reduce the amount of API that DDXen have. Signed-off-by: Jasper St. Pierre Reviewed-by: Daniel Stone --- hw/xwayland/xwayland-input.c | 34 ---------------------------------- hw/xwayland/xwayland.h | 1 - 2 files changed, 35 deletions(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 32007ded3..4a166ef65 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -638,37 +638,6 @@ DDXRingBell(int volume, int pitch, int duration) { } -static WindowPtr -xwl_xy_to_window(ScreenPtr screen, SpritePtr sprite, int x, int y) -{ - struct xwl_seat *xwl_seat = NULL; - DeviceIntPtr device; - - for (device = inputInfo.devices; device; device = device->next) { - if (device->deviceProc == xwl_pointer_proc && - device->spriteInfo->sprite == sprite) { - xwl_seat = device->public.devicePrivate; - break; - } - } - - if (xwl_seat == NULL) { - /* XTEST device */ - sprite->spriteTraceGood = 1; - return sprite->spriteTrace[0]; - } - - if (xwl_seat->focus_window) { - sprite->spriteTraceGood = 2; - sprite->spriteTrace[1] = xwl_seat->focus_window->window; - return miSpriteTrace(sprite, x, y); - } - else { - sprite->spriteTraceGood = 1; - return sprite->spriteTrace[0]; - } -} - void InitInput(int argc, char *argv[]) { @@ -681,9 +650,6 @@ InitInput(int argc, char *argv[]) wl_registry_add_listener(xwl_screen->input_registry, &input_listener, xwl_screen); - xwl_screen->XYToWindow = pScreen->XYToWindow; - pScreen->XYToWindow = xwl_xy_to_window; - xwl_screen->expecting_event = 0; wl_display_roundtrip(xwl_screen->display); while (xwl_screen->expecting_event) diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 28b0c995e..cd728ca33 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -62,7 +62,6 @@ struct xwl_screen { DestroyWindowProcPtr DestroyWindow; RealizeWindowProcPtr RealizeWindow; UnrealizeWindowProcPtr UnrealizeWindow; - XYToWindowProcPtr XYToWindow; struct xorg_list output_list; struct xorg_list seat_list; From d96eccc057094be31c1ee4e3b3246675934cb19d Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 27 May 2015 18:41:58 +0200 Subject: [PATCH 2/8] xwayland: Add xwl_touch struct This struct holds information about each individual, ongoing touchpoint. A list of these is held by the xwl_seat. Signed-off-by: Carlos Garnacho Reviewed-by: Olivier Fourdan --- hw/xwayland/xwayland-input.c | 10 ++++++++++ hw/xwayland/xwayland.h | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 4a166ef65..997b90f53 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -586,11 +586,21 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version xwl_seat->cursor = wl_compositor_create_surface(xwl_screen->compositor); wl_seat_add_listener(xwl_seat->seat, &seat_listener, xwl_seat); wl_array_init(&xwl_seat->keys); + + xorg_list_init(&xwl_seat->touches); } void xwl_seat_destroy(struct xwl_seat *xwl_seat) { + struct xwl_touch *xwl_touch, *next_xwl_touch; + + xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch, + &xwl_seat->touches, link_touch) { + xorg_list_del(&xwl_touch->link_touch); + free(xwl_touch); + } + wl_seat_destroy(xwl_seat->seat); wl_surface_destroy(xwl_seat->cursor); if (xwl_seat->cursor_frame_cb) diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index cd728ca33..3c10862e0 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -106,6 +106,13 @@ struct xwl_window { #define MODIFIER_META 0x01 +struct xwl_touch { + struct xwl_window *window; + int32_t id; + int x, y; + struct xorg_list link_touch; +}; + struct xwl_seat { DeviceIntPtr pointer; DeviceIntPtr keyboard; @@ -123,6 +130,8 @@ struct xwl_seat { struct wl_callback *cursor_frame_cb; Bool cursor_needs_update; + struct xorg_list touches; + size_t keymap_size; char *keymap; struct wl_surface *keyboard_focus; From b7cd48f71d269101e28ae6855b895057378715f9 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 27 May 2015 18:41:59 +0200 Subject: [PATCH 3/8] xwayland: Implement the wl_touch interface A DeviceIntPtr with touch valuators is also created in order to deliver the translated touch events. The lifetime of xwl_touch structs is tied to the wayland ones, finishing in either wl_touch.up() or wl_touch.cancel() Signed-off-by: Carlos Garnacho Reviewed-by: Olivier Fourdan --- hw/xwayland/xwayland-input.c | 198 ++++++++++++++++++++++++++++++++++- hw/xwayland/xwayland.h | 2 + 2 files changed, 199 insertions(+), 1 deletion(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 997b90f53..ef38e6af9 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -148,6 +148,61 @@ xwl_keyboard_proc(DeviceIntPtr device, int what) return BadMatch; } +static int +xwl_touch_proc(DeviceIntPtr device, int what) +{ +#define NTOUCHPOINTS 20 +#define NBUTTONS 1 +#define NAXES 2 + struct xwl_seat *xwl_seat = device->public.devicePrivate; + Atom btn_labels[NBUTTONS] = { 0 }; + Atom axes_labels[NAXES] = { 0 }; + BYTE map[NBUTTONS + 1] = { 0 }; + + switch (what) { + case DEVICE_INIT: + device->public.on = FALSE; + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y); + + if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels, + GetMotionHistorySize(), Absolute)) + return BadValue; + + if (!InitButtonClassDeviceStruct(device, NBUTTONS, btn_labels, map)) + return BadValue; + + if (!InitTouchClassDeviceStruct(device, NTOUCHPOINTS, + XIDirectTouch, NAXES)) + return BadValue; + + /* Valuators */ + /* FIXME: devices might be mapped to a single wl_output */ + InitValuatorAxisStruct(device, 0, axes_labels[0], + 0, xwl_seat->xwl_screen->width, + 10000, 0, 10000, Absolute); + InitValuatorAxisStruct(device, 1, axes_labels[1], + 0, xwl_seat->xwl_screen->height, + 10000, 0, 10000, Absolute); + return Success; + + case DEVICE_ON: + device->public.on = TRUE; + return Success; + + case DEVICE_OFF: + case DEVICE_CLOSE: + device->public.on = FALSE; + return Success; + } + + return BadMatch; +#undef NAXES +#undef NBUTTONS +#undef NTOUCHPOINTS +} + static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, @@ -480,6 +535,129 @@ static const struct wl_keyboard_listener keyboard_listener = { keyboard_handle_repeat_info, }; +static struct xwl_touch * +xwl_seat_lookup_touch(struct xwl_seat *xwl_seat, int32_t id) +{ + struct xwl_touch *xwl_touch, *next_xwl_touch; + + xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch, + &xwl_seat->touches, link_touch) { + if (xwl_touch->id == id) + return xwl_touch; + } + + return NULL; +} + +static void +xwl_touch_send_event(struct xwl_touch *xwl_touch, + struct xwl_seat *xwl_seat, int type) +{ + int32_t dx, dy; + ValuatorMask mask; + + dx = xwl_touch->window->window->drawable.x; + dy = xwl_touch->window->window->drawable.y; + + valuator_mask_zero(&mask); + valuator_mask_set(&mask, 0, dx + xwl_touch->x); + valuator_mask_set(&mask, 1, dy + xwl_touch->y); + QueueTouchEvents(xwl_seat->touch, type, xwl_touch->id, 0, &mask); +} + +static void +touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, + struct wl_surface *surface, + int32_t id, wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + struct xwl_seat *xwl_seat = data; + struct xwl_touch *xwl_touch; + + if (surface == NULL) + return; + + xwl_touch = calloc(sizeof *xwl_touch, 1); + if (xwl_touch == NULL) { + ErrorF("touch_handle_down ENOMEM"); + return; + } + + xwl_touch->window = wl_surface_get_user_data(surface); + xwl_touch->id = id; + xwl_touch->x = wl_fixed_to_int(sx_w); + xwl_touch->y = wl_fixed_to_int(sy_w); + xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches); + + xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin); +} + +static void +touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) +{ + struct xwl_touch *xwl_touch; + struct xwl_seat *xwl_seat = data; + + xwl_touch = xwl_seat_lookup_touch(xwl_seat, id); + + if (!xwl_touch) + return; + + xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchEnd); + xorg_list_del(&xwl_touch->link_touch); + free(xwl_touch); +} + +static void +touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, + wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + struct xwl_seat *xwl_seat = data; + struct xwl_touch *xwl_touch; + + xwl_touch = xwl_seat_lookup_touch(xwl_seat, id); + + if (!xwl_touch) + return; + + xwl_touch->x = wl_fixed_to_int(sx_w); + xwl_touch->y = wl_fixed_to_int(sy_w); + xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate); +} + +static void +touch_handle_frame(void *data, struct wl_touch *wl_touch) +{ +} + +static void +touch_handle_cancel(void *data, struct wl_touch *wl_touch) +{ + struct xwl_seat *xwl_seat = data; + struct xwl_touch *xwl_touch, *next_xwl_touch; + + xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch, + &xwl_seat->touches, link_touch) { + /* We can't properly notify of cancellation to the X client + * once it thinks it has the ownership, send at least a + * TouchEnd event. + */ + xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchEnd); + xorg_list_del(&xwl_touch->link_touch); + free(xwl_touch); + } +} + +static const struct wl_touch_listener touch_listener = { + touch_handle_down, + touch_handle_up, + touch_handle_motion, + touch_handle_frame, + touch_handle_cancel +}; + static DeviceIntPtr add_device(struct xwl_seat *xwl_seat, const char *driver, DeviceProc device_proc) @@ -548,8 +726,26 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, DisableDevice(xwl_seat->keyboard, TRUE); } + if (caps & WL_SEAT_CAPABILITY_TOUCH && xwl_seat->wl_touch == NULL) { + xwl_seat->wl_touch = wl_seat_get_touch(seat); + wl_touch_add_listener(xwl_seat->wl_touch, + &touch_listener, xwl_seat); + + if (xwl_seat->touch) + EnableDevice(xwl_seat->touch, TRUE); + else { + xwl_seat->touch = + add_device(xwl_seat, "xwayland-touch", xwl_touch_proc); + } + } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && xwl_seat->wl_touch) { + wl_touch_release(xwl_seat->wl_touch); + xwl_seat->wl_touch = NULL; + + if (xwl_seat->touch) + DisableDevice(xwl_seat->touch, TRUE); + } + xwl_seat->xwl_screen->expecting_event--; - /* FIXME: Touch ... */ } static void diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 3c10862e0..857650edc 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -116,10 +116,12 @@ struct xwl_touch { struct xwl_seat { DeviceIntPtr pointer; DeviceIntPtr keyboard; + DeviceIntPtr touch; struct xwl_screen *xwl_screen; struct wl_seat *seat; struct wl_pointer *wl_pointer; struct wl_keyboard *wl_keyboard; + struct wl_touch *wl_touch; struct wl_array keys; struct xwl_window *focus_window; uint32_t id; From 44f250a7e8eb86d3f41da5d186d839e7a14648a3 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 27 May 2015 18:42:00 +0200 Subject: [PATCH 4/8] xwayland: Remove related touchpoints when unrealizing windows These sequences are forgotten to all purposes. Signed-off-by: Carlos Garnacho Reviewed-by: Olivier Fourdan --- hw/xwayland/xwayland-input.c | 14 ++++++++++++++ hw/xwayland/xwayland.c | 6 +++--- hw/xwayland/xwayland.h | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index ef38e6af9..d26a7863a 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -844,6 +844,20 @@ DDXRingBell(int volume, int pitch, int duration) { } +void +xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window) +{ + struct xwl_touch *xwl_touch, *next_xwl_touch; + + xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch, + &xwl_seat->touches, link_touch) { + if (xwl_touch->window->window == window) { + xorg_list_del(&xwl_touch->link_touch); + free(xwl_touch); + } + } +} + void InitInput(int argc, char *argv[]) { diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index bc92beb38..f25bc006b 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -287,10 +287,10 @@ xwl_unrealize_window(WindowPtr window) xwl_screen = xwl_screen_get(screen); xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { - if (!xwl_seat->focus_window) - continue; - if (xwl_seat->focus_window->window == window) + if (xwl_seat->focus_window && xwl_seat->focus_window->window == window) xwl_seat->focus_window = NULL; + + xwl_seat_clear_touch(xwl_seat, window); } screen->UnrealizeWindow = xwl_screen->UnrealizeWindow; diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 857650edc..53ca420cf 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -159,6 +159,8 @@ void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); void xwl_seat_destroy(struct xwl_seat *xwl_seat); +void xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window); + Bool xwl_screen_init_output(struct xwl_screen *xwl_screen); struct xwl_output *xwl_output_create(struct xwl_screen *xwl_screen, From f1ba8858d5baa63cde6361492e6d349ce1b38d21 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 28 Aug 2015 14:28:09 +1000 Subject: [PATCH 5/8] xwayland: use the device pointer we already have No functional changes. Signed-off-by: Peter Hutterer Reviewed-by: Olivier Fourdan --- hw/xwayland/xwayland-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index d26a7863a..143a801e5 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -246,7 +246,7 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, valuator_mask_zero(&mask); for (i = 0; i < dev->button->numButtons; i++) if (BitIsOn(dev->button->down, i)) - QueuePointerEvents(xwl_seat->pointer, ButtonRelease, i, 0, &mask); + QueuePointerEvents(dev, ButtonRelease, i, 0, &mask); } static void From 373599ab008f0ecf8f3fb62455a5474f5ec8f499 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 28 Aug 2015 14:28:10 +1000 Subject: [PATCH 6/8] xwayland: fix crash on enter/leave for a grabbed slave device When grabbed, the slave device is floating, i.e. the master device is NULL. CheckMotion() isn't happy with NULL. Make sure we pass the right device in, either the master device when the device is attached, or the device itself when it is floating. Reported-by: Jason Gerecke Signed-off-by: Peter Hutterer Reviewed-by: Olivier Fourdan --- hw/xwayland/xwayland-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 143a801e5..a29ba782f 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -231,7 +231,7 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, xwl_seat->focus_window = wl_surface_get_user_data(surface); (*pScreen->SetCursorPosition) (dev, pScreen, sx, sy, TRUE); - CheckMotion(NULL, GetMaster(dev, MASTER_POINTER)); + CheckMotion(NULL, GetMaster(dev, POINTER_OR_FLOAT)); /* Ideally, X clients shouldn't see these button releases. When * the pointer leaves a window with buttons down, it means that @@ -259,7 +259,7 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer, xwl_seat->xwl_screen->serial = serial; xwl_seat->focus_window = NULL; - CheckMotion(NULL, GetMaster(dev, MASTER_POINTER)); + CheckMotion(NULL, GetMaster(dev, POINTER_OR_FLOAT)); } static void From f1995de1c43733a9e586605674c4071357a58e78 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 28 Aug 2015 14:28:11 +1000 Subject: [PATCH 7/8] xwayland: call through to miPointerWarpCursor on warp_cursor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is (eventually) called during InitializeSprite() → *pScreen->SetCursorPosition → miPointerSetCursorPosition when a device is set to floating. We don't do anything special outselves, but we need to pass on to the next layer to make sure the device is initialized properly. Otherwise, pScreen stays NULL and eventually crashes the server when we try to clean up behind us. Test case: grab a device → floats it, ungrab again → crash Reported-by: Jason Gerecke Signed-off-by: Peter Hutterer Reviewed-by: Olivier Fourdan --- hw/xwayland/xwayland-cursor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index c137e1ec0..76729db9e 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -199,6 +199,7 @@ xwl_cross_screen(ScreenPtr pScreen, Bool entering) static void xwl_pointer_warp_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) { + miPointerWarpCursor(pDev, pScreen, x, y); } static miPointerScreenFuncRec xwl_pointer_screen_funcs = { From 1ba4fde1015fc6da19dfbfdf0f77f1071416e215 Mon Sep 17 00:00:00 2001 From: Boyan Ding Date: Mon, 4 Aug 2014 21:16:34 +0800 Subject: [PATCH 8/8] xwayland: Activate and enable device on first capability reporting Commit 2172714c changed behavior of capability handling, but it only solved part of the problem. If Xwayland is launched without a capability (e.g. no pointer device is connected when Xwayland was spinned up), and later that capability comes, the device added will not be automatically initialized. This patch initializes the device when the capability is reported for the first time, thus avoiding the problem. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=81819 Signed-off-by: Boyan Ding Reviewed-by: Daniel Stone --- hw/xwayland/xwayland-input.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index a29ba782f..010d28c43 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -692,13 +692,13 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, wl_pointer_add_listener(xwl_seat->wl_pointer, &pointer_listener, xwl_seat); - if (xwl_seat->pointer) - EnableDevice(xwl_seat->pointer, TRUE); - else { + if (xwl_seat->pointer == NULL) { xwl_seat_set_cursor(xwl_seat); xwl_seat->pointer = add_device(xwl_seat, "xwayland-pointer", xwl_pointer_proc); + ActivateDevice(xwl_seat->pointer, TRUE); } + EnableDevice(xwl_seat->pointer, TRUE); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && xwl_seat->wl_pointer) { wl_pointer_release(xwl_seat->wl_pointer); xwl_seat->wl_pointer = NULL; @@ -712,12 +712,12 @@ seat_handle_capabilities(void *data, struct wl_seat *seat, wl_keyboard_add_listener(xwl_seat->wl_keyboard, &keyboard_listener, xwl_seat); - if (xwl_seat->keyboard) - EnableDevice(xwl_seat->keyboard, TRUE); - else { + if (xwl_seat->keyboard == NULL) { xwl_seat->keyboard = add_device(xwl_seat, "xwayland-keyboard", xwl_keyboard_proc); + ActivateDevice(xwl_seat->keyboard, TRUE); } + EnableDevice(xwl_seat->keyboard, TRUE); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && xwl_seat->wl_keyboard) { wl_keyboard_release(xwl_seat->wl_keyboard); xwl_seat->wl_keyboard = NULL;