Add cage-vi
This commit is contained in:
parent
5d4cfb5769
commit
dd3071719e
3 changed files with 2512 additions and 0 deletions
38
srcpkgs/cage-vi/PKGBUILD
Normal file
38
srcpkgs/cage-vi/PKGBUILD
Normal file
|
@ -0,0 +1,38 @@
|
|||
pkgname=cage-vi
|
||||
_pkgname=${pkgname%%-*}
|
||||
pkgver=0.1.4+39+ga81ab70
|
||||
_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=('wlroots' 'wayland' 'libxkbcommon' 'xorg-xwayland')
|
||||
makedepends=('meson' 'wayland-protocols')
|
||||
source=(
|
||||
"https://github.com/Hjdskes/${_pkgname}/releases/download/v${_pkgver}/${_pkgname}-${_pkgver}.tar.gz"
|
||||
'a81ab70.patch'
|
||||
'virtual_input.patch'
|
||||
)
|
||||
sha256sums=(
|
||||
'dfe27fb0c7d43db72d6c82f01e2736580a0791a23ba69d7b56285d08af98ad90'
|
||||
'8580568cc9b68b33de206a841e2110be14de730356c504b66fe366912d0abf76'
|
||||
'352a3f33c2690a401c90c4de668d38e4cdff53db6c2fc9577a7c607d8a9ec369'
|
||||
)
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${_pkgname}-${_pkgver}"
|
||||
patch -Np1 -i '../a81ab70.patch'
|
||||
patch -Np1 -i '../virtual_input.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
|
||||
}
|
2256
srcpkgs/cage-vi/a81ab70.patch
Normal file
2256
srcpkgs/cage-vi/a81ab70.patch
Normal file
|
@ -0,0 +1,2256 @@
|
|||
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..5e95347
|
||||
--- /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
|
||||
+
|
||||
+ - 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.15.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
|
||||
+ - name: Fetch wlroots as a subproject
|
||||
+ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.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
|
||||
+ - name: Fetch wlroots as a subproject
|
||||
+ run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0
|
||||
+ - name: Run scan-build
|
||||
+ run: |
|
||||
+ meson build-scan-build -Dxwayland=true
|
||||
+ ninja -C build-scan-build scan-build
|
||||
diff --git a/cage.c b/cage.c
|
||||
index 5392535..95f0cc7 100644
|
||||
--- a/cage.c
|
||||
+++ b/cage.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <unistd.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
+#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
@@ -27,8 +28,11 @@
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
+#include <wlr/types/wlr_presentation_time.h>
|
||||
+#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_screencopy_v1.h>
|
||||
#include <wlr/types/wlr_server_decoration.h>
|
||||
+#include <wlr/types/wlr_viewporter.h>
|
||||
#if CAGE_HAS_XWAYLAND
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#endif
|
||||
@@ -185,9 +189,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 +204,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,7 +253,6 @@ 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_data_device_manager *data_device_manager = NULL;
|
||||
struct wlr_server_decoration_manager *server_decoration_manager = NULL;
|
||||
@@ -270,6 +261,8 @@ main(int argc, char *argv[])
|
||||
struct wlr_screencopy_manager_v1 *screencopy_manager = NULL;
|
||||
struct wlr_xdg_output_manager_v1 *output_manager = NULL;
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL;
|
||||
+ struct wlr_viewporter *viewporter = NULL;
|
||||
+ struct wlr_presentation *presentation = NULL;
|
||||
struct wlr_xdg_shell *xdg_shell = NULL;
|
||||
#if CAGE_HAS_XWAYLAND
|
||||
struct wlr_xwayland *xwayland = NULL;
|
||||
@@ -316,8 +309,21 @@ main(int argc, char *argv[])
|
||||
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,7 +335,16 @@ 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;
|
||||
@@ -401,6 +416,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");
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 3a84794..5a8b28c 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.15.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 <wlr/config.h>', 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..c33bbe1 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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server-core.h>
|
||||
@@ -26,216 +27,20 @@
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
+#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/region.h>
|
||||
|
||||
#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 <wayland-server-core.h>
|
||||
-#include <wlr/backend.h>
|
||||
-#include <wlr/render/wlr_renderer.h>
|
||||
-#include <wlr/types/wlr_box.h>
|
||||
-#include <wlr/types/wlr_matrix.h>
|
||||
-#include <wlr/types/wlr_output.h>
|
||||
-#include <wlr/types/wlr_output_layout.h>
|
||||
-#include <wlr/types/wlr_surface.h>
|
||||
-#include <wlr/util/log.h>
|
||||
-#include <wlr/util/region.h>
|
||||
-
|
||||
-#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..4dce511 100644
|
||||
--- a/seat.c
|
||||
+++ b/seat.c
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
+#include <assert.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_keyboard_group.h>
|
||||
#include <wlr/types/wlr_primary_selection.h>
|
||||
+#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
@@ -41,42 +43,31 @@ static void drag_icon_update_position(struct cg_drag_icon *drag_icon);
|
||||
* menus or tooltips. This function tests if any of those are underneath the
|
||||
* coordinates lx and ly (in output Layout Coordinates). If so, it sets the
|
||||
* surface pointer to that wlr_surface and the sx and sy coordinates to the
|
||||
- * coordinates relative to that surface's top-left corner. */
|
||||
-static bool
|
||||
-view_at(struct cg_view *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
|
||||
-{
|
||||
- double view_sx = lx - view->lx;
|
||||
- double view_sy = ly - view->ly;
|
||||
-
|
||||
- double _sx, _sy;
|
||||
- struct wlr_surface *_surface = view_wlr_surface_at(view, view_sx, view_sy, &_sx, &_sy);
|
||||
- if (_surface != NULL) {
|
||||
- *sx = _sx;
|
||||
- *sy = _sy;
|
||||
- *surface = _surface;
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
-}
|
||||
-
|
||||
-/* This iterates over all of our surfaces and attempts to find one
|
||||
- * under the cursor. This relies on server->views being ordered from
|
||||
- * top-to-bottom. If desktop_view_at returns a view, there is also a
|
||||
- * surface. There cannot be a surface without a view, either. It's
|
||||
- * both or nothing. */
|
||||
+ * coordinates relative to that surface's top-left corner.
|
||||
+ *
|
||||
+ * This function iterates over all of our surfaces and attempts to find one
|
||||
+ * 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)
|
||||
{
|
||||
- struct cg_view *view;
|
||||
+ struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->node, lx, ly, sx, sy);
|
||||
+ if (node == NULL || node->type != WLR_SCENE_NODE_SURFACE) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
- wl_list_for_each (view, &server->views, link) {
|
||||
- if (view_at(view, lx, ly, surface, sx, sy)) {
|
||||
- return view;
|
||||
- }
|
||||
+ *surface = wlr_scene_surface_from_node(node)->surface;
|
||||
+
|
||||
+ /* Walk up the tree until we find a node with a data pointer. When done,
|
||||
+ * we've found the node representing the view. */
|
||||
+ while (node != NULL && node->data == NULL) {
|
||||
+ node = node->parent;
|
||||
}
|
||||
+ assert(node != NULL);
|
||||
|
||||
- return NULL;
|
||||
+ return node->data;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -351,17 +342,11 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device)
|
||||
{
|
||||
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);
|
||||
@@ -569,10 +554,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;
|
||||
@@ -605,15 +587,6 @@ handle_cursor_motion(struct wl_listener *listener, void *data)
|
||||
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 +594,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 +611,7 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon)
|
||||
break;
|
||||
}
|
||||
|
||||
- drag_icon_damage(drag_icon);
|
||||
+ wlr_scene_node_set_position(drag_icon->scene_node, drag_icon->lx, drag_icon->ly);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -650,6 +621,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data)
|
||||
|
||||
wl_list_remove(&drag_icon->link);
|
||||
wl_list_remove(&drag_icon->destroy.link);
|
||||
+ wlr_scene_node_destroy(drag_icon->scene_node);
|
||||
free(drag_icon);
|
||||
}
|
||||
|
||||
@@ -692,6 +664,11 @@ handle_start_drag(struct wl_listener *listener, void *data)
|
||||
}
|
||||
drag_icon->seat = seat;
|
||||
drag_icon->wlr_drag_icon = wlr_drag_icon;
|
||||
+ drag_icon->scene_node = wlr_scene_subsurface_tree_create(&seat->server->scene->node, wlr_drag_icon->surface);
|
||||
+ if (!drag_icon->scene_node) {
|
||||
+ free(drag_icon);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
drag_icon->destroy.notify = handle_drag_icon_destroy;
|
||||
wl_signal_add(&wlr_drag_icon->events.destroy, &drag_icon->destroy);
|
||||
@@ -840,7 +817,10 @@ struct cg_view *
|
||||
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..5fb2db3 100644
|
||||
--- a/seat.h
|
||||
+++ b/seat.h
|
||||
@@ -77,6 +77,7 @@ struct cg_drag_icon {
|
||||
struct wl_list link; // seat::drag_icons
|
||||
struct cg_seat *seat;
|
||||
struct wlr_drag_icon *wlr_drag_icon;
|
||||
+ struct wlr_scene_node *scene_node;
|
||||
|
||||
/* The drag icon has a position in layout coordinates. */
|
||||
double lx, ly;
|
||||
diff --git a/server.h b/server.h
|
||||
index 817637b..bb7f3c1 100644
|
||||
--- a/server.h
|
||||
+++ b/server.h
|
||||
@@ -25,6 +25,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 +36,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
|
||||
@@ -48,9 +51,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 <wlr/types/wlr_box.h>
|
||||
-
|
||||
-#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 <wlr/types/wlr_box.h>
|
||||
-
|
||||
-/** 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..6551142 100644
|
||||
--- a/view.c
|
||||
+++ b/view.c
|
||||
@@ -1,19 +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 <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-server-core.h>
|
||||
-#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
+#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
|
||||
#include "output.h"
|
||||
@@ -24,96 +25,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 +47,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 +67,9 @@ view_maximize(struct cg_view *view, struct wlr_box *layout_box)
|
||||
{
|
||||
view->lx = layout_box->x;
|
||||
view->ly = layout_box->y;
|
||||
+
|
||||
+ wlr_scene_node_set_position(view->scene_node, view->lx, view->ly);
|
||||
+
|
||||
view->impl->maximize(view, layout_box->width, layout_box->height);
|
||||
}
|
||||
|
||||
@@ -185,6 +81,8 @@ view_center(struct cg_view *view, struct wlr_box *layout_box)
|
||||
|
||||
view->lx = (layout_box->width - width) / 2;
|
||||
view->ly = (layout_box->height - height) / 2;
|
||||
+
|
||||
+ wlr_scene_node_set_position(view->scene_node, view->lx, view->ly);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -199,51 +97,29 @@ view_position(struct cg_view *view)
|
||||
}
|
||||
}
|
||||
|
||||
-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->impl->for_each_popup_surface(view, iterator, data);
|
||||
-}
|
||||
-
|
||||
void
|
||||
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_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_node = wlr_scene_subsurface_tree_create(&view->server->scene->node, surface);
|
||||
+ if (!view->scene_node) {
|
||||
+ wl_resource_post_no_memory(surface->resource);
|
||||
+ return;
|
||||
}
|
||||
+ view->scene_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..677a949 100644
|
||||
--- a/view.h
|
||||
+++ b/view.h
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-server-core.h>
|
||||
-#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
+#include <wlr/util/box.h>
|
||||
#if CAGE_HAS_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
#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_node *scene_node;
|
||||
|
||||
/* 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..ede71f4 100644
|
||||
--- a/xdg_shell.c
|
||||
+++ b/xdg_shell.c
|
||||
@@ -6,10 +6,11 @@
|
||||
* See the LICENSE file accompanying this file.
|
||||
*/
|
||||
|
||||
+#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
-#include <wlr/types/wlr_box.h>
|
||||
+#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
@@ -41,60 +42,32 @@ 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)
|
||||
+static struct cg_view *
|
||||
+popup_get_view(struct wlr_xdg_popup *popup)
|
||||
{
|
||||
- struct cg_xdg_popup *popup = wl_container_of(listener, popup, map);
|
||||
- view_damage_whole(popup->view_child.view);
|
||||
-}
|
||||
-
|
||||
-static void
|
||||
-handle_xdg_popup_unmap(struct wl_listener *listener, void *data)
|
||||
-{
|
||||
- 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->geometry;
|
||||
|
||||
struct wlr_output_layout *output_layout = server->output_layout;
|
||||
struct wlr_output *wlr_output =
|
||||
@@ -108,38 +81,7 @@ popup_unconstrain(struct cg_xdg_popup *popup)
|
||||
.height = output_box->height,
|
||||
};
|
||||
|
||||
- wlr_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 *
|
||||
@@ -170,9 +112,12 @@ static bool
|
||||
is_primary(struct cg_view *view)
|
||||
{
|
||||
struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
|
||||
- struct wlr_xdg_surface *parent = xdg_shell_view->xdg_surface->toplevel->parent;
|
||||
- /* FIXME: role is 0? */
|
||||
- return parent == NULL; /*&& role == WLR_XDG_SURFACE_ROLE_TOPLEVEL */
|
||||
+ struct wlr_xdg_surface *xdg_surface = xdg_shell_view->xdg_surface;
|
||||
+
|
||||
+ struct wlr_xdg_surface *parent = xdg_surface->toplevel->parent;
|
||||
+ enum wlr_xdg_surface_role role = xdg_surface->role;
|
||||
+
|
||||
+ return parent == NULL && role == WLR_XDG_SURFACE_ROLE_TOPLEVEL;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -216,41 +161,20 @@ 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);
|
||||
+ wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_surface, layout_box->width, layout_box->height);
|
||||
+
|
||||
+ wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_surface, event->fullscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -259,10 +183,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 +192,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);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -290,7 +205,6 @@ 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;
|
||||
|
||||
view_destroy(view);
|
||||
@@ -304,9 +218,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 +226,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_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_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_node *parent_scene_node = NULL;
|
||||
+ struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent);
|
||||
+ switch (parent->role) {
|
||||
+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
|
||||
+ parent_scene_node = view->scene_node;
|
||||
+ break;
|
||||
+ case WLR_XDG_SURFACE_ROLE_POPUP:
|
||||
+ parent_scene_node = parent->data;
|
||||
+ break;
|
||||
+ case WLR_XDG_SURFACE_ROLE_NONE:
|
||||
+ break;
|
||||
+ }
|
||||
+ if (parent_scene_node == 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_node *popup_scene_node = wlr_scene_xdg_surface_create(parent_scene_node, xdg_surface);
|
||||
+ if (popup_scene_node == NULL) {
|
||||
+ wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ popup_unconstrain(view, popup);
|
||||
+
|
||||
+ xdg_surface->data = popup_scene_node;
|
||||
+ break;
|
||||
+ case WLR_XDG_SURFACE_ROLE_NONE:
|
||||
+ assert(false); // unreachable
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/xdg_shell.h b/xdg_shell.h
|
||||
index 45d87db..9a101c6 100644
|
||||
--- a/xdg_shell.h
|
||||
+++ b/xdg_shell.h
|
||||
@@ -14,19 +14,7 @@ struct cg_xdg_shell_view {
|
||||
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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
-#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/xwayland.h>
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
218
srcpkgs/cage-vi/virtual_input.patch
Normal file
218
srcpkgs/cage-vi/virtual_input.patch
Normal file
|
@ -0,0 +1,218 @@
|
|||
From 99956cd5301ad1c19e3a3d07e022c942ca8b312d Mon Sep 17 00:00:00 2001
|
||||
From: Dominique Martinet <dominique.martinet@atmark-techno.com>
|
||||
Date: Tue, 18 May 2021 08:52:06 +0900
|
||||
Subject: [PATCH 1/2] seat: add wlr_virtual_keyboard_manager_v1
|
||||
|
||||
---
|
||||
seat.c | 43 ++++++++++++++++++++++++++++++++++++-------
|
||||
seat.h | 4 ++++
|
||||
2 files changed, 40 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/seat.c b/seat.c
|
||||
index 08f25a3..d8556f6 100644
|
||||
--- a/seat.c
|
||||
+++ b/seat.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
+#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/util/log.h>
|
||||
#if CAGE_HAS_XWAYLAND
|
||||
@@ -294,10 +295,16 @@ handle_keyboard_group_modifiers(struct wl_listener *listener, void *data)
|
||||
}
|
||||
|
||||
static void
|
||||
-cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat)
|
||||
+cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat, bool virtual)
|
||||
{
|
||||
struct wlr_keyboard *wlr_keyboard = device->keyboard;
|
||||
|
||||
+ if (virtual)
|
||||
+ /* We apparently should not group virtual keyboards,
|
||||
+ * so create a new group with it
|
||||
+ */
|
||||
+ goto create_new;
|
||||
+
|
||||
struct cg_keyboard_group *group;
|
||||
wl_list_for_each (group, &seat->keyboard_groups, link) {
|
||||
struct wlr_keyboard_group *wlr_group = group->wlr_group;
|
||||
@@ -309,7 +316,9 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat)
|
||||
|
||||
/* This is reached if and only if the keyboard could not be inserted into
|
||||
* any group */
|
||||
- struct cg_keyboard_group *cg_group = calloc(1, sizeof(struct cg_keyboard_group));
|
||||
+ struct cg_keyboard_group *cg_group;
|
||||
+create_new:
|
||||
+ cg_group = calloc(1, sizeof(struct cg_keyboard_group));
|
||||
if (cg_group == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate keyboard group.");
|
||||
return;
|
||||
@@ -322,7 +331,7 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat)
|
||||
}
|
||||
|
||||
cg_group->wlr_group->data = cg_group;
|
||||
- wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, device->keyboard->keymap);
|
||||
+ wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, wlr_keyboard->keymap);
|
||||
|
||||
wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, wlr_keyboard->repeat_info.rate,
|
||||
wlr_keyboard->repeat_info.delay);
|
||||
@@ -330,7 +339,10 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat)
|
||||
wlr_log(WLR_DEBUG, "Created keyboard group");
|
||||
|
||||
wlr_keyboard_group_add_keyboard(cg_group->wlr_group, wlr_keyboard);
|
||||
- wl_list_insert(&seat->keyboard_groups, &cg_group->link);
|
||||
+ if (!virtual)
|
||||
+ wl_list_insert(&seat->keyboard_groups, &cg_group->link);
|
||||
+ else
|
||||
+ wl_list_init(&cg_group->link);
|
||||
|
||||
wl_signal_add(&cg_group->wlr_group->keyboard.events.key, &cg_group->key);
|
||||
cg_group->key.notify = handle_keyboard_group_key;
|
||||
@@ -347,7 +359,7 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat)
|
||||
}
|
||||
|
||||
static void
|
||||
-handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device)
|
||||
+handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device, bool virtual)
|
||||
{
|
||||
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!context) {
|
||||
@@ -374,11 +386,24 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device)
|
||||
xkb_context_unref(context);
|
||||
wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
|
||||
|
||||
- cg_keyboard_group_add(device, seat);
|
||||
+ cg_keyboard_group_add(device, seat, virtual);
|
||||
|
||||
wlr_seat_set_keyboard(seat->seat, device);
|
||||
}
|
||||
|
||||
+static void
|
||||
+handle_virtual_keyboard(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ struct cg_seat *seat = wl_container_of(listener, seat, new_virtual_keyboard);
|
||||
+ struct wlr_virtual_keyboard_v1 *keyboard = data;
|
||||
+ struct wlr_input_device *device = &keyboard->input_device;
|
||||
+
|
||||
+ /* If multiple seats are supported, check keyboard->seat
|
||||
+ * to select the appropriate one */
|
||||
+
|
||||
+ handle_new_keyboard(seat, device, true);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
handle_new_input(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -387,7 +412,7 @@ handle_new_input(struct wl_listener *listener, void *data)
|
||||
|
||||
switch (device->type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
- handle_new_keyboard(seat, device);
|
||||
+ handle_new_keyboard(seat, device, false);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
handle_new_pointer(seat, device);
|
||||
@@ -818,6 +843,10 @@ seat_create(struct cg_server *server, struct wlr_backend *backend)
|
||||
seat->start_drag.notify = handle_start_drag;
|
||||
wl_signal_add(&seat->seat->events.start_drag, &seat->start_drag);
|
||||
|
||||
+ seat->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(server->wl_display);
|
||||
+ wl_signal_add(&seat->virtual_keyboard->events.new_virtual_keyboard, &seat->new_virtual_keyboard);
|
||||
+ seat->new_virtual_keyboard.notify = handle_virtual_keyboard;
|
||||
+
|
||||
return seat;
|
||||
}
|
||||
|
||||
diff --git a/seat.h b/seat.h
|
||||
index 188543d..428801a 100644
|
||||
--- a/seat.h
|
||||
+++ b/seat.h
|
||||
@@ -25,6 +25,10 @@ struct cg_seat {
|
||||
struct wl_list touch;
|
||||
struct wl_listener new_input;
|
||||
|
||||
+ // These belong to higher level if multiple seats are allowed
|
||||
+ struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
|
||||
+ struct wl_listener new_virtual_keyboard;
|
||||
+
|
||||
struct wlr_cursor *cursor;
|
||||
struct wlr_xcursor_manager *xcursor_manager;
|
||||
struct wl_listener cursor_motion;
|
||||
|
||||
From 9d2e1c2131c27fd656f37580689fce92a663dad0 Mon Sep 17 00:00:00 2001
|
||||
From: Dominique Martinet <dominique.martinet@atmark-techno.com>
|
||||
Date: Tue, 18 May 2021 08:52:22 +0900
|
||||
Subject: [PATCH 2/2] seat: add wlr_virtual_pointer_manager_v1
|
||||
|
||||
together with the previous patch, wayvnc can now be used with cage:
|
||||
$ cage something
|
||||
# figure out which wayland socket cage used
|
||||
$ WAYLAND_DISPLAY=wayland-0 wayvnc
|
||||
|
||||
Note this does not appear to work with headless backend, e.g. starting cage with
|
||||
WLR_BACKENDS=headless WLR_LIBINPUT_NO_DEVICES=1 cage something
|
||||
does start and wayvnc connects/displays output, but there are tons of errors
|
||||
and input does not work
|
||||
---
|
||||
seat.c | 17 +++++++++++++++++
|
||||
seat.h | 2 ++
|
||||
2 files changed, 19 insertions(+)
|
||||
|
||||
diff --git a/seat.c b/seat.c
|
||||
index d8556f6..9bf6672 100644
|
||||
--- a/seat.c
|
||||
+++ b/seat.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
||||
+#include <wlr/types/wlr_virtual_pointer_v1.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/util/log.h>
|
||||
#if CAGE_HAS_XWAYLAND
|
||||
@@ -216,6 +217,18 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device)
|
||||
map_input_device_to_output(seat, device);
|
||||
}
|
||||
|
||||
+static void
|
||||
+handle_virtual_pointer(struct wl_listener *listener, void *data)
|
||||
+{
|
||||
+ struct cg_seat *seat = wl_container_of(listener, seat, new_virtual_pointer);
|
||||
+ struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
|
||||
+ struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
|
||||
+ struct wlr_input_device *device = &pointer->input_device;
|
||||
+
|
||||
+ /* event->suggested_seat should be checked if we handle multiple seats */
|
||||
+ handle_new_pointer(seat, device);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat)
|
||||
{
|
||||
@@ -847,6 +860,10 @@ seat_create(struct cg_server *server, struct wlr_backend *backend)
|
||||
wl_signal_add(&seat->virtual_keyboard->events.new_virtual_keyboard, &seat->new_virtual_keyboard);
|
||||
seat->new_virtual_keyboard.notify = handle_virtual_keyboard;
|
||||
|
||||
+ seat->virtual_pointer = wlr_virtual_pointer_manager_v1_create(server->wl_display);
|
||||
+ wl_signal_add(&seat->virtual_pointer->events.new_virtual_pointer, &seat->new_virtual_pointer);
|
||||
+ seat->new_virtual_pointer.notify = handle_virtual_pointer;
|
||||
+
|
||||
return seat;
|
||||
}
|
||||
|
||||
diff --git a/seat.h b/seat.h
|
||||
index 428801a..0f6de59 100644
|
||||
--- a/seat.h
|
||||
+++ b/seat.h
|
||||
@@ -27,7 +27,9 @@ struct cg_seat {
|
||||
|
||||
// These belong to higher level if multiple seats are allowed
|
||||
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
|
||||
+ struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
|
||||
struct wl_listener new_virtual_keyboard;
|
||||
+ struct wl_listener new_virtual_pointer;
|
||||
|
||||
struct wlr_cursor *cursor;
|
||||
struct wlr_xcursor_manager *xcursor_manager;
|
Loading…
Reference in a new issue