diff --git a/cage-vi/.SRCINFO b/cage-vi/.SRCINFO
deleted file mode 100644
index 7e5f5a8..0000000
--- a/cage-vi/.SRCINFO
+++ /dev/null
@@ -1,25 +0,0 @@
-pkgbase = cage-vi
- pkgdesc = A Wayland kiosk, with virtual input patch applied
- pkgver = 0.1.4+54+gbd5b20e
- pkgrel = 1
- url = https://www.hjdskes.nl/projects/cage/
- arch = x86_64
- license = MIT
- makedepends = meson
- makedepends = pixman
- makedepends = scdoc
- makedepends = wayland-protocols
- makedepends = xorg-xwayland
- depends = glibc
- depends = wayland
- depends = wlroots
- optdepends = polkit: System privilege control. Required if not using seatd service
- optdepends = xorg-xwayland: X11 support
- provides = cage
- conflicts = cage
- source = https://github.com/Hjdskes/cage/releases/download/v0.1.4/cage-0.1.4.tar.gz
- source = bd5b20e.patch
- sha512sums = 55773fac44bf9e98086e53cbc20d17e3aad7046bedfe638ef8f896543388481be3989fede6f950d4f8cb0583f701cbf79617dfa011c7777a7c8b22c9bcddd64f
- sha512sums = e30d9596bf12a793e744a170dc859224f62d807bfc1f980ad26044ffe6170bedd1a1e8a9e9321b3bffb93aa3d42a152e67f60dd6735c6e13a4a2b987131a3394
-
-pkgname = cage-vi
diff --git a/cage-vi/PKGBUILD b/cage-vi/PKGBUILD
deleted file mode 100644
index c68cc30..0000000
--- a/cage-vi/PKGBUILD
+++ /dev/null
@@ -1,45 +0,0 @@
-pkgname=cage-vi
-_pkgname=${pkgname%%-*}
-pkgver=0.1.4+54+gbd5b20e
-_pkgver=${pkgver%%+*}
-pkgrel=1
-pkgdesc='A Wayland kiosk, with virtual input patch applied'
-arch=('x86_64')
-url="https://www.hjdskes.nl/projects/${_pkgname}/"
-license=('MIT')
-depends=('glibc' 'wayland' 'wlroots')
-makedepends=('meson' 'pixman' 'scdoc' 'wayland-protocols' 'xorg-xwayland')
-optdepends=(
- 'polkit: System privilege control. Required if not using seatd service'
- 'xorg-xwayland: X11 support'
-)
-provides=("${_pkgname}")
-conflicts=("${_pkgname}")
-source=(
- "https://github.com/Hjdskes/${_pkgname}/releases/download/v${_pkgver}/${_pkgname}-${_pkgver}.tar.gz"
- 'bd5b20e.patch'
-)
-sha512sums=('55773fac44bf9e98086e53cbc20d17e3aad7046bedfe638ef8f896543388481be3989fede6f950d4f8cb0583f701cbf79617dfa011c7777a7c8b22c9bcddd64f'
- 'e30d9596bf12a793e744a170dc859224f62d807bfc1f980ad26044ffe6170bedd1a1e8a9e9321b3bffb93aa3d42a152e67f60dd6735c6e13a4a2b987131a3394')
-
-#pkgver() {
-# cd "${srcdir}/${_pkgname}-${_pkgver}"
-# git describe --long --tags | sed 's/^v//;s/-/+/g'
-#}
-
-
-prepare() {
- cd "${srcdir}/${_pkgname}-${_pkgver}"
- patch -Np1 -i '../bd5b20e.patch'
- meson --buildtype=release -Dxwayland=true --prefix /usr "$srcdir/build"
-}
-
-build() {
- cd "${srcdir}/${_pkgname}-${_pkgver}"
- ninja -C "$srcdir/build"
-}
-
-package() {
- cd "${srcdir}/${_pkgname}-${_pkgver}"
- DESTDIR="$pkgdir/" ninja -C "$srcdir/build" install
-}
diff --git a/cage-vi/bd5b20e.patch b/cage-vi/bd5b20e.patch
deleted file mode 100644
index d59ba45..0000000
--- a/cage-vi/bd5b20e.patch
+++ /dev/null
@@ -1,2914 +0,0 @@
-diff --git a/.builds/alpine.yml b/.builds/alpine.yml
-deleted file mode 100644
-index ef32a95..0000000
---- a/.builds/alpine.yml
-+++ /dev/null
-@@ -1,35 +0,0 @@
--image: alpine/edge
--packages:
-- - eudev-dev
-- - mesa-dev
-- - meson
-- - libinput-dev
-- - libxkbcommon-dev
-- - pixman-dev
-- - scdoc
-- - wayland-dev
-- - wayland-protocols
-- - xcb-util-wm-dev
-- - xwayland
--sources:
-- - https://github.com/swaywm/wlroots
-- - https://github.com/Hjdskes/cage
--tasks:
-- # Install wlroots, which is required by Cage. Note that we compile a tagged
-- # version, instead of master, to avoid any breaking changes in wlroots.
-- - wlroots: |
-- cd wlroots
-- git checkout 0.14.0
-- meson --prefix=/usr build -Dexamples=false
-- ninja -C build
-- sudo ninja -C build install
-- - build: |
-- cd cage
-- meson build --werror -Dxwayland=true
-- ninja -C build
-- rm -rf build
-- - build-no-xwayland: |
-- cd cage
-- meson build --werror -Dxwayland=false
-- ninja -C build
-- rm -rf build
-diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml
-deleted file mode 100644
-index 99cdd24..0000000
---- a/.builds/archlinux.yml
-+++ /dev/null
-@@ -1,45 +0,0 @@
--image: archlinux
--packages:
-- - clang
-- - meson
-- - libinput
-- - libxkbcommon
-- - mesa
-- - scdoc
-- - wayland
-- - wayland-protocols
-- - xcb-util-wm
-- - xorg-xwayland
--sources:
-- - https://github.com/swaywm/wlroots
-- - https://github.com/Hjdskes/cage
--tasks:
-- # Install wlroots, which is required by Cage. Note that we compile a tagged
-- # version, instead of master, to avoid any breaking changes in wlroots.
-- - wlroots: |
-- cd wlroots
-- git checkout 0.14.0
-- meson --prefix=/usr build -Dexamples=false
-- ninja -C build
-- sudo ninja -C build install
-- - build: |
-- cd cage
-- meson build --werror -Dxwayland=true
-- ninja -C build
-- rm -rf build
-- - build-no-xwayland: |
-- cd cage
-- meson build --werror -Dxwayland=false
-- ninja -C build
-- rm -rf build
-- - scan-build: |
-- cd cage
-- CC=clang meson build --werror -Dxwayland=true
-- CC=clang ninja -C build scan-build
-- rm -rf build
-- - clang-format: |
-- cd cage
-- meson build --werror -Dxwayland=true
-- ninja -C build clang-format
-- rm -rf build
-- git diff --exit-code
-diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
-deleted file mode 100644
-index 92a2119..0000000
---- a/.builds/freebsd.yml
-+++ /dev/null
-@@ -1,37 +0,0 @@
--image: freebsd/latest
--packages:
-- - devel/evdev-proto
-- - devel/meson
-- - devel/libepoll-shim
-- - devel/pkgconf
-- - graphics/mesa-libs
-- - graphics/wayland
-- - graphics/wayland-protocols
-- - textproc/scdoc
-- - x11/libinput
-- - x11/libxkbcommon
-- - x11/pixman
-- - x11/xcb-util-wm
-- - x11-servers/xwayland
--sources:
-- - https://github.com/swaywm/wlroots
-- - https://github.com/Hjdskes/cage
--tasks:
-- # Install wlroots, which is required by Cage. Note that we compile a tagged
-- # version, instead of master, to avoid any breaking changes in wlroots.
-- - wlroots: |
-- cd wlroots
-- git checkout 0.14.0
-- meson --prefix=/usr/local build -Dexamples=false
-- ninja -C build
-- sudo ninja -C build install
-- - build: |
-- cd cage
-- PKG_CONFIG_PATH=/usr/local/lib/pkgconfig meson build --werror -Dxwayland=true
-- PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ninja -C build
-- rm -rf build
-- - build-no-xwayland: |
-- cd cage
-- PKG_CONFIG_PATH=/usr/local/lib/pkgconfig meson build --werror -Dxwayland=false
-- PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ninja -C build
-- rm -rf build
-diff --git a/.clang-format-ignore b/.clang-format-ignore
-new file mode 100644
-index 0000000..60dd059
---- /dev/null
-+++ b/.clang-format-ignore
-@@ -0,0 +1 @@
-+subprojects/**/*
-\ No newline at end of file
-diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
-new file mode 100644
-index 0000000..a98291a
---- /dev/null
-+++ b/.github/workflows/main.yml
-@@ -0,0 +1,76 @@
-+name: Continuous integration build
-+on:
-+ push:
-+ branches: [ master ]
-+ pull_request:
-+ branches: [ master ]
-+
-+jobs:
-+ compile:
-+ runs-on: ubuntu-latest
-+ strategy:
-+ matrix:
-+ CC: [ gcc, clang ]
-+ OS: [ "alpine:edge", "archlinux:base-devel" ]
-+ xwayland: [ true, false ]
-+ container: ${{ matrix.OS }}
-+ env:
-+ CC: ${{ matrix.CC }}
-+ steps:
-+ - name: Checkout Cage
-+ uses: actions/checkout@v2
-+
-+ - 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 hwdata
-+
-+ - name: Install dependencies (Arch)
-+ if: "matrix.OS == 'archlinux:base-devel'"
-+ 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
-+
-+ - name: Fetch wlroots as a subproject
-+ 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 }})
-+ run: |
-+ meson build-${{ matrix.CC }}-${{matrix.xwayland }} -Dxwayland=${{ matrix.xwayland }}
-+ ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }}
-+
-+ format:
-+ runs-on: ubuntu-latest
-+ container: "archlinux:base-devel"
-+ steps:
-+ - name: Checkout Cage
-+ uses: actions/checkout@v2
-+ - 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 hwdata
-+ - name: Fetch wlroots as a subproject
-+ 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
-+ ninja -C build-clang-format clang-format-check
-+
-+ scan-build:
-+ runs-on: ubuntu-latest
-+ container: "archlinux:base-devel"
-+ env:
-+ CC: clang
-+ steps:
-+ - name: Checkout Cage
-+ uses: actions/checkout@v2
-+ - 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 hwdata
-+ - name: Fetch wlroots as a subproject
-+ 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
-
-
-
-diff --git a/cage.c b/cage.c
-index 5392535..c5eda4d 100644
---- a/cage.c
-+++ b/cage.c
-@@ -19,6 +19,7 @@
- #include
- #include
- #include
-+#include
- #include
- #include
- #include
-@@ -27,8 +28,15 @@
- #include
- #include
- #include
-+#include
-+#include
- #include
- #include
-+#include
-+#include
-+#include
-+#include
-+#include
- #if CAGE_HAS_XWAYLAND
- #include
- #endif
-@@ -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"
--#ifdef DEBUG
-- " -D\t Turn on damage tracking debugging\n"
--#endif
- " -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 +213,11 @@ static bool
- parse_args(struct cg_server *server, int argc, char *argv[])
- {
- int c;
--#ifdef DEBUG
-- while ((c = getopt(argc, argv, "dDhm:rsv")) != -1) {
--#else
- while ((c = getopt(argc, argv, "dhm:rsv")) != -1) {
--#endif
- switch (c) {
- case 'd':
- server->xdg_decoration = true;
- break;
--#ifdef DEBUG
-- case 'D':
-- server->debug_damage_tracking = true;
-- break;
--#endif
- case 'h':
- usage(stdout, argv[0]);
- return false;
-@@ -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;
- 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 +322,21 @@ main(int argc, char *argv[])
- goto end;
- }
-
-- renderer = wlr_backend_get_renderer(server.backend);
-- wlr_renderer_init_wl_display(renderer, server.wl_display);
-+ server.renderer = wlr_renderer_autocreate(server.backend);
-+ if (!server.renderer) {
-+ wlr_log(WLR_ERROR, "Unable to create the wlroots renderer");
-+ ret = 1;
-+ goto end;
-+ }
-+
-+ server.allocator = wlr_allocator_autocreate(server.backend, server.renderer);
-+ if (!server.allocator) {
-+ wlr_log(WLR_ERROR, "Unable to create the wlroots allocator");
-+ ret = 1;
-+ goto end;
-+ }
-+
-+ wlr_renderer_init_wl_display(server.renderer, server.wl_display);
-
- wl_list_init(&server.views);
- wl_list_init(&server.outputs);
-@@ -329,13 +348,29 @@ main(int argc, char *argv[])
- goto end;
- }
-
-- compositor = wlr_compositor_create(server.wl_display, renderer);
-+ server.scene = wlr_scene_create();
-+ if (!server.scene) {
-+ wlr_log(WLR_ERROR, "Unable to create scene");
-+ ret = 1;
-+ goto end;
-+ }
-+
-+ wlr_scene_attach_output_layout(server.scene, server.output_layout);
-+
-+ compositor = wlr_compositor_create(server.wl_display, server.renderer);
- if (!compositor) {
- wlr_log(WLR_ERROR, "Unable to create the wlroots compositor");
- ret = 1;
- 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);
-
-+ viewporter = wlr_viewporter_create(server.wl_display);
-+ if (!viewporter) {
-+ wlr_log(WLR_ERROR, "Unable to create the viewporter interface");
-+ ret = 1;
-+ goto end;
-+ }
-+
-+ presentation = wlr_presentation_create(server.wl_display, server.backend);
-+ if (!presentation) {
-+ wlr_log(WLR_ERROR, "Unable to create the presentation interface");
-+ ret = 1;
-+ goto end;
-+ }
-+ wlr_scene_set_presentation(server.scene, presentation);
-+
- 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..fbd7e16 100644
---- a/meson.build
-+++ b/meson.build
-@@ -1,16 +1,17 @@
- project('cage', 'c',
- version: '0.1.4',
- license: 'MIT',
-+ meson_version: '>=0.58.1',
- default_options: [
- 'c_std=c11',
-- 'warning_level=3',
-+ 'warning_level=2',
-+ 'werror=true',
- ],
- )
-
- add_project_arguments(
- [
- '-DWLR_USE_UNSTABLE',
-- '-Wall',
- '-Wundef',
- '-Wno-unused-parameter',
- ],
-@@ -34,14 +35,13 @@ if is_freebsd
- )
- endif
-
--wlroots = dependency('wlroots', version: '>= 0.14.0')
-+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')
- xkbcommon = dependency('xkbcommon')
- math = cc.find_library('m')
-
--wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
-+wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
- wayland_scanner = find_program('wayland-scanner')
- wayland_scanner_server = generator(
- wayland_scanner,
-@@ -65,12 +65,11 @@ server_protos = declare_dependency(
- )
-
- if get_option('xwayland')
-- wlroots_has_xwayland = cc.get_define('WLR_HAS_XWAYLAND', prefix: '#include ', dependencies: wlroots) == '1'
-+ wlroots_has_xwayland = wlroots.get_variable(pkgconfig: 'have_xwayland', internal: 'have_xwayland') == 'true'
- if not wlroots_has_xwayland
- error('Cannot build Cage with XWayland support: wlroots has been built without it')
-- else
-- have_xwayland = true
- endif
-+ have_xwayland = true
- else
- have_xwayland = false
- endif
-@@ -78,8 +77,8 @@ endif
- version = '@0@'.format(meson.project_version())
- git = find_program('git', native: true, required: false)
- if git.found()
-- git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'])
-- git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'])
-+ git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false)
-+ git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
- if git_commit.returncode() == 0 and git_branch.returncode() == 0
- version = '@0@-@1@ (branch \'@2@\')'.format(
- meson.project_version(),
-@@ -95,7 +94,7 @@ conf_data.set_quoted('CAGE_VERSION', version)
-
- scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
- if scdoc.found()
-- scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true)
-+ scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true)
- sh = find_program('sh', native: true)
- mandir = get_option('mandir')
- man_files = [
-@@ -111,7 +110,7 @@ if scdoc.found()
- input: filename,
- output: output,
- command: [
-- sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output)
-+ sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.full_path(), output)
- ],
- install: true,
- install_dir: '@0@/man@1@'.format(mandir, section)
-@@ -123,9 +122,7 @@ cage_sources = [
- 'cage.c',
- 'idle_inhibit_v1.c',
- 'output.c',
-- 'render.c',
- 'seat.c',
-- 'util.c',
- 'view.c',
- 'xdg_shell.c',
- ]
-@@ -136,10 +133,8 @@ cage_headers = [
- configuration: conf_data),
- 'idle_inhibit_v1.h',
- 'output.h',
-- 'render.h',
- 'seat.h',
- 'server.h',
-- 'util.h',
- 'view.h',
- 'xdg_shell.h',
- ]
-@@ -157,7 +152,6 @@ executable(
- wayland_server,
- wlroots,
- xkbcommon,
-- pixman,
- math,
- ],
- install: true,
-diff --git a/output.c b/output.c
-index d8da3b9..6eca0db 100644
---- a/output.c
-+++ b/output.c
-@@ -1,7 +1,7 @@
- /*
- * Cage: A Wayland kiosk.
- *
-- * Copyright (C) 2018-2020 Jente Hidskes
-+ * Copyright (C) 2018-2021 Jente Hidskes
- * Copyright (C) 2019 The Sway authors
- *
- * See the LICENSE file accompanying this file.
-@@ -11,6 +11,7 @@
-
- #include "config.h"
-
-+#include
- #include
- #include
- #include
-@@ -21,221 +22,25 @@
- #include
- #endif
- #include
-+#include
- #include
- #include
- #include
- #include
- #include
--#include
-+#include
- #include
- #include
- #include
-
- #include "output.h"
--#include "render.h"
- #include "seat.h"
- #include "server.h"
--#include "util.h"
- #include "view.h"
- #if CAGE_HAS_XWAYLAND
- #include "xwayland.h"
- #endif
-
--static void output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data);
--
--struct surface_iterator_data {
-- cg_surface_iterator_func_t user_iterator;
-- void *user_data;
--
-- struct cg_output *output;
--
-- /* Output-local coordinates. */
-- double ox, oy;
--};
--
--static bool
--intersects_with_output(struct cg_output *output, struct wlr_output_layout *output_layout, struct wlr_box *surface_box)
--{
-- /* Since the surface_box's x- and y-coordinates are already output local,
-- * the x- and y-coordinates of this box need to be 0 for this function to
-- * work correctly. */
-- struct wlr_box output_box = {0};
-- wlr_output_effective_resolution(output->wlr_output, &output_box.width, &output_box.height);
--
-- struct wlr_box intersection;
-- return wlr_box_intersection(&intersection, &output_box, surface_box);
--}
--
--static void
--output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, void *user_data)
--{
-- struct surface_iterator_data *data = user_data;
-- struct cg_output *output = data->output;
--
-- if (!wlr_surface_has_buffer(surface)) {
-- return;
-- }
--
-- struct wlr_box surface_box = {
-- .x = data->ox + sx + surface->sx,
-- .y = data->oy + sy + surface->sy,
-- .width = surface->current.width,
-- .height = surface->current.height,
-- };
--
-- if (!intersects_with_output(output, output->server->output_layout, &surface_box)) {
-- return;
-- }
--
-- data->user_iterator(data->output, surface, &surface_box, data->user_data);
--}
--
--void
--output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, double ox, double oy,
-- cg_surface_iterator_func_t iterator, void *user_data)
--{
-- struct surface_iterator_data data = {
-- .user_iterator = iterator,
-- .user_data = user_data,
-- .output = output,
-- .ox = ox,
-- .oy = oy,
-- };
--
-- wlr_surface_for_each_surface(surface, output_for_each_surface_iterator, &data);
--}
--
--static void
--output_view_for_each_surface(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator,
-- void *user_data)
--{
-- struct surface_iterator_data data = {
-- .user_iterator = iterator,
-- .user_data = user_data,
-- .output = output,
-- .ox = view->lx,
-- .oy = view->ly,
-- };
--
-- wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy);
-- view_for_each_surface(view, output_for_each_surface_iterator, &data);
--}
--
--void
--output_view_for_each_popup_surface(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator,
-- void *user_data)
--{
-- struct surface_iterator_data data = {
-- .user_iterator = iterator,
-- .user_data = user_data,
-- .output = output,
-- .ox = view->lx,
-- .oy = view->ly,
-- };
--
-- wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy);
-- view_for_each_popup_surface(view, output_for_each_surface_iterator, &data);
--}
--
--void
--output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *drag_icons,
-- cg_surface_iterator_func_t iterator, void *user_data)
--{
-- struct cg_drag_icon *drag_icon;
-- wl_list_for_each (drag_icon, drag_icons, link) {
-- if (drag_icon->wlr_drag_icon->mapped) {
-- double ox = drag_icon->lx;
-- double oy = drag_icon->ly;
-- wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy);
-- output_surface_for_each_surface(output, drag_icon->wlr_drag_icon->surface, ox, oy, iterator,
-- user_data);
-- }
-- }
--}
--
--static void
--output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data)
--{
-- struct cg_view *view;
-- wl_list_for_each_reverse (view, &output->server->views, link) {
-- output_view_for_each_surface(output, view, iterator, user_data);
-- }
--
-- output_drag_icons_for_each_surface(output, &output->server->seat->drag_icons, iterator, user_data);
--}
--
--struct send_frame_done_data {
-- struct timespec when;
--};
--
--static void
--send_frame_done_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data)
--{
-- struct send_frame_done_data *data = user_data;
-- wlr_surface_send_frame_done(surface, &data->when);
--}
--
--static void
--send_frame_done(struct cg_output *output, struct send_frame_done_data *data)
--{
-- output_for_each_surface(output, send_frame_done_iterator, data);
--}
--
--static void
--count_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *_box, void *data)
--{
-- size_t *n = data;
-- n++;
--}
--
--static bool
--scan_out_primary_view(struct cg_output *output)
--{
-- struct cg_server *server = output->server;
-- struct wlr_output *wlr_output = output->wlr_output;
--
-- struct cg_drag_icon *drag_icon;
-- wl_list_for_each (drag_icon, &server->seat->drag_icons, link) {
-- if (drag_icon->wlr_drag_icon->mapped) {
-- return false;
-- }
-- }
--
-- struct cg_view *view = seat_get_focus(server->seat);
-- if (!view || !view->wlr_surface) {
-- return false;
-- }
--
-- size_t n_surfaces = 0;
-- output_view_for_each_surface(output, view, count_surface_iterator, &n_surfaces);
-- if (n_surfaces > 1) {
-- return false;
-- }
--
--#if CAGE_HAS_XWAYLAND
-- if (view->type == CAGE_XWAYLAND_VIEW) {
-- struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
-- if (!wl_list_empty(&xwayland_view->xwayland_surface->children)) {
-- return false;
-- }
-- }
--#endif
--
-- struct wlr_surface *surface = view->wlr_surface;
--
-- if (!surface->buffer) {
-- return false;
-- }
--
-- if ((float) surface->current.scale != wlr_output->scale ||
-- surface->current.transform != wlr_output->transform) {
-- return false;
-- }
--
-- wlr_output_attach_buffer(wlr_output, &surface->buffer->base);
-- return wlr_output_commit(wlr_output);
--}
--
- static void
- output_enable(struct cg_output *output)
- {
-@@ -249,6 +54,9 @@ output_enable(struct cg_output *output)
- wlr_output_layout_add_auto(output->server->output_layout, wlr_output);
- wlr_output_enable(wlr_output, true);
- wlr_output_commit(wlr_output);
-+
-+ output->scene_output = wlr_scene_get_scene_output(output->server->scene, wlr_output);
-+ assert(output->scene_output != NULL);
- }
-
- static void
-@@ -261,6 +69,8 @@ output_disable(struct cg_output *output)
- return;
- }
-
-+ output->scene_output = NULL;
-+
- wlr_log(WLR_DEBUG, "Disabling output %s", wlr_output->name);
- wlr_output_enable(wlr_output, false);
- wlr_output_layout_remove(output->server->output_layout, wlr_output);
-@@ -268,93 +78,19 @@ output_disable(struct cg_output *output)
- }
-
- static void
--damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data)
-+handle_output_frame(struct wl_listener *listener, void *data)
- {
-- struct wlr_output *wlr_output = output->wlr_output;
-- bool whole = *(bool *) user_data;
--
-- scale_box(box, output->wlr_output->scale);
--
-- if (whole) {
-- wlr_output_damage_add_box(output->damage, box);
-- } else if (pixman_region32_not_empty(&surface->buffer_damage)) {
-- pixman_region32_t damage;
-- pixman_region32_init(&damage);
-- wlr_surface_get_effective_damage(surface, &damage);
--
-- wlr_region_scale(&damage, &damage, wlr_output->scale);
-- if (ceil(wlr_output->scale) > surface->current.scale) {
-- /* When scaling up a surface it'll become
-- blurry, so we need to expand the damage
-- region. */
-- wlr_region_expand(&damage, &damage, ceil(wlr_output->scale) - surface->current.scale);
-- }
-- pixman_region32_translate(&damage, box->x, box->y);
-- wlr_output_damage_add(output->damage, &damage);
-- pixman_region32_fini(&damage);
-- }
--}
-+ struct cg_output *output = wl_container_of(listener, output, frame);
-
--void
--output_damage_surface(struct cg_output *output, struct wlr_surface *surface, double lx, double ly, bool whole)
--{
- if (!output->wlr_output->enabled) {
-- wlr_log(WLR_DEBUG, "Not adding damage for disabled output %s", output->wlr_output->name);
- return;
- }
-
-- double ox = lx, oy = ly;
-- wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy);
-- output_surface_for_each_surface(output, surface, ox, oy, damage_surface_iterator, &whole);
--}
-+ wlr_scene_output_commit(output->scene_output);
-
--static void
--handle_output_damage_frame(struct wl_listener *listener, void *data)
--{
-- struct cg_output *output = wl_container_of(listener, output, damage_frame);
-- struct send_frame_done_data frame_data = {0};
--
-- if (!output->wlr_output->enabled) {
-- return;
-- }
--
-- /* Check if we can scan-out the primary view. */
-- static bool last_scanned_out = false;
-- bool scanned_out = scan_out_primary_view(output);
--
-- if (scanned_out && !last_scanned_out) {
-- wlr_log(WLR_DEBUG, "Scanning out primary view");
-- }
-- if (last_scanned_out && !scanned_out) {
-- wlr_log(WLR_DEBUG, "Stopping primary view scan out");
-- }
-- last_scanned_out = scanned_out;
--
-- if (scanned_out) {
-- goto frame_done;
-- }
--
-- bool needs_frame;
-- pixman_region32_t damage;
-- pixman_region32_init(&damage);
-- if (!wlr_output_damage_attach_render(output->damage, &needs_frame, &damage)) {
-- wlr_log(WLR_ERROR, "Cannot make damage output current");
-- goto damage_finish;
-- }
--
-- if (!needs_frame) {
-- wlr_output_rollback(output->wlr_output);
-- goto damage_finish;
-- }
--
-- output_render(output, &damage);
--
--damage_finish:
-- pixman_region32_fini(&damage);
--
--frame_done:
-- clock_gettime(CLOCK_MONOTONIC, &frame_data.when);
-- send_frame_done(output, &frame_data);
-+ struct timespec now = {0};
-+ clock_gettime(CLOCK_MONOTONIC, &now);
-+ wlr_scene_output_send_frame_done(output->scene_output, &now);
- }
-
- static void
-@@ -395,11 +131,12 @@ output_destroy(struct cg_output *output)
- {
- struct cg_server *server = output->server;
-
-+ output->wlr_output->data = NULL;
-+
- wl_list_remove(&output->destroy.link);
- wl_list_remove(&output->commit.link);
- wl_list_remove(&output->mode.link);
-- wl_list_remove(&output->damage_frame.link);
-- wl_list_remove(&output->damage_destroy.link);
-+ wl_list_remove(&output->frame.link);
- wl_list_remove(&output->link);
-
- wlr_output_layout_remove(server->output_layout, output->wlr_output);
-@@ -421,18 +158,10 @@ output_destroy(struct cg_output *output)
- }
- }
-
--static void
--handle_output_damage_destroy(struct wl_listener *listener, void *data)
--{
-- struct cg_output *output = wl_container_of(listener, output, damage_destroy);
-- output_destroy(output);
--}
--
- static void
- handle_output_destroy(struct wl_listener *listener, void *data)
- {
- struct cg_output *output = wl_container_of(listener, output, destroy);
-- wlr_output_damage_destroy(output->damage);
- output_destroy(output);
- }
-
-@@ -442,6 +171,11 @@ handle_new_output(struct wl_listener *listener, void *data)
- struct cg_server *server = wl_container_of(listener, server, new_output);
- struct wlr_output *wlr_output = data;
-
-+ if (!wlr_output_init_render(wlr_output, server->allocator, server->renderer)) {
-+ wlr_log(WLR_ERROR, "Failed to initialize output rendering");
-+ return;
-+ }
-+
- struct cg_output *output = calloc(1, sizeof(struct cg_output));
- if (!output) {
- wlr_log(WLR_ERROR, "Failed to allocate output");
-@@ -449,8 +183,9 @@ handle_new_output(struct wl_listener *listener, void *data)
- }
-
- output->wlr_output = wlr_output;
-+ wlr_output->data = output;
- output->server = server;
-- output->damage = wlr_output_damage_create(wlr_output);
-+
- wl_list_insert(&server->outputs, &output->link);
-
- output->commit.notify = handle_output_commit;
-@@ -459,15 +194,29 @@ handle_new_output(struct wl_listener *listener, void *data)
- wl_signal_add(&wlr_output->events.mode, &output->mode);
- output->destroy.notify = handle_output_destroy;
- wl_signal_add(&wlr_output->events.destroy, &output->destroy);
-- output->damage_frame.notify = handle_output_damage_frame;
-- wl_signal_add(&output->damage->events.frame, &output->damage_frame);
-- output->damage_destroy.notify = handle_output_damage_destroy;
-- wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
--
-- struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output);
-- if (preferred_mode) {
-- wlr_output_set_mode(wlr_output, preferred_mode);
-+ output->frame.notify = handle_output_frame;
-+ wl_signal_add(&wlr_output->events.frame, &output->frame);
-+
-+ if (!wl_list_empty(&wlr_output->modes)) {
-+ struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output);
-+ if (preferred_mode) {
-+ wlr_output_set_mode(wlr_output, preferred_mode);
-+ }
-+ if (!wlr_output_test(wlr_output)) {
-+ struct wlr_output_mode *mode;
-+ wl_list_for_each (mode, &wlr_output->modes, link) {
-+ if (mode == preferred_mode) {
-+ continue;
-+ }
-+
-+ wlr_output_set_mode(wlr_output, mode);
-+ if (wlr_output_test(wlr_output)) {
-+ break;
-+ }
-+ }
-+ }
- }
-+
- wlr_output_set_transform(wlr_output, output->server->output_transform);
-
- if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST) {
-diff --git a/output.h b/output.h
-index b3fd3b4..ced06f6 100644
---- a/output.h
-+++ b/output.h
-@@ -11,28 +11,17 @@
- struct cg_output {
- struct cg_server *server;
- struct wlr_output *wlr_output;
-- struct wlr_output_damage *damage;
-+ struct wlr_scene_output *scene_output;
-
- struct wl_listener commit;
- struct wl_listener mode;
- struct wl_listener destroy;
-- struct wl_listener damage_frame;
-- struct wl_listener damage_destroy;
-+ struct wl_listener frame;
-
- struct wl_list link; // cg_server::outputs
- };
-
--typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box,
-- void *user_data);
--
- void handle_new_output(struct wl_listener *listener, void *data);
--void output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, double ox, double oy,
-- cg_surface_iterator_func_t iterator, void *user_data);
--void output_view_for_each_popup_surface(struct cg_output *output, struct cg_view *view,
-- cg_surface_iterator_func_t iterator, void *user_data);
--void output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *drag_icons,
-- cg_surface_iterator_func_t iterator, void *user_data);
--void output_damage_surface(struct cg_output *output, struct wlr_surface *surface, double lx, double ly, bool whole);
- void output_set_window_title(struct cg_output *output, const char *title);
-
- #endif
-diff --git a/render.c b/render.c
-deleted file mode 100644
-index 166a088..0000000
---- a/render.c
-+++ /dev/null
-@@ -1,205 +0,0 @@
--/*
-- * Cage: A Wayland kiosk.
-- *
-- * Copyright (C) 2018-2020 Jente Hidskes
-- * Copyright (C) 2019 The Sway authors
-- *
-- * See the LICENSE file accompanying this file.
-- */
--
--#include
--#include
--#include
--#include
--#include
--#include
--#include
--#include
--#include
--#include
--
--#include "output.h"
--#include "seat.h"
--#include "server.h"
--#include "util.h"
--#include "view.h"
--
--static void
--scissor_output(struct wlr_output *output, pixman_box32_t *rect)
--{
-- struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
--
-- struct wlr_box box = {
-- .x = rect->x1,
-- .y = rect->y1,
-- .width = rect->x2 - rect->x1,
-- .height = rect->y2 - rect->y1,
-- };
--
-- int output_width, output_height;
-- wlr_output_transformed_resolution(output, &output_width, &output_height);
-- enum wl_output_transform transform = wlr_output_transform_invert(output->transform);
-- wlr_box_transform(&box, &box, transform, output_width, output_height);
--
-- wlr_renderer_scissor(renderer, &box);
--}
--
--struct render_data {
-- pixman_region32_t *damage;
--};
--
--static void
--render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage, struct wlr_texture *texture,
-- const struct wlr_box *box, const float matrix[static 9])
--{
-- struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
--
-- pixman_region32_t damage;
-- pixman_region32_init(&damage);
-- pixman_region32_union_rect(&damage, &damage, box->x, box->y, box->width, box->height);
-- pixman_region32_intersect(&damage, &damage, output_damage);
-- if (!pixman_region32_not_empty(&damage)) {
-- goto damage_finish;
-- }
--
-- int nrects;
-- pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
-- for (int i = 0; i < nrects; i++) {
-- scissor_output(wlr_output, &rects[i]);
-- wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f);
-- }
--
--damage_finish:
-- pixman_region32_fini(&damage);
--}
--
--static void
--render_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data)
--{
-- struct render_data *data = user_data;
-- struct wlr_output *wlr_output = output->wlr_output;
-- pixman_region32_t *output_damage = data->damage;
--
-- struct wlr_texture *texture = wlr_surface_get_texture(surface);
-- if (!texture) {
-- wlr_log(WLR_DEBUG, "Cannot obtain surface texture");
-- return;
-- }
--
-- scale_box(box, wlr_output->scale);
--
-- float matrix[9];
-- enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform);
-- wlr_matrix_project_box(matrix, box, transform, 0.0f, wlr_output->transform_matrix);
--
-- render_texture(wlr_output, output_damage, texture, box, matrix);
--}
--
--static void
--render_drag_icons(struct cg_output *output, pixman_region32_t *damage, struct wl_list *drag_icons)
--{
-- struct render_data data = {
-- .damage = damage,
-- };
-- output_drag_icons_for_each_surface(output, drag_icons, render_surface_iterator, &data);
--}
--
--/**
-- * Render all toplevels without descending into popups.
-- */
--static void
--render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage)
--{
-- struct render_data data = {
-- .damage = damage,
-- };
-- double ox = view->lx;
-- double oy = view->ly;
-- wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy);
-- output_surface_for_each_surface(output, view->wlr_surface, ox, oy, render_surface_iterator, &data);
--}
--
--static void
--render_view_popups(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage)
--{
-- struct render_data data = {
-- .damage = damage,
-- };
-- output_view_for_each_popup_surface(output, view, render_surface_iterator, &data);
--}
--
--void
--output_render(struct cg_output *output, pixman_region32_t *damage)
--{
-- struct cg_server *server = output->server;
-- struct wlr_output *wlr_output = output->wlr_output;
--
-- struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
-- if (!renderer) {
-- wlr_log(WLR_DEBUG, "Expected the output backend to have a renderer");
-- return;
-- }
--
-- wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
--
-- if (!pixman_region32_not_empty(damage)) {
-- wlr_log(WLR_DEBUG, "Output isn't damaged but needs a buffer swap");
-- goto renderer_end;
-- }
--
--#ifdef DEBUG
-- if (server->debug_damage_tracking) {
-- wlr_renderer_clear(renderer, (float[]){1.0f, 0.0f, 0.0f, 1.0f});
-- }
--#endif
--
-- float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
-- int nrects;
-- pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
-- for (int i = 0; i < nrects; i++) {
-- scissor_output(wlr_output, &rects[i]);
-- wlr_renderer_clear(renderer, color);
-- }
--
-- // TODO: render only top view, possibly use focused view for this, see #35.
-- struct cg_view *view;
-- wl_list_for_each_reverse (view, &server->views, link) {
-- render_view_toplevels(view, output, damage);
-- }
--
-- struct cg_view *focused_view = seat_get_focus(server->seat);
-- if (focused_view) {
-- render_view_popups(focused_view, output, damage);
-- }
--
-- render_drag_icons(output, damage, &server->seat->drag_icons);
--
--renderer_end:
-- /* Draw software cursor in case hardware cursors aren't
-- available. This is a no-op when they are. */
-- wlr_output_render_software_cursors(wlr_output, damage);
-- wlr_renderer_scissor(renderer, NULL);
-- wlr_renderer_end(renderer);
--
-- int output_width, output_height;
-- wlr_output_transformed_resolution(wlr_output, &output_width, &output_height);
--
-- pixman_region32_t frame_damage;
-- pixman_region32_init(&frame_damage);
--
-- enum wl_output_transform transform = wlr_output_transform_invert(wlr_output->transform);
-- wlr_region_transform(&frame_damage, &output->damage->current, transform, output_width, output_height);
--
--#ifdef DEBUG
-- if (server->debug_damage_tracking) {
-- pixman_region32_union_rect(&frame_damage, &frame_damage, 0, 0, output_width, output_height);
-- }
--#endif
--
-- wlr_output_set_damage(wlr_output, &frame_damage);
-- pixman_region32_fini(&frame_damage);
--
-- if (!wlr_output_commit(wlr_output)) {
-- wlr_log(WLR_ERROR, "Could not commit output");
-- }
--}
-diff --git a/render.h b/render.h
-deleted file mode 100644
-index 085b00b..0000000
---- a/render.h
-+++ /dev/null
-@@ -1,8 +0,0 @@
--#ifndef CG_RENDER_H
--#define CG_RENDER_H
--
--#include "output.h"
--
--void output_render(struct cg_output *output, pixman_region32_t *damage);
--
--#endif
-diff --git a/seat.c b/seat.c
-index 08f25a3..5d80e33 100644
---- a/seat.c
-+++ b/seat.c
-@@ -6,10 +6,14 @@
- * See the LICENSE file accompanying this file.
- */
-
-+#define _POSIX_C_SOURCE 200809L
-+
- #include "config.h"
-
-+#include
- #include
- #include
-+#include
- #include
- #include
- #include
-@@ -18,9 +22,11 @@
- #include
- #include
- #include
-+#include
- #include
--#include
- #include
-+#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)
-+ * coordinates relative to that surface's top-left corner.
-+ *
-+ * This function iterates over all of our surfaces and attempts to find one
-+ * under the cursor. 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)
- {
-- 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;
-+ /* 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->data) {
-+ if (!node->parent) {
-+ node = NULL;
-+ break;
- }
-+
-+ node = &node->parent->node;
- }
-
-- return NULL;
-+ assert(node != NULL);
-+ return node->data;
- }
-
- static void
-@@ -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) {
-- wlr_log(WLR_ERROR, "Unable to create XBK context");
-+ wlr_log(WLR_ERROR, "Unable to create XKB context");
- return;
- }
-
-- struct xkb_rule_names rules = {0};
-- rules.rules = getenv("XKB_DEFAULT_RULES");
-- rules.model = getenv("XKB_DEFAULT_MODEL");
-- rules.layout = getenv("XKB_DEFAULT_LAYOUT");
-- rules.variant = getenv("XKB_DEFAULT_VARIANT");
-- rules.options = getenv("XKB_DEFAULT_OPTIONS");
-- struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
-+ struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
- if (!keymap) {
- wlr_log(WLR_ERROR, "Unable to configure keyboard: keymap does not exist");
- xkb_context_unref(context);
- 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);
-
-- bool focus_changed = wlr_seat->pointer_state.focused_surface != surface;
-- if (!focus_changed && time > 0) {
-- wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy);
-- }
-+ wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy);
- }
-
- struct cg_drag_icon *drag_icon;
-@@ -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);
- }
-
--static void
--drag_icon_damage(struct cg_drag_icon *drag_icon)
--{
-- struct cg_output *output;
-- wl_list_for_each (output, &drag_icon->seat->server->outputs, link) {
-- output_damage_surface(output, drag_icon->wlr_drag_icon->surface, drag_icon->lx, drag_icon->ly, true);
-- }
--}
--
- static void
- 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;
-
-- drag_icon_damage(drag_icon);
--
- switch (wlr_icon->drag->grab_type) {
- case WLR_DRAG_GRAB_KEYBOARD:
- return;
-@@ -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_tree->node, drag_icon->lx, drag_icon->ly);
- }
-
- static void
-@@ -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_tree->node);
- free(drag_icon);
- }
-
-@@ -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_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);
-@@ -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;
-- return view_from_wlr_surface(seat->server, prev_surface);
-+ if (!prev_surface) {
-+ return NULL;
-+ }
-+ return view_from_wlr_surface(prev_surface);
- }
-
- void
-diff --git a/seat.h b/seat.h
-index 188543d..52cbee4 100644
---- a/seat.h
-+++ b/seat.h
-@@ -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_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..082a435 100644
---- a/server.h
-+++ b/server.h
-@@ -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;
-+ struct wlr_renderer *renderer;
-+ struct wlr_allocator *allocator;
-
- struct cg_seat *seat;
- struct wlr_idle *idle;
-@@ -34,6 +32,7 @@ struct cg_server {
-
- enum cg_multi_output_mode output_mode;
- struct wlr_output_layout *output_layout;
-+ struct wlr_scene *scene;
- /* Includes disabled outputs; depending on the output_mode
- * some outputs may be disabled. */
- struct wl_list outputs; // cg_output::link
-@@ -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;
--#ifdef DEBUG
-- bool debug_damage_tracking;
--#endif
- };
-
- #endif
-diff --git a/util.c b/util.c
-deleted file mode 100644
-index 95de499..0000000
---- a/util.c
-+++ /dev/null
-@@ -1,36 +0,0 @@
--/*
-- * Cage: A Wayland kiosk.
-- *
-- * Copyright (C) 2019 The Sway authors
-- *
-- * See the LICENSE file accompanying this file.
-- */
--
--#include
--
--#include "util.h"
--
--int
--scale_length(int length, int offset, float scale)
--{
-- /**
-- * One does not simply multiply the width by the scale. We allow fractional
-- * scaling, which means the resulting scaled width might be a decimal.
-- * So we round it.
-- *
-- * But even this can produce undesirable results depending on the X or Y
-- * offset of the box. For example, with a scale of 1.5, a box with
-- * width=1 should not scale to 2px if its X coordinate is 1, because the
-- * X coordinate would have scaled to 2px.
-- */
-- return round((offset + length) * scale) - round(offset * scale);
--}
--
--void
--scale_box(struct wlr_box *box, float scale)
--{
-- box->width = scale_length(box->width, box->x, scale);
-- box->height = scale_length(box->height, box->y, scale);
-- box->x = round(box->x * scale);
-- box->y = round(box->y * scale);
--}
-diff --git a/util.h b/util.h
-deleted file mode 100644
-index db6bc7d..0000000
---- a/util.h
-+++ /dev/null
-@@ -1,11 +0,0 @@
--#ifndef CG_UTIL_H
--#define CG_UTIL_H
--
--#include
--
--/** Apply scale to a width or height. */
--int scale_length(int length, int offset, float scale);
--
--void scale_box(struct wlr_box *box, float scale);
--
--#endif
-diff --git a/view.c b/view.c
-index 3f3b0ed..b4a3eca 100644
---- a/view.c
-+++ b/view.c
-@@ -1,20 +1,20 @@
- /*
- * Cage: A Wayland kiosk.
- *
-- * Copyright (C) 2018-2020 Jente Hidskes
-+ * Copyright (C) 2018-2021 Jente Hidskes
- *
- * See the LICENSE file accompanying this file.
- */
-
- #define _POSIX_C_SOURCE 200809L
-
-+#include
- #include
- #include
- #include
- #include
--#include
- #include
--#include
-+#include
-
- #include "output.h"
- #include "seat.h"
-@@ -24,96 +24,6 @@
- #include "xwayland.h"
- #endif
-
--static void
--view_child_handle_commit(struct wl_listener *listener, void *data)
--{
-- struct cg_view_child *child = wl_container_of(listener, child, commit);
-- view_damage_part(child->view);
--}
--
--static void subsurface_create(struct cg_view *view, struct wlr_subsurface *wlr_subsurface);
--
--static void
--view_child_handle_new_subsurface(struct wl_listener *listener, void *data)
--{
-- struct cg_view_child *child = wl_container_of(listener, child, new_subsurface);
-- struct wlr_subsurface *wlr_subsurface = data;
-- subsurface_create(child->view, wlr_subsurface);
--}
--
--void
--view_child_finish(struct cg_view_child *child)
--{
-- if (!child) {
-- return;
-- }
--
-- view_damage_whole(child->view);
--
-- wl_list_remove(&child->link);
-- wl_list_remove(&child->commit.link);
-- wl_list_remove(&child->new_subsurface.link);
--}
--
--void
--view_child_init(struct cg_view_child *child, struct cg_view *view, struct wlr_surface *wlr_surface)
--{
-- child->view = view;
-- child->wlr_surface = wlr_surface;
--
-- child->commit.notify = view_child_handle_commit;
-- wl_signal_add(&wlr_surface->events.commit, &child->commit);
-- child->new_subsurface.notify = view_child_handle_new_subsurface;
-- wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface);
--
-- wl_list_insert(&view->children, &child->link);
--}
--
--static void
--subsurface_destroy(struct cg_view_child *child)
--{
-- if (!child) {
-- return;
-- }
--
-- struct cg_subsurface *subsurface = (struct cg_subsurface *) child;
-- wl_list_remove(&subsurface->destroy.link);
-- view_child_finish(&subsurface->view_child);
-- free(subsurface);
--}
--
--static void
--subsurface_handle_destroy(struct wl_listener *listener, void *data)
--{
-- struct cg_subsurface *subsurface = wl_container_of(listener, subsurface, destroy);
-- struct cg_view_child *view_child = (struct cg_view_child *) subsurface;
-- subsurface_destroy(view_child);
--}
--
--static void
--subsurface_create(struct cg_view *view, struct wlr_subsurface *wlr_subsurface)
--{
-- struct cg_subsurface *subsurface = calloc(1, sizeof(struct cg_subsurface));
-- if (!subsurface) {
-- return;
-- }
--
-- view_child_init(&subsurface->view_child, view, wlr_subsurface->surface);
-- subsurface->view_child.destroy = subsurface_destroy;
-- subsurface->wlr_subsurface = wlr_subsurface;
--
-- subsurface->destroy.notify = subsurface_handle_destroy;
-- wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
--}
--
--static void
--handle_new_subsurface(struct wl_listener *listener, void *data)
--{
-- struct cg_view *view = wl_container_of(listener, view, new_subsurface);
-- struct wlr_subsurface *wlr_subsurface = data;
-- subsurface_create(view, wlr_subsurface);
--}
--
- char *
- view_get_title(struct cg_view *view)
- {
-@@ -136,24 +46,6 @@ view_is_transient_for(struct cg_view *child, struct cg_view *parent)
- return child->impl->is_transient_for(child, parent);
- }
-
--void
--view_damage_part(struct cg_view *view)
--{
-- struct cg_output *output;
-- wl_list_for_each (output, &view->server->outputs, link) {
-- output_damage_surface(output, view->wlr_surface, view->lx, view->ly, false);
-- }
--}
--
--void
--view_damage_whole(struct cg_view *view)
--{
-- struct cg_output *output;
-- wl_list_for_each (output, &view->server->outputs, link) {
-- output_damage_surface(output, view->wlr_surface, view->lx, view->ly, true);
-- }
--}
--
- void
- view_activate(struct cg_view *view, bool activate)
- {
-@@ -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_tree->node, view->lx, view->ly);
-+
- view->impl->maximize(view, layout_box->width, layout_box->height);
- }
-
-@@ -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_tree->node, view->lx, view->ly);
- }
-
- void
- 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)
--{
-- view->impl->for_each_surface(view, iterator, data);
--}
--
--void
--view_for_each_popup_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data)
--{
-- if (!view->impl->for_each_popup_surface) {
-- return;
-+ view_center(view, &layout_box);
- }
-- view->impl->for_each_popup_surface(view, iterator, data);
- }
-
- void
-@@ -219,31 +102,24 @@ view_unmap(struct cg_view *view)
- {
- wl_list_remove(&view->link);
-
-- wl_list_remove(&view->new_subsurface.link);
--
-- struct cg_view_child *child, *tmp;
-- wl_list_for_each_safe (child, tmp, &view->children, link) {
-- child->destroy(child);
-- }
-+ wlr_scene_node_destroy(&view->scene_tree->node);
-
-+ view->wlr_surface->data = NULL;
- view->wlr_surface = NULL;
- }
-
- void
- view_map(struct cg_view *view, struct wlr_surface *surface)
- {
-- view->wlr_surface = surface;
--
-- struct wlr_subsurface *subsurface;
-- wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces_below, parent_link) {
-- subsurface_create(view, subsurface);
-- }
-- wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces_above, parent_link) {
-- subsurface_create(view, subsurface);
-+ 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_tree->node.data = view;
-
-- view->new_subsurface.notify = handle_new_subsurface;
-- wl_signal_add(&view->wlr_surface->events.new_subsurface, &view->new_subsurface);
-+ view->wlr_surface = surface;
-+ surface->data = view;
-
- #if CAGE_HAS_XWAYLAND
- /* We shouldn't position override-redirect windows. They set
-@@ -283,24 +159,11 @@ view_init(struct cg_view *view, struct cg_server *server, enum cg_view_type type
- view->server = server;
- view->type = type;
- view->impl = impl;
--
-- wl_list_init(&view->children);
- }
-
- struct cg_view *
--view_from_wlr_surface(struct cg_server *server, struct wlr_surface *surface)
--{
-- struct cg_view *view;
-- wl_list_for_each (view, &server->views, link) {
-- if (view->wlr_surface == surface) {
-- return view;
-- }
-- }
-- return NULL;
--}
--
--struct wlr_surface *
--view_wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y)
-+view_from_wlr_surface(struct wlr_surface *surface)
- {
-- return view->impl->wlr_surface_at(view, sx, sy, sub_x, sub_y);
-+ assert(surface);
-+ return surface->data;
- }
-diff --git a/view.h b/view.h
-index cd16e42..5ae13dd 100644
---- a/view.h
-+++ b/view.h
-@@ -5,9 +5,9 @@
-
- #include
- #include
--#include
--#include
-+#include
- #include
-+#include
- #if CAGE_HAS_XWAYLAND
- #include
- #endif
-@@ -24,16 +24,14 @@ enum cg_view_type {
- struct cg_view {
- struct cg_server *server;
- struct wl_list link; // server::views
-- struct wl_list children; // cg_view_child::link
- struct wlr_surface *wlr_surface;
-+ struct wlr_scene_tree *scene_tree;
-
- /* The view has a position in layout coordinates. */
- int lx, ly;
-
- enum cg_view_type type;
- const struct cg_view_impl *impl;
--
-- struct wl_listener new_subsurface;
- };
-
- struct cg_view_impl {
-@@ -44,47 +42,18 @@ struct cg_view_impl {
- void (*activate)(struct cg_view *view, bool activate);
- void (*maximize)(struct cg_view *view, int output_width, int output_height);
- void (*destroy)(struct cg_view *view);
-- void (*for_each_surface)(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data);
-- void (*for_each_popup_surface)(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data);
-- struct wlr_surface *(*wlr_surface_at)(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y);
--};
--
--struct cg_view_child {
-- struct cg_view *view;
-- struct wlr_surface *wlr_surface;
-- struct wl_list link;
--
-- struct wl_listener commit;
-- struct wl_listener new_subsurface;
--
-- void (*destroy)(struct cg_view_child *child);
--};
--
--struct cg_subsurface {
-- struct cg_view_child view_child;
-- struct wlr_subsurface *wlr_subsurface;
--
-- struct wl_listener destroy;
- };
-
- char *view_get_title(struct cg_view *view);
- bool view_is_primary(struct cg_view *view);
- bool view_is_transient_for(struct cg_view *child, struct cg_view *parent);
--void view_damage_part(struct cg_view *view);
--void view_damage_whole(struct cg_view *view);
- void view_activate(struct cg_view *view, bool activate);
- void view_position(struct cg_view *view);
--void view_for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data);
--void view_for_each_popup_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data);
- void view_unmap(struct cg_view *view);
- void view_map(struct cg_view *view, struct wlr_surface *surface);
- void view_destroy(struct cg_view *view);
- void view_init(struct cg_view *view, struct cg_server *server, enum cg_view_type type, const struct cg_view_impl *impl);
-
--struct cg_view *view_from_wlr_surface(struct cg_server *server, struct wlr_surface *surface);
--struct wlr_surface *view_wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y);
--
--void view_child_finish(struct cg_view_child *child);
--void view_child_init(struct cg_view_child *child, struct cg_view *view, struct wlr_surface *wlr_surface);
-+struct cg_view *view_from_wlr_surface(struct wlr_surface *surface);
-
- #endif
-diff --git a/xdg_shell.c b/xdg_shell.c
-index 2e42347..c577dc5 100644
---- a/xdg_shell.c
-+++ b/xdg_shell.c
-@@ -6,10 +6,11 @@
- * See the LICENSE file accompanying this file.
- */
-
-+#include
- #include
- #include
- #include
--#include
-+#include
- #include
- #include
-
-@@ -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);
- }
-
--static void
--xdg_popup_destroy(struct cg_view_child *child)
--{
-- if (!child) {
-- return;
-- }
--
-- struct cg_xdg_popup *popup = (struct cg_xdg_popup *) child;
-- wl_list_remove(&popup->destroy.link);
-- wl_list_remove(&popup->map.link);
-- wl_list_remove(&popup->unmap.link);
-- wl_list_remove(&popup->new_popup.link);
-- view_child_finish(&popup->view_child);
-- free(popup);
--}
--
--static void
--handle_xdg_popup_map(struct wl_listener *listener, void *data)
--{
-- 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);
--}
--
--static void
--handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
--{
-- struct cg_xdg_popup *popup = wl_container_of(listener, popup, destroy);
-- struct cg_view_child *view_child = (struct cg_view_child *) popup;
-- xdg_popup_destroy(view_child);
--}
--
--static void xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup);
-+ while (true) {
-+ if (popup->parent == NULL || !wlr_surface_is_xdg_surface(popup->parent)) {
-+ return NULL;
-+ }
-
--static void
--popup_handle_new_xdg_popup(struct wl_listener *listener, void *data)
--{
-- struct cg_xdg_popup *popup = wl_container_of(listener, popup, new_popup);
-- struct wlr_xdg_popup *wlr_popup = data;
-- xdg_popup_create(popup->view_child.view, wlr_popup);
-+ struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(popup->parent);
-+ switch (xdg_surface->role) {
-+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
-+ return xdg_surface->data;
-+ case WLR_XDG_SURFACE_ROLE_POPUP:
-+ popup = xdg_surface->popup;
-+ break;
-+ case WLR_XDG_SURFACE_ROLE_NONE:
-+ return NULL;
-+ }
-+ }
- }
-
- static void
--popup_unconstrain(struct cg_xdg_popup *popup)
-+popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup)
- {
-- 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->current.geometry;
-
- struct wlr_output_layout *output_layout = server->output_layout;
- struct wlr_output *wlr_output =
- 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);
--}
--
--static void
--xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup)
--{
-- struct cg_xdg_popup *popup = calloc(1, sizeof(struct cg_xdg_popup));
-- if (!popup) {
-- return;
-- }
--
-- popup->wlr_popup = wlr_popup;
-- view_child_init(&popup->view_child, view, wlr_popup->base->surface);
-- popup->view_child.destroy = xdg_popup_destroy;
-- popup->destroy.notify = handle_xdg_popup_destroy;
-- wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
-- popup->map.notify = handle_xdg_popup_map;
-- wl_signal_add(&wlr_popup->base->events.map, &popup->map);
-- popup->unmap.notify = handle_xdg_popup_unmap;
-- wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
-- popup->new_popup.notify = popup_handle_new_xdg_popup;
-- wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
--
-- popup_unconstrain(popup);
--}
--
--static void
--handle_new_xdg_popup(struct wl_listener *listener, void *data)
--{
-- struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, new_popup);
-- struct wlr_xdg_popup *wlr_popup = data;
-- xdg_popup_create(&xdg_shell_view->view, wlr_popup);
-+ wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box);
- }
-
- static struct cg_xdg_shell_view *
-@@ -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_toplevel *parent = xdg_shell_view->xdg_toplevel->parent;
-+
-+ return parent == NULL;
- }
-
- static bool
-@@ -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);
- }
-
--static void
--for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data)
--{
-- struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
-- wlr_xdg_surface_for_each_surface(xdg_shell_view->xdg_surface, iterator, data);
--}
--
--static void
--for_each_popup_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data)
--{
-- struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
-- wlr_xdg_surface_for_each_popup_surface(xdg_shell_view->xdg_surface, iterator, data);
--}
--
--static struct wlr_surface *
--wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y)
--{
-- struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
-- return wlr_xdg_surface_surface_at(xdg_shell_view->xdg_surface, sx, sy, sub_x, sub_y);
--}
--
- static void
- 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;
-- wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_surface, event->fullscreen);
--}
-
--static void
--handle_xdg_shell_surface_commit(struct wl_listener *listener, void *data)
--{
-- struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, commit);
-- struct cg_view *view = &xdg_shell_view->view;
-- view_damage_part(view);
-+ /**
-+ * 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, &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_toplevel,
-+ xdg_shell_view->xdg_toplevel->requested.fullscreen);
- }
-
- static void
-@@ -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;
-
-- view_damage_whole(view);
--
-- wl_list_remove(&xdg_shell_view->commit.link);
--
- view_unmap(view);
- }
-
-@@ -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_damage_whole(view);
-+ view_map(view, xdg_shell_view->xdg_toplevel->base->surface);
- }
-
- static void
-@@ -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_toplevel = NULL;
-
- view_destroy(view);
- }
-@@ -304,9 +216,6 @@ static const struct cg_view_impl xdg_shell_view_impl = {
- .activate = activate,
- .maximize = maximize,
- .destroy = destroy,
-- .for_each_surface = for_each_surface,
-- .for_each_popup_surface = for_each_popup_surface,
-- .wlr_surface_at = wlr_surface_at,
- };
-
- void
-@@ -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;
-
-- if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
-- return;
-- }
-+ switch (xdg_surface->role) {
-+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
-+ struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view));
-+ if (!xdg_shell_view) {
-+ wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view");
-+ return;
-+ }
-
-- struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view));
-- if (!xdg_shell_view) {
-- wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view");
-- return;
-- }
-+ view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl);
-+ 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);
-+ xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap;
-+ wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap);
-+ xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy;
-+ wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
-+ xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen;
-+ wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen);
-+
-+ xdg_surface->data = xdg_shell_view;
-+ break;
-+ case WLR_XDG_SURFACE_ROLE_POPUP:;
-+ struct wlr_xdg_popup *popup = xdg_surface->popup;
-+ struct cg_view *view = popup_get_view(popup);
-+ if (view == NULL) {
-+ return;
-+ }
-+
-+ 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_tree = view->scene_tree;
-+ break;
-+ case WLR_XDG_SURFACE_ROLE_POPUP:
-+ parent_scene_tree = parent->data;
-+ break;
-+ case WLR_XDG_SURFACE_ROLE_NONE:
-+ break;
-+ }
-+ if (parent_scene_tree == NULL) {
-+ 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->map.notify = handle_xdg_shell_surface_map;
-- wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
-- xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap;
-- wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap);
-- xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy;
-- wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
-- xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen;
-- 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_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_tree;
-+ break;
-+ case WLR_XDG_SURFACE_ROLE_NONE:
-+ assert(false); // unreachable
-+ }
- }
-
- void
-diff --git a/xdg_shell.h b/xdg_shell.h
-index 45d87db..2fd506a 100644
---- a/xdg_shell.h
-+++ b/xdg_shell.h
-@@ -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;
-- struct wl_listener commit;
- struct wl_listener request_fullscreen;
-- struct wl_listener new_popup;
--};
--
--struct cg_xdg_popup {
-- struct cg_view_child view_child;
-- struct wlr_xdg_popup *wlr_popup;
--
-- struct wl_listener destroy;
-- struct wl_listener map;
-- struct wl_listener unmap;
-- struct wl_listener new_popup;
- };
-
- struct cg_xdg_decoration {
-diff --git a/xwayland.c b/xwayland.c
-index 2aae0f9..ef37a49 100644
---- a/xwayland.c
-+++ b/xwayland.c
-@@ -9,7 +9,6 @@
- #include
- #include
- #include
--#include
- #include
- #include
-
-@@ -96,18 +95,6 @@ destroy(struct cg_view *view)
- free(xwayland_view);
- }
-
--static void
--for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data)
--{
-- wlr_surface_for_each_surface(view->wlr_surface, iterator, data);
--}
--
--static struct wlr_surface *
--wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y)
--{
-- return wlr_surface_surface_at(view->wlr_surface, sx, sy, sub_x, sub_y);
--}
--
- static void
- handle_xwayland_surface_request_fullscreen(struct wl_listener *listener, void *data)
- {
-@@ -116,24 +103,12 @@ handle_xwayland_surface_request_fullscreen(struct wl_listener *listener, void *d
- wlr_xwayland_surface_set_fullscreen(xwayland_view->xwayland_surface, xwayland_surface->fullscreen);
- }
-
--static void
--handle_xwayland_surface_commit(struct wl_listener *listener, void *data)
--{
-- struct cg_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, commit);
-- struct cg_view *view = &xwayland_view->view;
-- view_damage_part(view);
--}
--
- static void
- handle_xwayland_surface_unmap(struct wl_listener *listener, void *data)
- {
- struct cg_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, unmap);
- struct cg_view *view = &xwayland_view->view;
-
-- view_damage_whole(view);
--
-- wl_list_remove(&xwayland_view->commit.link);
--
- view_unmap(view);
- }
-
-@@ -148,12 +123,7 @@ handle_xwayland_surface_map(struct wl_listener *listener, void *data)
- view->ly = xwayland_view->xwayland_surface->y;
- }
-
-- xwayland_view->commit.notify = handle_xwayland_surface_commit;
-- wl_signal_add(&xwayland_view->xwayland_surface->surface->events.commit, &xwayland_view->commit);
--
- view_map(view, xwayland_view->xwayland_surface->surface);
--
-- view_damage_whole(view);
- }
-
- static void
-@@ -179,10 +149,6 @@ static const struct cg_view_impl xwayland_view_impl = {
- .activate = activate,
- .maximize = maximize,
- .destroy = destroy,
-- .for_each_surface = for_each_surface,
-- /* XWayland doesn't have a separate popup iterator. */
-- .for_each_popup_surface = NULL,
-- .wlr_surface_at = wlr_surface_at,
- };
-
- void
-diff --git a/xwayland.h b/xwayland.h
-index d257f57..31edb8f 100644
---- a/xwayland.h
-+++ b/xwayland.h
-@@ -12,7 +12,6 @@ struct cg_xwayland_view {
- struct wl_listener destroy;
- struct wl_listener unmap;
- struct wl_listener map;
-- struct wl_listener commit;
- struct wl_listener request_fullscreen;
- };
-