diff --git a/cage-vi/.SRCINFO b/cage-vi/.SRCINFO index 1ae3fb5..7f2e870 100644 --- a/cage-vi/.SRCINFO +++ b/cage-vi/.SRCINFO @@ -1,6 +1,6 @@ pkgbase = cage-vi pkgdesc = A Wayland kiosk, with virtual input patch applied - pkgver = 0.1.4+39+ga81ab70 + pkgver = 0.1.4+54+gbd5b20e pkgrel = 1 url = https://www.hjdskes.nl/projects/cage/ arch = x86_64 @@ -18,10 +18,8 @@ pkgbase = cage-vi provides = cage conflicts = cage source = https://github.com/Hjdskes/cage/releases/download/v0.1.4/cage-0.1.4.tar.gz - source = a81ab70.patch - source = virtual_input.patch + source = bd5b20e.patch sha256sums = dfe27fb0c7d43db72d6c82f01e2736580a0791a23ba69d7b56285d08af98ad90 - sha256sums = 8580568cc9b68b33de206a841e2110be14de730356c504b66fe366912d0abf76 - sha256sums = 352a3f33c2690a401c90c4de668d38e4cdff53db6c2fc9577a7c607d8a9ec369 + sha256sums = b3608b082c8859433158377ec875ee17ca72f10d61d8827eb5b1c2e01771c0ce pkgname = cage-vi diff --git a/cage-vi/PKGBUILD b/cage-vi/PKGBUILD index f1f4453..ad82ad2 100644 --- a/cage-vi/PKGBUILD +++ b/cage-vi/PKGBUILD @@ -1,6 +1,6 @@ pkgname=cage-vi _pkgname=${pkgname%%-*} -pkgver=0.1.4+39+ga81ab70 +pkgver=0.1.4+54+gbd5b20e _pkgver=${pkgver%%+*} pkgrel=1 pkgdesc='A Wayland kiosk, with virtual input patch applied' @@ -17,19 +17,20 @@ provides=("${_pkgname}") conflicts=("${_pkgname}") source=( "https://github.com/Hjdskes/${_pkgname}/releases/download/v${_pkgver}/${_pkgname}-${_pkgver}.tar.gz" - 'a81ab70.patch' - 'virtual_input.patch' -) -sha256sums=( - 'dfe27fb0c7d43db72d6c82f01e2736580a0791a23ba69d7b56285d08af98ad90' - '8580568cc9b68b33de206a841e2110be14de730356c504b66fe366912d0abf76' - '352a3f33c2690a401c90c4de668d38e4cdff53db6c2fc9577a7c607d8a9ec369' + 'bd5b20e.patch' ) +sha256sums=('dfe27fb0c7d43db72d6c82f01e2736580a0791a23ba69d7b56285d08af98ad90' + 'b3608b082c8859433158377ec875ee17ca72f10d61d8827eb5b1c2e01771c0ce') + +#pkgver() { +# cd "${srcdir}/${_pkgname}-${_pkgver}" +# git describe --long --tags | sed 's/^v//;s/-/+/g' +#} + prepare() { cd "${srcdir}/${_pkgname}-${_pkgver}" - patch -Np1 -i '../a81ab70.patch' - patch -Np1 -i '../virtual_input.patch' + patch -Np1 -i '../bd5b20e.patch' meson --buildtype=release -Dxwayland=true --prefix /usr "$srcdir/build" } diff --git a/cage-vi/a81ab70.patch b/cage-vi/bd5b20e.patch similarity index 68% rename from cage-vi/a81ab70.patch rename to cage-vi/bd5b20e.patch index 6939578..d59ba45 100644 --- a/cage-vi/a81ab70.patch +++ b/cage-vi/bd5b20e.patch @@ -143,7 +143,7 @@ index 0000000..60dd059 \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 -index 0000000..5e95347 +index 0000000..a98291a --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,76 @@ @@ -171,7 +171,7 @@ index 0000000..5e95347 + + - name: Install dependencies (Alpine) + if: "matrix.OS == 'alpine:edge'" -+ run: apk add build-base xcb-util-wm-dev libseat-dev clang git eudev-dev mesa-dev libdrm-dev libinput-dev libxkbcommon-dev pixman-dev wayland-dev meson wayland-protocols xwayland scdoc-doc ++ run: apk add build-base xcb-util-wm-dev libseat-dev clang git eudev-dev mesa-dev libdrm-dev libinput-dev libxkbcommon-dev pixman-dev wayland-dev meson wayland-protocols xwayland scdoc-doc hwdata + + - name: Install dependencies (Arch) + if: "matrix.OS == 'archlinux:base-devel'" @@ -180,7 +180,7 @@ index 0000000..5e95347 + pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc + + - name: Fetch wlroots as a subproject -+ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0 ++ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 + + # TODO: use --fatal-meson-warnings when on wlroots 0.15.0 + - name: Compile Cage (XWayland=${{ matrix.xwayland }}) @@ -197,9 +197,9 @@ index 0000000..5e95347 + - name: Install dependencies + run: | + pacman-key --init -+ pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc ++ pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata + - name: Fetch wlroots as a subproject -+ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0 ++ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 + - name: Check for formatting changes + run: | + meson build-clang-format -Dxwayland=true @@ -216,15 +216,25 @@ index 0000000..5e95347 + - name: Install dependencies + run: | + pacman-key --init -+ pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc ++ pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata + - name: Fetch wlroots as a subproject -+ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0 ++ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 + - name: Run scan-build + run: | + meson build-scan-build -Dxwayland=true + ninja -C build-scan-build scan-build +diff --git a/README.md b/README.md +index e1b6f56..752387e 100644 +--- a/README.md ++++ b/README.md +@@ -1,4 +1,4 @@ +-# Cage: a Wayland kiosk [![builds.sr.ht status](https://builds.sr.ht/~hjdskes.svg)](https://builds.sr.ht/~hjdskes?) ++# Cage: a Wayland kiosk + + Cage's logo + diff --git a/cage.c b/cage.c -index 5392535..95f0cc7 100644 +index 5392535..c5eda4d 100644 --- a/cage.c +++ b/cage.c @@ -19,6 +19,7 @@ @@ -235,7 +245,7 @@ index 5392535..95f0cc7 100644 #include #include #include -@@ -27,8 +28,11 @@ +@@ -27,8 +28,15 @@ #include #include #include @@ -243,11 +253,28 @@ index 5392535..95f0cc7 100644 +#include #include #include ++#include ++#include +#include ++#include ++#include #if CAGE_HAS_XWAYLAND #include #endif -@@ -185,9 +189,6 @@ usage(FILE *file, const char *cage) +@@ -145,7 +153,12 @@ cleanup_primary_client(pid_t pid) + static bool + drop_permissions(void) + { ++ if (getuid() == 0 || getgid() == 0) { ++ wlr_log(WLR_INFO, "Running as root user, this is dangerous"); ++ return true; ++ } + if (getuid() != geteuid() || getgid() != getegid()) { ++ wlr_log(WLR_INFO, "setuid/setgid bit detected, dropping permissions"); + // Set the gid and uid in the correct order. + if (setgid(getgid()) != 0 || setuid(getuid()) != 0) { + wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); +@@ -185,9 +198,6 @@ usage(FILE *file, const char *cage) "Usage: %s [OPTIONS] [--] APPLICATION\n" "\n" " -d\t Don't draw client side decorations, when possible\n" @@ -257,7 +284,7 @@ index 5392535..95f0cc7 100644 " -h\t Display this help message\n" " -m extend Extend the display across all connected outputs (default)\n" " -m last Use only the last connected output\n" -@@ -203,20 +204,11 @@ static bool +@@ -203,20 +213,11 @@ static bool parse_args(struct cg_server *server, int argc, char *argv[]) { int c; @@ -278,24 +305,29 @@ index 5392535..95f0cc7 100644 case 'h': usage(stdout, argv[0]); return false; -@@ -261,7 +253,6 @@ main(int argc, char *argv[]) +@@ -261,15 +262,20 @@ main(int argc, char *argv[]) struct wl_event_source *sigint_source = NULL; struct wl_event_source *sigterm_source = NULL; struct wl_event_source *sigchld_source = NULL; - struct wlr_renderer *renderer = NULL; struct wlr_compositor *compositor = NULL; ++ struct wlr_subcompositor *subcompositor = NULL; struct wlr_data_device_manager *data_device_manager = NULL; struct wlr_server_decoration_manager *server_decoration_manager = NULL; -@@ -270,6 +261,8 @@ main(int argc, char *argv[]) + struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; + struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL; struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; ++ struct wlr_single_pixel_buffer_manager_v1 *single_pixel_buffer = NULL; struct wlr_xdg_output_manager_v1 *output_manager = NULL; struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; ++ struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard = NULL; ++ struct wlr_virtual_pointer_manager_v1 *virtual_pointer = NULL; + struct wlr_viewporter *viewporter = NULL; + struct wlr_presentation *presentation = NULL; struct wlr_xdg_shell *xdg_shell = NULL; #if CAGE_HAS_XWAYLAND struct wlr_xwayland *xwayland = NULL; -@@ -316,8 +309,21 @@ main(int argc, char *argv[]) +@@ -316,8 +322,21 @@ main(int argc, char *argv[]) goto end; } @@ -319,7 +351,7 @@ index 5392535..95f0cc7 100644 wl_list_init(&server.views); wl_list_init(&server.outputs); -@@ -329,7 +335,16 @@ main(int argc, char *argv[]) +@@ -329,13 +348,29 @@ main(int argc, char *argv[]) goto end; } @@ -337,7 +369,29 @@ index 5392535..95f0cc7 100644 if (!compositor) { wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); ret = 1; -@@ -401,6 +416,21 @@ main(int argc, char *argv[]) + goto end; + } + ++ subcompositor = wlr_subcompositor_create(server.wl_display); ++ if (!subcompositor) { ++ wlr_log(WLR_ERROR, "Unable to create the wlroots subcompositor"); ++ ret = 1; ++ goto end; ++ } ++ + data_device_manager = wlr_data_device_manager_create(server.wl_display); + if (!data_device_manager) { + wlr_log(WLR_ERROR, "Unable to create the data device manager"); +@@ -373,7 +408,7 @@ main(int argc, char *argv[]) + wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1); + wl_list_init(&server.inhibitors); + +- xdg_shell = wlr_xdg_shell_create(server.wl_display); ++ xdg_shell = wlr_xdg_shell_create(server.wl_display, 4); + if (!xdg_shell) { + wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); + ret = 1; +@@ -401,6 +436,21 @@ main(int argc, char *argv[]) server_decoration_manager, server.xdg_decoration ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); @@ -359,8 +413,57 @@ index 5392535..95f0cc7 100644 export_dmabuf_manager = wlr_export_dmabuf_manager_v1_create(server.wl_display); if (!export_dmabuf_manager) { wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); +@@ -415,6 +465,13 @@ main(int argc, char *argv[]) + goto end; + } + ++ single_pixel_buffer = wlr_single_pixel_buffer_manager_v1_create(server.wl_display); ++ if (!single_pixel_buffer) { ++ wlr_log(WLR_ERROR, "Unable to create the single pixel buffer manager"); ++ ret = 1; ++ goto end; ++ } ++ + output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout); + if (!output_manager) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); +@@ -429,6 +486,22 @@ main(int argc, char *argv[]) + goto end; + } + ++ virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(server.wl_display); ++ if (!virtual_keyboard) { ++ wlr_log(WLR_ERROR, "Unable to create the virtual keyboard manager"); ++ ret = 1; ++ goto end; ++ } ++ wl_signal_add(&virtual_keyboard->events.new_virtual_keyboard, &server.new_virtual_keyboard); ++ ++ virtual_pointer = wlr_virtual_pointer_manager_v1_create(server.wl_display); ++ if (!virtual_pointer) { ++ wlr_log(WLR_ERROR, "Unable to create the virtual pointer manager"); ++ ret = 1; ++ goto end; ++ } ++ wl_signal_add(&virtual_pointer->events.new_virtual_pointer, &server.new_virtual_pointer); ++ + #if CAGE_HAS_XWAYLAND + xwayland = wlr_xwayland_create(server.wl_display, compositor, true); + if (!xwayland) { +@@ -492,8 +565,9 @@ main(int argc, char *argv[]) + } + + /* Place the cursor in the center of the output layout. */ +- struct wlr_box *layout_box = wlr_output_layout_get_box(server.output_layout, NULL); +- wlr_cursor_warp(server.seat->cursor, NULL, layout_box->width / 2, layout_box->height / 2); ++ struct wlr_box layout_box; ++ wlr_output_layout_get_box(server.output_layout, NULL, &layout_box); ++ wlr_cursor_warp(server.seat->cursor, NULL, layout_box.width / 2, layout_box.height / 2); + + wl_display_run(server.wl_display); + diff --git a/meson.build b/meson.build -index 3a84794..5a8b28c 100644 +index 3a84794..fbd7e16 100644 --- a/meson.build +++ b/meson.build @@ -1,16 +1,17 @@ @@ -388,7 +491,7 @@ index 3a84794..5a8b28c 100644 endif -wlroots = dependency('wlroots', version: '>= 0.14.0') -+wlroots = dependency('wlroots', version: '>= 0.15.0', fallback: ['wlroots', 'wlroots']) ++wlroots = dependency('wlroots', version: '>= 0.16.0', fallback: ['wlroots', 'wlroots']) wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') -pixman = dependency('pixman-1') @@ -474,7 +577,7 @@ index 3a84794..5a8b28c 100644 ], install: true, diff --git a/output.c b/output.c -index d8da3b9..c33bbe1 100644 +index d8da3b9..6eca0db 100644 --- a/output.c +++ b/output.c @@ -1,7 +1,7 @@ @@ -494,12 +597,18 @@ index d8da3b9..c33bbe1 100644 #include #include #include -@@ -26,216 +27,20 @@ +@@ -21,221 +22,25 @@ + #include + #endif + #include ++#include + #include + #include #include #include #include +-#include +#include - #include #include #include #include @@ -1187,53 +1296,44 @@ index 085b00b..0000000 - -#endif diff --git a/seat.c b/seat.c -index 08f25a3..4dce511 100644 +index 08f25a3..5d80e33 100644 --- a/seat.c +++ b/seat.c -@@ -8,6 +8,7 @@ +@@ -6,10 +6,14 @@ + * See the LICENSE file accompanying this file. + */ ++#define _POSIX_C_SOURCE 200809L ++ #include "config.h" +#include #include #include ++#include #include -@@ -18,6 +19,7 @@ + #include + #include +@@ -18,9 +22,11 @@ #include #include #include +#include #include - #include +-#include #include -@@ -41,42 +43,31 @@ static void drag_icon_update_position(struct cg_drag_icon *drag_icon); ++#include ++#include + #include + #include + #if CAGE_HAS_XWAYLAND +@@ -41,42 +47,42 @@ static void drag_icon_update_position(struct cg_drag_icon *drag_icon); * menus or tooltips. This function tests if any of those are underneath the * coordinates lx and ly (in output Layout Coordinates). If so, it sets the * surface pointer to that wlr_surface and the sx and sy coordinates to the - * coordinates relative to that surface's top-left corner. */ -static bool -view_at(struct cg_view *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) --{ -- double view_sx = lx - view->lx; -- double view_sy = ly - view->ly; -- -- double _sx, _sy; -- struct wlr_surface *_surface = view_wlr_surface_at(view, view_sx, view_sy, &_sx, &_sy); -- if (_surface != NULL) { -- *sx = _sx; -- *sy = _sy; -- *surface = _surface; -- return true; -- } -- -- return false; --} -- --/* This iterates over all of our surfaces and attempts to find one -- * under the cursor. This relies on server->views being ordered from -- * top-to-bottom. If desktop_view_at returns a view, there is also a -- * surface. There cannot be a surface without a view, either. It's -- * both or nothing. */ + * coordinates relative to that surface's top-left corner. + * + * This function iterates over all of our surfaces and attempts to find one @@ -1241,34 +1341,297 @@ index 08f25a3..4dce511 100644 + * surface. There cannot be a surface without a view, either. It's both or + * nothing. + */ - static struct cg_view * - desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) ++static struct cg_view * ++desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { -- struct cg_view *view; -+ struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->node, lx, ly, sx, sy); -+ if (node == NULL || node->type != WLR_SCENE_NODE_SURFACE) { +- double view_sx = lx - view->lx; +- double view_sy = ly - view->ly; ++ struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy); ++ if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) { + return NULL; + } +- double _sx, _sy; +- struct wlr_surface *_surface = view_wlr_surface_at(view, view_sx, view_sy, &_sx, &_sy); +- if (_surface != NULL) { +- *sx = _sx; +- *sy = _sy; +- *surface = _surface; +- return true; ++ struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); ++ struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_buffer(scene_buffer); ++ if (!scene_surface) { ++ return NULL; + } + +- return false; +-} ++ *surface = scene_surface->surface; + +-/* This iterates over all of our surfaces and attempts to find one +- * under the cursor. This relies on server->views being ordered from +- * top-to-bottom. If desktop_view_at returns a view, there is also a +- * surface. There cannot be a surface without a view, either. It's +- * both or nothing. */ +-static struct cg_view * +-desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) +-{ +- struct cg_view *view; +- - wl_list_for_each (view, &server->views, link) { - if (view_at(view, lx, ly, surface, sx, sy)) { - return view; -- } -+ *surface = wlr_scene_surface_from_node(node)->surface; -+ + /* Walk up the tree until we find a node with a data pointer. When done, + * we've found the node representing the view. */ -+ while (node != NULL && node->data == NULL) { -+ node = node->parent; ++ while (!node->data) { ++ if (!node->parent) { ++ node = NULL; ++ break; + } ++ ++ node = &node->parent->node; } -+ assert(node != NULL); - return NULL; ++ assert(node != NULL); + return node->data; } static void -@@ -351,17 +342,11 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) +@@ -127,16 +133,16 @@ update_capabilities(struct cg_seat *seat) + } + + static void +-map_input_device_to_output(struct cg_seat *seat, struct wlr_input_device *device) ++map_input_device_to_output(struct cg_seat *seat, struct wlr_input_device *device, const char *output_name) + { +- if (!device->output_name) { ++ if (!output_name) { + wlr_log(WLR_INFO, "Input device %s cannot be mapped to an output device\n", device->name); + return; + } + + struct cg_output *output; + wl_list_for_each (output, &seat->server->outputs, link) { +- if (strcmp(device->output_name, output->wlr_output->name) == 0) { ++ if (strcmp(output_name, output->wlr_output->name) == 0) { + wlr_log(WLR_INFO, "Mapping input device %s to output device %s\n", device->name, + output->wlr_output->name); + wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); +@@ -154,7 +160,7 @@ handle_touch_destroy(struct wl_listener *listener, void *data) + struct cg_seat *seat = touch->seat; + + wl_list_remove(&touch->link); +- wlr_cursor_detach_input_device(seat->cursor, touch->device); ++ wlr_cursor_detach_input_device(seat->cursor, &touch->touch->base); + wl_list_remove(&touch->destroy.link); + free(touch); + +@@ -162,7 +168,7 @@ handle_touch_destroy(struct wl_listener *listener, void *data) + } + + static void +-handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) ++handle_new_touch(struct cg_seat *seat, struct wlr_touch *wlr_touch) + { + struct cg_touch *touch = calloc(1, sizeof(struct cg_touch)); + if (!touch) { +@@ -171,14 +177,14 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) + } + + touch->seat = seat; +- touch->device = device; +- wlr_cursor_attach_input_device(seat->cursor, device); ++ touch->touch = wlr_touch; ++ wlr_cursor_attach_input_device(seat->cursor, &wlr_touch->base); + + wl_list_insert(&seat->touch, &touch->link); + touch->destroy.notify = handle_touch_destroy; +- wl_signal_add(&touch->device->events.destroy, &touch->destroy); ++ wl_signal_add(&wlr_touch->base.events.destroy, &touch->destroy); + +- map_input_device_to_output(seat, device); ++ map_input_device_to_output(seat, &wlr_touch->base, wlr_touch->output_name); + } + + static void +@@ -188,7 +194,7 @@ handle_pointer_destroy(struct wl_listener *listener, void *data) + struct cg_seat *seat = pointer->seat; + + wl_list_remove(&pointer->link); +- wlr_cursor_detach_input_device(seat->cursor, pointer->device); ++ wlr_cursor_detach_input_device(seat->cursor, &pointer->pointer->base); + wl_list_remove(&pointer->destroy.link); + free(pointer); + +@@ -196,7 +202,7 @@ handle_pointer_destroy(struct wl_listener *listener, void *data) + } + + static void +-handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) ++handle_new_pointer(struct cg_seat *seat, struct wlr_pointer *wlr_pointer) + { + struct cg_pointer *pointer = calloc(1, sizeof(struct cg_pointer)); + if (!pointer) { +@@ -205,21 +211,42 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) + } + + pointer->seat = seat; +- pointer->device = device; +- wlr_cursor_attach_input_device(seat->cursor, device); ++ pointer->pointer = wlr_pointer; ++ wlr_cursor_attach_input_device(seat->cursor, &wlr_pointer->base); + + wl_list_insert(&seat->pointers, &pointer->link); + pointer->destroy.notify = handle_pointer_destroy; +- wl_signal_add(&device->events.destroy, &pointer->destroy); ++ wl_signal_add(&wlr_pointer->base.events.destroy, &pointer->destroy); ++ ++ map_input_device_to_output(seat, &wlr_pointer->base, wlr_pointer->output_name); ++} + +- map_input_device_to_output(seat, device); ++static void ++handle_virtual_pointer(struct wl_listener *listener, void *data) ++{ ++ struct cg_server *server = wl_container_of(listener, server, new_virtual_pointer); ++ struct cg_seat *seat = server->seat; ++ struct wlr_virtual_pointer_v1_new_pointer_event *event = data; ++ struct wlr_virtual_pointer_v1 *pointer = event->new_pointer; ++ struct wlr_pointer *wlr_pointer = &pointer->pointer; ++ ++ /* We'll want to map the device back to an output later, this is a bit ++ * sub-optimal (we could just keep the suggested_output), but just copy ++ * its name so we do like other devices ++ */ ++ if (event->suggested_output != NULL) { ++ wlr_pointer->output_name = strdup(event->suggested_output->name); ++ } ++ /* TODO: event->suggested_seat should be checked if we handle multiple seats */ ++ handle_new_pointer(seat, wlr_pointer); ++ update_capabilities(seat); + } + + static void +-handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) ++handle_modifier_event(struct wlr_keyboard *keyboard, struct cg_seat *seat) + { +- wlr_seat_set_keyboard(seat->seat, device); +- wlr_seat_keyboard_notify_modifiers(seat->seat, &device->keyboard->modifiers); ++ wlr_seat_set_keyboard(seat->seat, keyboard); ++ wlr_seat_keyboard_notify_modifiers(seat->seat, &keyboard->modifiers); + + wlr_idle_notify_activity(seat->server->idle, seat->seat); + } +@@ -249,18 +276,18 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) + } + + static void +-handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *data) ++handle_key_event(struct wlr_keyboard *keyboard, struct cg_seat *seat, void *data) + { +- struct wlr_event_keyboard_key *event = data; ++ struct wlr_keyboard_key_event *event = data; + + /* Translate from libinput keycode to an xkbcommon keycode. */ + xkb_keycode_t keycode = event->keycode + 8; + + const xkb_keysym_t *syms; +- int nsyms = xkb_state_key_get_syms(device->keyboard->xkb_state, keycode, &syms); ++ int nsyms = xkb_state_key_get_syms(keyboard->xkb_state, keycode, &syms); + + bool handled = false; +- uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); ++ uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard); + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + /* If Alt is held down and this button was pressed, we + * attempt to process it as a compositor +@@ -272,7 +299,7 @@ handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *da + + if (!handled) { + /* Otherwise, we pass it along to the client. */ +- wlr_seat_set_keyboard(seat->seat, device); ++ wlr_seat_set_keyboard(seat->seat, keyboard); + wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); + } + +@@ -283,27 +310,32 @@ static void + handle_keyboard_group_key(struct wl_listener *listener, void *data) + { + struct cg_keyboard_group *cg_group = wl_container_of(listener, cg_group, key); +- handle_key_event(cg_group->wlr_group->input_device, cg_group->seat, data); ++ handle_key_event(&cg_group->wlr_group->keyboard, cg_group->seat, data); + } + + static void + handle_keyboard_group_modifiers(struct wl_listener *listener, void *data) + { + struct cg_keyboard_group *group = wl_container_of(listener, group, modifiers); +- handle_modifier_event(group->wlr_group->input_device, group->seat); ++ handle_modifier_event(&group->wlr_group->keyboard, group->seat); + } + + static void +-cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) ++cg_keyboard_group_add(struct wlr_keyboard *keyboard, struct cg_seat *seat, bool virtual) + { +- struct wlr_keyboard *wlr_keyboard = device->keyboard; +- +- struct cg_keyboard_group *group; +- wl_list_for_each (group, &seat->keyboard_groups, link) { +- struct wlr_keyboard_group *wlr_group = group->wlr_group; +- if (wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard)) { +- wlr_log(WLR_DEBUG, "Added new keyboard to existing group"); +- return; ++ /* We apparently should not group virtual keyboards, ++ * so create a new group with it ++ */ ++ if (!virtual) { ++ struct cg_keyboard_group *group; ++ wl_list_for_each (group, &seat->keyboard_groups, link) { ++ if (group->is_virtual) ++ continue; ++ struct wlr_keyboard_group *wlr_group = group->wlr_group; ++ if (wlr_keyboard_group_add_keyboard(wlr_group, keyboard)) { ++ wlr_log(WLR_DEBUG, "Added new keyboard to existing group"); ++ return; ++ } + } + } + +@@ -315,6 +347,7 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) + return; + } + cg_group->seat = seat; ++ cg_group->is_virtual = virtual; + cg_group->wlr_group = wlr_keyboard_group_create(); + if (cg_group->wlr_group == NULL) { + wlr_log(WLR_ERROR, "Failed to create wlr keyboard group."); +@@ -322,14 +355,14 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) + } + + cg_group->wlr_group->data = cg_group; +- wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, device->keyboard->keymap); ++ wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, keyboard->keymap); + +- wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, wlr_keyboard->repeat_info.rate, +- wlr_keyboard->repeat_info.delay); ++ wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, keyboard->repeat_info.rate, ++ keyboard->repeat_info.delay); + + wlr_log(WLR_DEBUG, "Created keyboard group"); + +- wlr_keyboard_group_add_keyboard(cg_group->wlr_group, wlr_keyboard); ++ wlr_keyboard_group_add_keyboard(cg_group->wlr_group, keyboard); + wl_list_insert(&seat->keyboard_groups, &cg_group->link); + + wl_signal_add(&cg_group->wlr_group->keyboard.events.key, &cg_group->key); +@@ -347,36 +380,45 @@ cleanup: + } + + static void +-handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) ++handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard, bool virtual) { struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -1288,7 +1651,136 @@ index 08f25a3..4dce511 100644 if (!keymap) { wlr_log(WLR_ERROR, "Unable to configure keyboard: keymap does not exist"); xkb_context_unref(context); -@@ -569,10 +554,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) + return; + } + +- wlr_keyboard_set_keymap(device->keyboard, keymap); ++ wlr_keyboard_set_keymap(keyboard, keymap); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); +- wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); ++ wlr_keyboard_set_repeat_info(keyboard, 25, 600); ++ ++ cg_keyboard_group_add(keyboard, seat, virtual); ++ ++ wlr_seat_set_keyboard(seat->seat, keyboard); ++} + +- cg_keyboard_group_add(device, seat); ++static void ++handle_virtual_keyboard(struct wl_listener *listener, void *data) ++{ ++ struct cg_server *server = wl_container_of(listener, server, new_virtual_keyboard); ++ struct cg_seat *seat = server->seat; ++ struct wlr_virtual_keyboard_v1 *keyboard = data; ++ struct wlr_keyboard *wlr_keyboard = &keyboard->keyboard; ++ ++ /* TODO: If multiple seats are supported, check keyboard->seat ++ * to select the appropriate one */ + +- wlr_seat_set_keyboard(seat->seat, device); ++ handle_new_keyboard(seat, wlr_keyboard, true); ++ update_capabilities(seat); + } + + static void +@@ -387,13 +429,13 @@ handle_new_input(struct wl_listener *listener, void *data) + + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: +- handle_new_keyboard(seat, device); ++ handle_new_keyboard(seat, wlr_keyboard_from_input_device(device), false); + break; + case WLR_INPUT_DEVICE_POINTER: +- handle_new_pointer(seat, device); ++ handle_new_pointer(seat, wlr_pointer_from_input_device(device)); + break; + case WLR_INPUT_DEVICE_TOUCH: +- handle_new_touch(seat, device); ++ handle_new_touch(seat, wlr_touch_from_input_device(device)); + break; + case WLR_INPUT_DEVICE_SWITCH: + wlr_log(WLR_DEBUG, "Switch input is not implemented"); +@@ -448,10 +490,10 @@ static void + handle_touch_down(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, touch_down); +- struct wlr_event_touch_down *event = data; ++ struct wlr_touch_down_event *event = data; + + double lx, ly; +- wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); ++ wlr_cursor_absolute_to_layout_coords(seat->cursor, &event->touch->base, event->x, event->y, &lx, &ly); + + double sx, sy; + struct wlr_surface *surface; +@@ -466,7 +508,7 @@ handle_touch_down(struct wl_listener *listener, void *data) + seat->touch_id = event->touch_id; + seat->touch_lx = lx; + seat->touch_ly = ly; +- press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); ++ press_cursor_button(seat, &event->touch->base, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); + } + + wlr_idle_notify_activity(seat->server->idle, seat->seat); +@@ -476,14 +518,14 @@ static void + handle_touch_up(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, touch_up); +- struct wlr_event_touch_up *event = data; ++ struct wlr_touch_up_event *event = data; + + if (!wlr_seat_touch_get_point(seat->seat, event->touch_id)) { + return; + } + + if (wlr_seat_touch_num_points(seat->seat) == 1) { +- press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED, ++ press_cursor_button(seat, &event->touch->base, event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED, + seat->touch_lx, seat->touch_ly); + } + +@@ -495,14 +537,14 @@ static void + handle_touch_motion(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, touch_motion); +- struct wlr_event_touch_motion *event = data; ++ struct wlr_touch_motion_event *event = data; + + if (!wlr_seat_touch_get_point(seat->seat, event->touch_id)) { + return; + } + + double lx, ly; +- wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); ++ wlr_cursor_absolute_to_layout_coords(seat->cursor, &event->touch->base, event->x, event->y, &lx, &ly); + + double sx, sy; + struct wlr_surface *surface; +@@ -536,7 +578,7 @@ static void + handle_cursor_axis(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, cursor_axis); +- struct wlr_event_pointer_axis *event = data; ++ struct wlr_pointer_axis_event *event = data; + + wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, + event->delta_discrete, event->source); +@@ -547,10 +589,10 @@ static void + handle_cursor_button(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, cursor_button); +- struct wlr_event_pointer_button *event = data; ++ struct wlr_pointer_button_event *event = data; + + wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state); +- press_cursor_button(seat, event->device, event->time_msec, event->button, event->state, seat->cursor->x, ++ press_cursor_button(seat, &event->pointer->base, event->time_msec, event->button, event->state, seat->cursor->x, + seat->cursor->y); + wlr_idle_notify_activity(seat->server->idle, seat->seat); + } +@@ -569,10 +611,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) } else { wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy); @@ -1300,7 +1792,28 @@ index 08f25a3..4dce511 100644 } struct cg_drag_icon *drag_icon; -@@ -605,15 +587,6 @@ handle_cursor_motion(struct wl_listener *listener, void *data) +@@ -587,9 +626,9 @@ static void + handle_cursor_motion_absolute(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_absolute); +- struct wlr_event_pointer_motion_absolute *event = data; ++ struct wlr_pointer_motion_absolute_event *event = data; + +- wlr_cursor_warp_absolute(seat->cursor, event->device, event->x, event->y); ++ wlr_cursor_warp_absolute(seat->cursor, &event->pointer->base, event->x, event->y); + process_cursor_motion(seat, event->time_msec); + wlr_idle_notify_activity(seat->server->idle, seat->seat); + } +@@ -598,22 +637,13 @@ static void + handle_cursor_motion(struct wl_listener *listener, void *data) + { + struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion); +- struct wlr_event_pointer_motion *event = data; ++ struct wlr_pointer_motion_event *event = data; + +- wlr_cursor_move(seat->cursor, event->device, event->delta_x, event->delta_y); ++ wlr_cursor_move(seat->cursor, &event->pointer->base, event->delta_x, event->delta_y); + process_cursor_motion(seat, event->time_msec); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -1316,7 +1829,7 @@ index 08f25a3..4dce511 100644 static void drag_icon_update_position(struct cg_drag_icon *drag_icon) { -@@ -621,8 +594,6 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) +@@ -621,8 +651,6 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) struct cg_seat *seat = drag_icon->seat; struct wlr_touch_point *point; @@ -1325,36 +1838,46 @@ index 08f25a3..4dce511 100644 switch (wlr_icon->drag->grab_type) { case WLR_DRAG_GRAB_KEYBOARD: return; -@@ -640,7 +611,7 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) +@@ -640,7 +668,7 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) break; } - drag_icon_damage(drag_icon); -+ wlr_scene_node_set_position(drag_icon->scene_node, drag_icon->lx, drag_icon->ly); ++ wlr_scene_node_set_position(&drag_icon->scene_tree->node, drag_icon->lx, drag_icon->ly); } static void -@@ -650,6 +621,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) +@@ -650,6 +678,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) wl_list_remove(&drag_icon->link); wl_list_remove(&drag_icon->destroy.link); -+ wlr_scene_node_destroy(drag_icon->scene_node); ++ wlr_scene_node_destroy(&drag_icon->scene_tree->node); free(drag_icon); } -@@ -692,6 +664,11 @@ handle_start_drag(struct wl_listener *listener, void *data) +@@ -692,6 +721,11 @@ handle_start_drag(struct wl_listener *listener, void *data) } drag_icon->seat = seat; drag_icon->wlr_drag_icon = wlr_drag_icon; -+ drag_icon->scene_node = wlr_scene_subsurface_tree_create(&seat->server->scene->node, wlr_drag_icon->surface); -+ if (!drag_icon->scene_node) { ++ drag_icon->scene_tree = wlr_scene_subsurface_tree_create(&seat->server->scene->tree, wlr_drag_icon->surface); ++ if (!drag_icon->scene_tree) { + free(drag_icon); + return; + } drag_icon->destroy.notify = handle_drag_icon_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &drag_icon->destroy); -@@ -840,7 +817,10 @@ struct cg_view * +@@ -812,6 +846,9 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) + seat->new_input.notify = handle_new_input; + wl_signal_add(&backend->events.new_input, &seat->new_input); + ++ server->new_virtual_keyboard.notify = handle_virtual_keyboard; ++ server->new_virtual_pointer.notify = handle_virtual_pointer; ++ + wl_list_init(&seat->drag_icons); + seat->request_start_drag.notify = handle_request_start_drag; + wl_signal_add(&seat->seat->events.request_start_drag, &seat->request_start_drag); +@@ -840,7 +877,10 @@ struct cg_view * seat_get_focus(struct cg_seat *seat) { struct wlr_surface *prev_surface = seat->seat->keyboard_state.focused_surface; @@ -1367,22 +1890,57 @@ index 08f25a3..4dce511 100644 void diff --git a/seat.h b/seat.h -index 188543d..5fb2db3 100644 +index 188543d..52cbee4 100644 --- a/seat.h +++ b/seat.h -@@ -77,6 +77,7 @@ struct cg_drag_icon { +@@ -55,12 +55,13 @@ struct cg_keyboard_group { + struct wl_listener key; + struct wl_listener modifiers; + struct wl_list link; // cg_seat::keyboard_groups ++ bool is_virtual; + }; + + struct cg_pointer { + struct wl_list link; // seat::pointers + struct cg_seat *seat; +- struct wlr_input_device *device; ++ struct wlr_pointer *pointer; + + struct wl_listener destroy; + }; +@@ -68,7 +69,7 @@ struct cg_pointer { + struct cg_touch { + struct wl_list link; // seat::touch + struct cg_seat *seat; +- struct wlr_input_device *device; ++ struct wlr_touch *touch; + + struct wl_listener destroy; + }; +@@ -77,6 +78,7 @@ struct cg_drag_icon { struct wl_list link; // seat::drag_icons struct cg_seat *seat; struct wlr_drag_icon *wlr_drag_icon; -+ struct wlr_scene_node *scene_node; ++ struct wlr_scene_tree *scene_tree; /* The drag icon has a position in layout coordinates. */ double lx, ly; diff --git a/server.h b/server.h -index 817637b..bb7f3c1 100644 +index 817637b..082a435 100644 --- a/server.h +++ b/server.h -@@ -25,6 +25,8 @@ struct cg_server { +@@ -12,10 +12,6 @@ + #include + #endif + +-#include "output.h" +-#include "seat.h" +-#include "view.h" +- + enum cg_multi_output_mode { + CAGE_MULTI_OUTPUT_MODE_EXTEND, + CAGE_MULTI_OUTPUT_MODE_LAST, +@@ -25,6 +21,8 @@ struct cg_server { struct wl_display *wl_display; struct wl_list views; struct wlr_backend *backend; @@ -1391,7 +1949,7 @@ index 817637b..bb7f3c1 100644 struct cg_seat *seat; struct wlr_idle *idle; -@@ -34,6 +36,7 @@ struct cg_server { +@@ -34,6 +32,7 @@ struct cg_server { enum cg_multi_output_mode output_mode; struct wlr_output_layout *output_layout; @@ -1399,7 +1957,17 @@ index 817637b..bb7f3c1 100644 /* Includes disabled outputs; depending on the output_mode * some outputs may be disabled. */ struct wl_list outputs; // cg_output::link -@@ -48,9 +51,6 @@ struct cg_server { +@@ -41,6 +40,9 @@ struct cg_server { + + struct wl_listener xdg_toplevel_decoration; + struct wl_listener new_xdg_shell_surface; ++ ++ struct wl_listener new_virtual_keyboard; ++ struct wl_listener new_virtual_pointer; + #if CAGE_HAS_XWAYLAND + struct wl_listener new_xwayland_surface; + #endif +@@ -48,9 +50,6 @@ struct cg_server { bool xdg_decoration; bool allow_vt_switch; enum wl_output_transform output_transform; @@ -1469,10 +2037,10 @@ index db6bc7d..0000000 - -#endif diff --git a/view.c b/view.c -index 3f3b0ed..6551142 100644 +index 3f3b0ed..b4a3eca 100644 --- a/view.c +++ b/view.c -@@ -1,19 +1,20 @@ +@@ -1,20 +1,20 @@ /* * Cage: A Wayland kiosk. * @@ -1491,11 +2059,12 @@ index 3f3b0ed..6551142 100644 #include -#include #include +-#include +#include - #include #include "output.h" -@@ -24,96 +25,6 @@ + #include "seat.h" +@@ -24,96 +24,6 @@ #include "xwayland.h" #endif @@ -1592,7 +2161,7 @@ index 3f3b0ed..6551142 100644 char * view_get_title(struct cg_view *view) { -@@ -136,24 +47,6 @@ view_is_transient_for(struct cg_view *child, struct cg_view *parent) +@@ -136,24 +46,6 @@ view_is_transient_for(struct cg_view *child, struct cg_view *parent) return child->impl->is_transient_for(child, parent); } @@ -1617,29 +2186,40 @@ index 3f3b0ed..6551142 100644 void view_activate(struct cg_view *view, bool activate) { -@@ -174,6 +67,9 @@ view_maximize(struct cg_view *view, struct wlr_box *layout_box) +@@ -174,6 +66,9 @@ view_maximize(struct cg_view *view, struct wlr_box *layout_box) { view->lx = layout_box->x; view->ly = layout_box->y; + -+ wlr_scene_node_set_position(view->scene_node, view->lx, view->ly); ++ wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); + view->impl->maximize(view, layout_box->width, layout_box->height); } -@@ -185,6 +81,8 @@ view_center(struct cg_view *view, struct wlr_box *layout_box) +@@ -185,33 +80,21 @@ view_center(struct cg_view *view, struct wlr_box *layout_box) view->lx = (layout_box->width - width) / 2; view->ly = (layout_box->height - height) / 2; + -+ wlr_scene_node_set_position(view->scene_node, view->lx, view->ly); ++ wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); } void -@@ -199,51 +97,29 @@ view_position(struct cg_view *view) - } - } + view_position(struct cg_view *view) + { +- struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); ++ struct wlr_box layout_box; ++ wlr_output_layout_get_box(view->server->output_layout, NULL, &layout_box); +- if (view_is_primary(view) || view_extends_output_layout(view, layout_box)) { +- view_maximize(view, layout_box); ++ if (view_is_primary(view) || view_extends_output_layout(view, &layout_box)) { ++ view_maximize(view, &layout_box); + } else { +- view_center(view, layout_box); +- } +-} +- -void -view_for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) -{ @@ -1651,12 +2231,13 @@ index 3f3b0ed..6551142 100644 -{ - if (!view->impl->for_each_popup_surface) { - return; -- } ++ view_center(view, &layout_box); + } - view->impl->for_each_popup_surface(view, iterator, data); --} -- + } + void - view_unmap(struct cg_view *view) +@@ -219,31 +102,24 @@ view_unmap(struct cg_view *view) { wl_list_remove(&view->link); @@ -1666,7 +2247,7 @@ index 3f3b0ed..6551142 100644 - wl_list_for_each_safe (child, tmp, &view->children, link) { - child->destroy(child); - } -+ wlr_scene_node_destroy(view->scene_node); ++ wlr_scene_node_destroy(&view->scene_tree->node); + view->wlr_surface->data = NULL; view->wlr_surface = NULL; @@ -1683,12 +2264,12 @@ index 3f3b0ed..6551142 100644 - } - wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces_above, parent_link) { - subsurface_create(view, subsurface); -+ view->scene_node = wlr_scene_subsurface_tree_create(&view->server->scene->node, surface); -+ if (!view->scene_node) { ++ view->scene_tree = wlr_scene_subsurface_tree_create(&view->server->scene->tree, surface); ++ if (!view->scene_tree) { + wl_resource_post_no_memory(surface->resource); + return; } -+ view->scene_node->data = view; ++ view->scene_tree->node.data = view; - view->new_subsurface.notify = handle_new_subsurface; - wl_signal_add(&view->wlr_surface->events.new_subsurface, &view->new_subsurface); @@ -1726,7 +2307,7 @@ index 3f3b0ed..6551142 100644 + return surface->data; } diff --git a/view.h b/view.h -index cd16e42..677a949 100644 +index cd16e42..5ae13dd 100644 --- a/view.h +++ b/view.h @@ -5,9 +5,9 @@ @@ -1734,7 +2315,8 @@ index cd16e42..677a949 100644 #include #include -#include - #include +-#include ++#include #include +#include #if CAGE_HAS_XWAYLAND @@ -1746,7 +2328,7 @@ index cd16e42..677a949 100644 struct wl_list link; // server::views - struct wl_list children; // cg_view_child::link struct wlr_surface *wlr_surface; -+ struct wlr_scene_node *scene_node; ++ struct wlr_scene_tree *scene_tree; /* The view has a position in layout coordinates. */ int lx, ly; @@ -1808,7 +2390,7 @@ index cd16e42..677a949 100644 #endif diff --git a/xdg_shell.c b/xdg_shell.c -index 2e42347..ede71f4 100644 +index 2e42347..c577dc5 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -6,10 +6,11 @@ @@ -1824,7 +2406,7 @@ index 2e42347..ede71f4 100644 #include #include -@@ -41,60 +42,32 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data) +@@ -41,105 +42,47 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data) wlr_xdg_toplevel_decoration_v1_set_mode(xdg_decoration->wlr_decoration, mode); } @@ -1846,16 +2428,16 @@ index 2e42347..ede71f4 100644 - -static void -handle_xdg_popup_map(struct wl_listener *listener, void *data) -+static struct cg_view * -+popup_get_view(struct wlr_xdg_popup *popup) - { +-{ - struct cg_xdg_popup *popup = wl_container_of(listener, popup, map); - view_damage_whole(popup->view_child.view); -} - -static void -handle_xdg_popup_unmap(struct wl_listener *listener, void *data) --{ ++static struct cg_view * ++popup_get_view(struct wlr_xdg_popup *popup) + { - struct cg_xdg_popup *popup = wl_container_of(listener, popup, unmap); - view_damage_whole(popup->view_child.view); -} @@ -1900,12 +2482,24 @@ index 2e42347..ede71f4 100644 - struct cg_view *view = popup->view_child.view; struct cg_server *server = view->server; - struct wlr_box *popup_box = &popup->wlr_popup->geometry; -+ struct wlr_box *popup_box = &popup->geometry; ++ struct wlr_box *popup_box = &popup->current.geometry; struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output *wlr_output = -@@ -108,38 +81,7 @@ popup_unconstrain(struct cg_xdg_popup *popup) - .height = output_box->height, + wlr_output_layout_output_at(output_layout, view->lx + popup_box->x, view->ly + popup_box->y); +- struct wlr_box *output_box = wlr_output_layout_get_box(output_layout, wlr_output); ++ struct wlr_box output_box; ++ wlr_output_layout_get_box(output_layout, wlr_output, &output_box); + + struct wlr_box output_toplevel_box = { +- .x = output_box->x - view->lx, +- .y = output_box->y - view->ly, +- .width = output_box->width, +- .height = output_box->height, ++ .x = output_box.x - view->lx, ++ .y = output_box.y - view->ly, ++ .width = output_box.width, ++ .height = output_box.height, }; - wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box); @@ -1944,23 +2538,76 @@ index 2e42347..ede71f4 100644 } static struct cg_xdg_shell_view * -@@ -170,9 +112,12 @@ static bool +@@ -152,7 +95,7 @@ static char * + get_title(struct cg_view *view) + { + struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); +- return xdg_shell_view->xdg_surface->toplevel->title; ++ return xdg_shell_view->xdg_toplevel->title; + } + + static void +@@ -161,7 +104,7 @@ get_geometry(struct cg_view *view, int *width_out, int *height_out) + struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); + struct wlr_box geom; + +- wlr_xdg_surface_get_geometry(xdg_shell_view->xdg_surface, &geom); ++ wlr_xdg_surface_get_geometry(xdg_shell_view->xdg_toplevel->base, &geom); + *width_out = geom.width; + *height_out = geom.height; + } +@@ -170,9 +113,9 @@ static bool is_primary(struct cg_view *view) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); - struct wlr_xdg_surface *parent = xdg_shell_view->xdg_surface->toplevel->parent; - /* FIXME: role is 0? */ - return parent == NULL; /*&& role == WLR_XDG_SURFACE_ROLE_TOPLEVEL */ -+ struct wlr_xdg_surface *xdg_surface = xdg_shell_view->xdg_surface; ++ struct wlr_xdg_toplevel *parent = xdg_shell_view->xdg_toplevel->parent; + -+ struct wlr_xdg_surface *parent = xdg_surface->toplevel->parent; -+ enum wlr_xdg_surface_role role = xdg_surface->role; -+ -+ return parent == NULL && role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; ++ return parent == NULL; } static bool -@@ -216,41 +161,20 @@ destroy(struct cg_view *view) +@@ -182,14 +125,13 @@ is_transient_for(struct cg_view *child, struct cg_view *parent) + return false; + } + struct cg_xdg_shell_view *_child = xdg_shell_view_from_view(child); +- struct wlr_xdg_surface *xdg_surface = _child->xdg_surface; ++ struct wlr_xdg_toplevel *xdg_toplevel = _child->xdg_toplevel; + struct cg_xdg_shell_view *_parent = xdg_shell_view_from_view(parent); +- struct wlr_xdg_surface *parent_xdg_surface = _parent->xdg_surface; +- while (xdg_surface) { +- if (xdg_surface->toplevel->parent == parent_xdg_surface) { ++ while (xdg_toplevel) { ++ if (xdg_toplevel->parent == _parent->xdg_toplevel) { + return true; + } +- xdg_surface = xdg_surface->toplevel->parent; ++ xdg_toplevel = xdg_toplevel->parent; + } + return false; + } +@@ -198,15 +140,15 @@ static void + activate(struct cg_view *view, bool activate) + { + struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); +- wlr_xdg_toplevel_set_activated(xdg_shell_view->xdg_surface, activate); ++ wlr_xdg_toplevel_set_activated(xdg_shell_view->xdg_toplevel, activate); + } + + static void + maximize(struct cg_view *view, int output_width, int output_height) + { + struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); +- wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_surface, output_width, output_height); +- wlr_xdg_toplevel_set_maximized(xdg_shell_view->xdg_surface, true); ++ wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_toplevel, output_width, output_height); ++ wlr_xdg_toplevel_set_maximized(xdg_shell_view->xdg_toplevel, true); + } + + static void +@@ -216,41 +158,21 @@ destroy(struct cg_view *view) free(xdg_shell_view); } @@ -1989,7 +2636,7 @@ index 2e42347..ede71f4 100644 handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void *data) { struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_fullscreen); - struct wlr_xdg_toplevel_set_fullscreen_event *event = data; +- struct wlr_xdg_toplevel_set_fullscreen_event *event = data; - wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_surface, event->fullscreen); -} @@ -2003,14 +2650,16 @@ index 2e42347..ede71f4 100644 + * Certain clients do not like figuring out their own window geometry if they + * display in fullscreen mode, so we set it here. + */ -+ struct wlr_box *layout_box = wlr_output_layout_get_box(xdg_shell_view->view.server->output_layout, NULL); -+ wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_surface, layout_box->width, layout_box->height); ++ struct wlr_box layout_box; ++ wlr_output_layout_get_box(xdg_shell_view->view.server->output_layout, NULL, &layout_box); ++ wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_toplevel, layout_box.width, layout_box.height); + -+ wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_surface, event->fullscreen); ++ wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_toplevel, ++ xdg_shell_view->xdg_toplevel->requested.fullscreen); } static void -@@ -259,10 +183,6 @@ handle_xdg_shell_surface_unmap(struct wl_listener *listener, void *data) +@@ -259,10 +181,6 @@ handle_xdg_shell_surface_unmap(struct wl_listener *listener, void *data) struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, unmap); struct cg_view *view = &xdg_shell_view->view; @@ -2021,28 +2670,31 @@ index 2e42347..ede71f4 100644 view_unmap(view); } -@@ -272,12 +192,7 @@ handle_xdg_shell_surface_map(struct wl_listener *listener, void *data) +@@ -272,12 +190,7 @@ handle_xdg_shell_surface_map(struct wl_listener *listener, void *data) struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, map); struct cg_view *view = &xdg_shell_view->view; - xdg_shell_view->commit.notify = handle_xdg_shell_surface_commit; - wl_signal_add(&xdg_shell_view->xdg_surface->surface->events.commit, &xdg_shell_view->commit); - - view_map(view, xdg_shell_view->xdg_surface->surface); +- view_map(view, xdg_shell_view->xdg_surface->surface); - - view_damage_whole(view); ++ view_map(view, xdg_shell_view->xdg_toplevel->base->surface); } static void -@@ -290,7 +205,6 @@ handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data) +@@ -290,8 +203,7 @@ handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data) wl_list_remove(&xdg_shell_view->unmap.link); wl_list_remove(&xdg_shell_view->destroy.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); - wl_list_remove(&xdg_shell_view->new_popup.link); - xdg_shell_view->xdg_surface = NULL; +- xdg_shell_view->xdg_surface = NULL; ++ xdg_shell_view->xdg_toplevel = NULL; view_destroy(view); -@@ -304,9 +218,6 @@ static const struct cg_view_impl xdg_shell_view_impl = { + } +@@ -304,9 +216,6 @@ static const struct cg_view_impl xdg_shell_view_impl = { .activate = activate, .maximize = maximize, .destroy = destroy, @@ -2052,7 +2704,7 @@ index 2e42347..ede71f4 100644 }; void -@@ -315,29 +226,64 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) +@@ -315,29 +224,64 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) struct cg_server *server = wl_container_of(listener, server, new_xdg_shell_surface); struct wlr_xdg_surface *xdg_surface = data; @@ -2073,7 +2725,7 @@ index 2e42347..ede71f4 100644 - return; - } + view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); -+ xdg_shell_view->xdg_surface = xdg_surface; ++ xdg_shell_view->xdg_toplevel = xdg_surface->toplevel; + + xdg_shell_view->map.notify = handle_xdg_shell_surface_map; + wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); @@ -2093,19 +2745,19 @@ index 2e42347..ede71f4 100644 + return; + } + -+ struct wlr_scene_node *parent_scene_node = NULL; ++ struct wlr_scene_tree *parent_scene_tree = NULL; + struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent); + switch (parent->role) { + case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; -+ parent_scene_node = view->scene_node; ++ parent_scene_tree = view->scene_tree; + break; + case WLR_XDG_SURFACE_ROLE_POPUP: -+ parent_scene_node = parent->data; ++ parent_scene_tree = parent->data; + break; + case WLR_XDG_SURFACE_ROLE_NONE: + break; + } -+ if (parent_scene_node == NULL) { ++ if (parent_scene_tree == NULL) { + return; + } @@ -2122,15 +2774,15 @@ index 2e42347..ede71f4 100644 - wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); - xdg_shell_view->new_popup.notify = handle_new_xdg_popup; - wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_view->new_popup); -+ struct wlr_scene_node *popup_scene_node = wlr_scene_xdg_surface_create(parent_scene_node, xdg_surface); -+ if (popup_scene_node == NULL) { ++ struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, xdg_surface); ++ if (popup_scene_tree == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); + return; + } + + popup_unconstrain(view, popup); + -+ xdg_surface->data = popup_scene_node; ++ xdg_surface->data = popup_scene_tree; + break; + case WLR_XDG_SURFACE_ROLE_NONE: + assert(false); // unreachable @@ -2139,10 +2791,16 @@ index 2e42347..ede71f4 100644 void diff --git a/xdg_shell.h b/xdg_shell.h -index 45d87db..9a101c6 100644 +index 45d87db..2fd506a 100644 --- a/xdg_shell.h +++ b/xdg_shell.h -@@ -14,19 +14,7 @@ struct cg_xdg_shell_view { +@@ -9,24 +9,12 @@ + + struct cg_xdg_shell_view { + struct cg_view view; +- struct wlr_xdg_surface *xdg_surface; ++ struct wlr_xdg_toplevel *xdg_toplevel; + struct wl_listener destroy; struct wl_listener unmap; struct wl_listener map; diff --git a/cage-vi/virtual_input.patch b/cage-vi/virtual_input.patch deleted file mode 100644 index a34b567..0000000 --- a/cage-vi/virtual_input.patch +++ /dev/null @@ -1,218 +0,0 @@ -From 99956cd5301ad1c19e3a3d07e022c942ca8b312d Mon Sep 17 00:00:00 2001 -From: Dominique Martinet -Date: Tue, 18 May 2021 08:52:06 +0900 -Subject: [PATCH 1/2] seat: add wlr_virtual_keyboard_manager_v1 - ---- - seat.c | 43 ++++++++++++++++++++++++++++++++++++------- - seat.h | 4 ++++ - 2 files changed, 40 insertions(+), 7 deletions(-) - -diff --git a/seat.c b/seat.c -index 08f25a3..d8556f6 100644 ---- a/seat.c -+++ b/seat.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - #include - #if CAGE_HAS_XWAYLAND -@@ -294,10 +295,16 @@ handle_keyboard_group_modifiers(struct wl_listener *listener, void *data) - } - - static void --cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) -+cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat, bool virtual) - { - struct wlr_keyboard *wlr_keyboard = device->keyboard; - -+ if (virtual) -+ /* We apparently should not group virtual keyboards, -+ * so create a new group with it -+ */ -+ goto create_new; -+ - struct cg_keyboard_group *group; - wl_list_for_each (group, &seat->keyboard_groups, link) { - struct wlr_keyboard_group *wlr_group = group->wlr_group; -@@ -309,7 +316,9 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) - - /* This is reached if and only if the keyboard could not be inserted into - * any group */ -- struct cg_keyboard_group *cg_group = calloc(1, sizeof(struct cg_keyboard_group)); -+ struct cg_keyboard_group *cg_group; -+create_new: -+ cg_group = calloc(1, sizeof(struct cg_keyboard_group)); - if (cg_group == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate keyboard group."); - return; -@@ -322,7 +331,7 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) - } - - cg_group->wlr_group->data = cg_group; -- wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, device->keyboard->keymap); -+ wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, wlr_keyboard->keymap); - - wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, wlr_keyboard->repeat_info.rate, - wlr_keyboard->repeat_info.delay); -@@ -330,7 +339,10 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) - wlr_log(WLR_DEBUG, "Created keyboard group"); - - wlr_keyboard_group_add_keyboard(cg_group->wlr_group, wlr_keyboard); -- wl_list_insert(&seat->keyboard_groups, &cg_group->link); -+ if (!virtual) -+ wl_list_insert(&seat->keyboard_groups, &cg_group->link); -+ else -+ wl_list_init(&cg_group->link); - - wl_signal_add(&cg_group->wlr_group->keyboard.events.key, &cg_group->key); - cg_group->key.notify = handle_keyboard_group_key; -@@ -347,7 +359,7 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) - } - - static void --handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) -+handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device, bool virtual) - { - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { -@@ -374,11 +386,24 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) - xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); - -- cg_keyboard_group_add(device, seat); -+ cg_keyboard_group_add(device, seat, virtual); - - wlr_seat_set_keyboard(seat->seat, device); - } - -+static void -+handle_virtual_keyboard(struct wl_listener *listener, void *data) -+{ -+ struct cg_seat *seat = wl_container_of(listener, seat, new_virtual_keyboard); -+ struct wlr_virtual_keyboard_v1 *keyboard = data; -+ struct wlr_input_device *device = &keyboard->input_device; -+ -+ /* If multiple seats are supported, check keyboard->seat -+ * to select the appropriate one */ -+ -+ handle_new_keyboard(seat, device, true); -+} -+ - static void - handle_new_input(struct wl_listener *listener, void *data) - { -@@ -387,7 +412,7 @@ handle_new_input(struct wl_listener *listener, void *data) - - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: -- handle_new_keyboard(seat, device); -+ handle_new_keyboard(seat, device, false); - break; - case WLR_INPUT_DEVICE_POINTER: - handle_new_pointer(seat, device); -@@ -818,6 +843,10 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) - seat->start_drag.notify = handle_start_drag; - wl_signal_add(&seat->seat->events.start_drag, &seat->start_drag); - -+ seat->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(server->wl_display); -+ wl_signal_add(&seat->virtual_keyboard->events.new_virtual_keyboard, &seat->new_virtual_keyboard); -+ seat->new_virtual_keyboard.notify = handle_virtual_keyboard; -+ - return seat; - } - -diff --git a/seat.h b/seat.h -index 188543d..428801a 100644 ---- a/seat.h -+++ b/seat.h -@@ -25,6 +25,10 @@ struct cg_seat { - struct wl_list touch; - struct wl_listener new_input; - -+ // These belong to higher level if multiple seats are allowed -+ struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; -+ struct wl_listener new_virtual_keyboard; -+ - struct wlr_cursor *cursor; - struct wlr_xcursor_manager *xcursor_manager; - struct wl_listener cursor_motion; - -From 9d2e1c2131c27fd656f37580689fce92a663dad0 Mon Sep 17 00:00:00 2001 -From: Dominique Martinet -Date: Tue, 18 May 2021 08:52:22 +0900 -Subject: [PATCH 2/2] seat: add wlr_virtual_pointer_manager_v1 - -together with the previous patch, wayvnc can now be used with cage: - $ cage something - # figure out which wayland socket cage used - $ WAYLAND_DISPLAY=wayland-0 wayvnc - -Note this does not appear to work with headless backend, e.g. starting cage with -WLR_BACKENDS=headless WLR_LIBINPUT_NO_DEVICES=1 cage something -does start and wayvnc connects/displays output, but there are tons of errors -and input does not work ---- - seat.c | 17 +++++++++++++++++ - seat.h | 2 ++ - 2 files changed, 19 insertions(+) - -diff --git a/seat.c b/seat.c -index d8556f6..9bf6672 100644 ---- a/seat.c -+++ b/seat.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - #include - #if CAGE_HAS_XWAYLAND -@@ -216,6 +217,18 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) - map_input_device_to_output(seat, device); - } - -+static void -+handle_virtual_pointer(struct wl_listener *listener, void *data) -+{ -+ struct cg_seat *seat = wl_container_of(listener, seat, new_virtual_pointer); -+ struct wlr_virtual_pointer_v1_new_pointer_event *event = data; -+ struct wlr_virtual_pointer_v1 *pointer = event->new_pointer; -+ struct wlr_input_device *device = &pointer->input_device; -+ -+ /* event->suggested_seat should be checked if we handle multiple seats */ -+ handle_new_pointer(seat, device); -+} -+ - static void - handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) - { -@@ -847,6 +860,10 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) - wl_signal_add(&seat->virtual_keyboard->events.new_virtual_keyboard, &seat->new_virtual_keyboard); - seat->new_virtual_keyboard.notify = handle_virtual_keyboard; - -+ seat->virtual_pointer = wlr_virtual_pointer_manager_v1_create(server->wl_display); -+ wl_signal_add(&seat->virtual_pointer->events.new_virtual_pointer, &seat->new_virtual_pointer); -+ seat->new_virtual_pointer.notify = handle_virtual_pointer; -+ - return seat; - } - -diff --git a/seat.h b/seat.h -index 428801a..0f6de59 100644 ---- a/seat.h -+++ b/seat.h -@@ -27,7 +27,9 @@ struct cg_seat { - - // These belong to higher level if multiple seats are allowed - struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; -+ struct wlr_virtual_pointer_manager_v1 *virtual_pointer; - struct wl_listener new_virtual_keyboard; -+ struct wl_listener new_virtual_pointer; - - struct wlr_cursor *cursor; - struct wlr_xcursor_manager *xcursor_manager;