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 - - Cage's logo - -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; - }; -