From 35166e4e1b253e8155664775838c497dec2750e9 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 7 Jul 2019 16:43:15 +0200 Subject: [PATCH 001/233] README: use www subdomain Fixes #76 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 280034e..11711ae 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ application. This README is only relevant for development resources and instructions. For a description of Cage and installation instructions for end-users, please see [its project -page](https://hjdskes.nl/projects/cage). +page](https://www.hjdskes.nl/projects/cage). ## Release signatures From 016ef340d20febd15ae6d4fec2b6e9fba1422cee Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 9 Jul 2019 14:25:33 +0200 Subject: [PATCH 002/233] README: update email address --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11711ae..f862d87 100644 --- a/README.md +++ b/README.md @@ -57,4 +57,4 @@ Please see [LICENSE](https://github.com/Hjdskes/cage/blob/master/LICENSE) on [GitHub](https://github.com/Hjdskes/cage). -Copyright © 2018-2019 Jente Hidskes +Copyright © 2018-2019 Jente Hidskes From 69340921a4765db25154c28a285238980e9ad772 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 25 Aug 2019 17:44:53 +0200 Subject: [PATCH 003/233] CI: use a version of wlroots that compiles with libinput 1.14 See https://github.com/swaywm/wlroots/issues/1796 --- .builds/alpine.yml | 5 +++-- .builds/archlinux.yml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 2c6d089..8451df2 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -17,8 +17,9 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # This corresponds to the tag of 0.6.0 - git checkout c0305f4f864543f8c3fea6f302e91c9b1d3396f3 + # We'd like to build against the latest release (0.6.0), but that doesn't compile + # against libinput 1.14. This commit introduces support for that version. + git checkout 94f65e354d09ded037e6ba724dc3eeed6d63778f meson --prefix=/usr build -Drootston=false -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index e052118..6757ec6 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -15,8 +15,9 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # This corresponds to the tag of 0.6.0 - git checkout c0305f4f864543f8c3fea6f302e91c9b1d3396f3 + # We'd like to build against the latest release (0.6.0), but that doesn't compile + # against libinput 1.14. This commit introduces support for that version. + git checkout 94f65e354d09ded037e6ba724dc3eeed6d63778f meson --prefix=/usr build -Drootston=false -Dexamples=false ninja -C build sudo ninja -C build install From da6b6c208ecd4e02e272c996d0853f8f6b22b1a9 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Fri, 16 Aug 2019 16:46:51 +0000 Subject: [PATCH 004/233] Add screencopy --- cage.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cage.c b/cage.c index 9c7098a..5045b88 100644 --- a/cage.c +++ b/cage.c @@ -30,6 +30,7 @@ #endif #include #include +#include #include #if CAGE_HAS_XWAYLAND #include @@ -169,6 +170,7 @@ main(int argc, char *argv[]) struct wlr_data_device_manager *data_device_mgr = NULL; struct wlr_server_decoration_manager *server_decoration_manager = NULL; struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; + struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; struct wlr_xdg_shell *xdg_shell = NULL; #if CAGE_HAS_XWAYLAND struct wlr_xwayland *xwayland = NULL; @@ -293,6 +295,13 @@ main(int argc, char *argv[]) WLR_SERVER_DECORATION_MANAGER_MODE_SERVER : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); + screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); + if (!screencopy_manager) { + wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); + ret = 1; + goto end; + } + #if CAGE_HAS_XWAYLAND xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { @@ -374,6 +383,7 @@ end: wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); seat_destroy(server.seat); + wlr_screencopy_manager_v1_destroy(screencopy_manager); wlr_server_decoration_manager_destroy(server_decoration_manager); wlr_xdg_decoration_manager_v1_destroy(xdg_decoration_manager); wlr_xdg_shell_destroy(xdg_shell); From c13ada98de9e9a243740e64c450ad7c278745377 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Fri, 16 Aug 2019 17:04:28 +0000 Subject: [PATCH 005/233] Add xdg output manager --- cage.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cage.c b/cage.c index 5045b88..2c59726 100644 --- a/cage.c +++ b/cage.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #if CAGE_HAS_XWAYLAND #include @@ -171,6 +172,7 @@ main(int argc, char *argv[]) struct wlr_server_decoration_manager *server_decoration_manager = NULL; struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; + struct wlr_xdg_output_manager_v1 *output_manager = NULL; struct wlr_xdg_shell *xdg_shell = NULL; #if CAGE_HAS_XWAYLAND struct wlr_xwayland *xwayland = NULL; @@ -302,6 +304,13 @@ main(int argc, char *argv[]) goto end; } + output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout); + if (!output_manager) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); + ret = 1; + goto end; + } + #if CAGE_HAS_XWAYLAND xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { @@ -383,6 +392,7 @@ end: wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); seat_destroy(server.seat); + wlr_xdg_output_manager_v1_destroy(output_manager); wlr_screencopy_manager_v1_destroy(screencopy_manager); wlr_server_decoration_manager_destroy(server_decoration_manager); wlr_xdg_decoration_manager_v1_destroy(xdg_decoration_manager); From 0fb513fb85eb5846eb598b91a0fc79dc16b5da36 Mon Sep 17 00:00:00 2001 From: Ruben Vandamme Date: Tue, 27 Aug 2019 10:01:25 +0200 Subject: [PATCH 006/233] Set startup color to black. --- output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output.c b/output.c index 658f422..1c36b4d 100644 --- a/output.c +++ b/output.c @@ -224,7 +224,7 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) } #endif - float color[4] = {0.3, 0.3, 0.3, 1.0}; + float color[4] = {0, 0, 0, 1.0}; int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&buffer_damage, &nrects); for (int i = 0; i < nrects; i++) { From 33bb3c818c5971777b6f09d8821e7f078d38d262 Mon Sep 17 00:00:00 2001 From: Derek Wallace Date: Mon, 9 Dec 2019 15:15:00 -0700 Subject: [PATCH 007/233] Removed destructors per wlroots PR 1915 --- cage.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/cage.c b/cage.c index 2c59726..dc27fb2 100644 --- a/cage.c +++ b/cage.c @@ -392,17 +392,6 @@ end: wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); seat_destroy(server.seat); - wlr_xdg_output_manager_v1_destroy(output_manager); - wlr_screencopy_manager_v1_destroy(screencopy_manager); - wlr_server_decoration_manager_destroy(server_decoration_manager); - wlr_xdg_decoration_manager_v1_destroy(xdg_decoration_manager); - wlr_xdg_shell_destroy(xdg_shell); - wlr_idle_inhibit_v1_destroy(server.idle_inhibit_v1); - if (server.idle) { - wlr_idle_destroy(server.idle); - } - wlr_data_device_manager_destroy(data_device_mgr); - wlr_compositor_destroy(compositor); wlr_output_layout_destroy(server.output_layout); /* This function is not null-safe, but we only ever get here with a proper wl_display. */ From 436ad33db8094e8b6fca615fb7247f7cedbec324 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Wed, 18 Dec 2019 21:34:21 +0100 Subject: [PATCH 008/233] Update wlroots in CI builds to 0.8.1 --- .builds/alpine.yml | 6 ++---- .builds/archlinux.yml | 7 +++---- .builds/freebsd.yml | 6 +++--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 8451df2..5ed154d 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -17,10 +17,8 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # We'd like to build against the latest release (0.6.0), but that doesn't compile - # against libinput 1.14. This commit introduces support for that version. - git checkout 94f65e354d09ded037e6ba724dc3eeed6d63778f - meson --prefix=/usr build -Drootston=false -Dexamples=false + git checkout 0.8.1 + meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install - build: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 6757ec6..7a5b8f1 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -15,10 +15,9 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # We'd like to build against the latest release (0.6.0), but that doesn't compile - # against libinput 1.14. This commit introduces support for that version. - git checkout 94f65e354d09ded037e6ba724dc3eeed6d63778f - meson --prefix=/usr build -Drootston=false -Dexamples=false + # Need this to compile 0.8.1. + git checkout d113e48a2a32542fe6e12f1759f07888364609bf + meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install - build: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 274eaaa..e9d31aa 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -18,9 +18,9 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # This corresponds to the tag of 0.6.0 - git checkout c0305f4f864543f8c3fea6f302e91c9b1d3396f3 - meson --prefix=/usr/local build -Drootston=false -Dexamples=false + # Need this to compile 0.8.1 + git checkout d113e48a2a32542fe6e12f1759f07888364609bf + meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install - build: | From 531cdc84b7d9c1be8a47b0c0cd3e48534e76ab77 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Wed, 18 Dec 2019 21:48:22 +0100 Subject: [PATCH 009/233] Fix the FreeBSD build --- .builds/freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index e9d31aa..dba93eb 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -20,7 +20,7 @@ tasks: cd wlroots # Need this to compile 0.8.1 git checkout d113e48a2a32542fe6e12f1759f07888364609bf - meson --prefix=/usr build -Dexamples=false + meson --prefix=/usr/local build -Dexamples=false ninja -C build sudo ninja -C build install - build: | From 65177466e7e63bab371b83ef019196f4afdb4238 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 20 Dec 2019 12:23:16 +0100 Subject: [PATCH 010/233] Implement wlr-gamma-control-unstable-v1 Closes #20 --- cage.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cage.c b/cage.c index dc27fb2..c36e670 100644 --- a/cage.c +++ b/cage.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -173,6 +174,7 @@ main(int argc, char *argv[]) struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; 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_xdg_shell *xdg_shell = NULL; #if CAGE_HAS_XWAYLAND struct wlr_xwayland *xwayland = NULL; @@ -311,6 +313,13 @@ main(int argc, char *argv[]) goto end; } + gamma_control_manager = wlr_gamma_control_manager_v1_create(server.wl_display); + if (!gamma_control_manager) { + wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); + ret = 1; + goto end; + } + #if CAGE_HAS_XWAYLAND xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { From dd87c1fab588c75729ff888cd8814a3b48ee18fa Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 20 Dec 2019 12:33:15 +0100 Subject: [PATCH 011/233] Rename data_device_mgr to _manager --- cage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cage.c b/cage.c index c36e670..da01e97 100644 --- a/cage.c +++ b/cage.c @@ -169,7 +169,7 @@ main(int argc, char *argv[]) struct wl_event_source *sigterm_source = NULL; struct wlr_renderer *renderer = NULL; struct wlr_compositor *compositor = NULL; - struct wlr_data_device_manager *data_device_mgr = NULL; + struct wlr_data_device_manager *data_device_manager = NULL; struct wlr_server_decoration_manager *server_decoration_manager = NULL; struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; @@ -233,8 +233,8 @@ main(int argc, char *argv[]) goto end; } - data_device_mgr = wlr_data_device_manager_create(server.wl_display); - if (!data_device_mgr) { + data_device_manager = wlr_data_device_manager_create(server.wl_display); + if (!data_device_manager) { wlr_log(WLR_ERROR, "Unable to create the data device manager"); ret = 1; goto end; From 90e70c68825d42f653fd7dc5c33a06b3f7477744 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 20 Dec 2019 16:37:07 +0100 Subject: [PATCH 012/233] Document environment variables Fixes #93. --- docs/env_vars.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/env_vars.md diff --git a/docs/env_vars.md b/docs/env_vars.md new file mode 100644 index 0000000..c24a14f --- /dev/null +++ b/docs/env_vars.md @@ -0,0 +1,35 @@ +# Environment variables + +Cage sets the following environment variables: + +* `DISPLAY`: if compiled with Xwayland support, this will be set to the name of + the X display used for Xwayland. +* `WAYLAND_DISPLAY`: specifies the name of the Wayland display that Cage is + running on. + +The following environment variables can be used to configure behavior of +libraries that Cage uses. Effectively, these environment variables configure +the Cage session. + +## XKB environment variables + +``` +XKB_DEFAULT_RULES +XKB_DEFAULT_MODEL +XKB_DEFAULT_LAYOUT +XKB_DEFAULT_VARIANT +XKB_DEFAULT_OPTIONS +``` + +These environment variables configure the XKB keyboard settings. See +xkeyboard-config(7). + +## Wlroots environment variables + +* `DISPLAY`: if set probe X11 backend. +* `WAYLAND_DISPLAY`, `_WAYLAND_DISPLAY`, `WAYLAND_SOCKET`: if set probe Wayland + backend. +* `XCURSOR_PATH`: directory where xcursors are located. + +For a complete list of wlroots environment variables, see +https://github.com/swaywm/wlroots/blob/master/docs/env_vars.md. From 7c6d6c75aea2211d0560136d84049b3736cedca1 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 20 Dec 2019 16:58:56 +0100 Subject: [PATCH 013/233] Implement wlr_export_dmabuf_unstable_v1 --- cage.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cage.c b/cage.c index da01e97..f10e03a 100644 --- a/cage.c +++ b/cage.c @@ -21,17 +21,18 @@ #include #include #include +#include #include #include #include #include +#include #include #if CAGE_HAS_XWAYLAND #include #endif #include #include -#include #include #include #if CAGE_HAS_XWAYLAND @@ -172,6 +173,7 @@ main(int argc, char *argv[]) struct wlr_data_device_manager *data_device_manager = NULL; struct wlr_server_decoration_manager *server_decoration_manager = NULL; struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; + struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL; struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; struct wlr_xdg_output_manager_v1 *output_manager = NULL; struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; @@ -299,6 +301,13 @@ main(int argc, char *argv[]) WLR_SERVER_DECORATION_MANAGER_MODE_SERVER : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); + 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"); + ret = 1; + goto end; + } + screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); if (!screencopy_manager) { wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); From abfe6a66caac106b24564abb8ace5120dd9612ed Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 20 Dec 2019 17:04:38 +0100 Subject: [PATCH 014/233] README: refer to docs/ --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f862d87..1369c6b 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ a TTY, it'll run with the KMS+DRM backend. In debug mode (default build type with Meson), press Alt+Esc to quit. To build a release build, use `meson build --buildtype=release`. +For more information, see the `docs/` folder. + Cage is based on the annotated source of tinywl and rootston. ## Bugs From 0aeba8085cc023e42aedc7e2d54cb3fd23bafdbf Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 20 Dec 2019 17:16:53 +0100 Subject: [PATCH 015/233] Replace all wayland-server.h includes with wayland-server-core.h The documentation for `wayland-server.h` says: > Use of this header file is discouraged. Prefer including > wayland-server-core.h instead, which does not include the server protocol > header and as such only defines the library PI, excluding the deprecated API > below. See also https://github.com/swaywm/wlroots/commit/ca45f4490ccce64bf7aa0985951319646b55d258#diff-b57e10fe0774258a6d21b22077001cff --- cage.c | 2 +- idle_inhibit_v1.c | 2 +- idle_inhibit_v1.h | 2 +- output.c | 2 +- output.h | 2 +- seat.c | 2 +- seat.h | 2 +- server.h | 2 +- view.c | 2 +- view.h | 2 +- xdg_shell.c | 2 +- xdg_shell.h | 2 +- xwayland.c | 2 +- xwayland.h | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cage.c b/cage.c index f10e03a..4b74305 100644 --- a/cage.c +++ b/cage.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/idle_inhibit_v1.c b/idle_inhibit_v1.c index 3b950ad..1d0e167 100644 --- a/idle_inhibit_v1.c +++ b/idle_inhibit_v1.c @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include diff --git a/idle_inhibit_v1.h b/idle_inhibit_v1.h index 5cde94f..e9bb25b 100644 --- a/idle_inhibit_v1.h +++ b/idle_inhibit_v1.h @@ -1,7 +1,7 @@ #ifndef CG_IDLE_INHIBIT_H #define CG_IDLE_INHIBIT_H -#include +#include void handle_idle_inhibitor_v1_new(struct wl_listener *listener, void *data); diff --git a/output.c b/output.c index 1c36b4d..e5b545b 100644 --- a/output.c +++ b/output.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #if WLR_HAS_X11_BACKEND diff --git a/output.h b/output.h index 9c052f2..9237c67 100644 --- a/output.h +++ b/output.h @@ -1,7 +1,7 @@ #ifndef CG_OUTPUT_H #define CG_OUTPUT_H -#include +#include #include #include diff --git a/seat.c b/seat.c index 980adf3..9402ec6 100644 --- a/seat.c +++ b/seat.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include diff --git a/seat.h b/seat.h index 7e5d6b6..11acf56 100644 --- a/seat.h +++ b/seat.h @@ -1,7 +1,7 @@ #ifndef CG_SEAT_H #define CG_SEAT_H -#include +#include #include #include #include diff --git a/server.h b/server.h index 80e9951..ce43d5b 100644 --- a/server.h +++ b/server.h @@ -3,7 +3,7 @@ #include "config.h" -#include +#include #include #include #include diff --git a/view.c b/view.c index 6b55606..cc2f4b0 100644 --- a/view.c +++ b/view.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/view.h b/view.h index 03e41ca..d574f4f 100644 --- a/view.h +++ b/view.h @@ -4,7 +4,7 @@ #include "config.h" #include -#include +#include #include #include #include diff --git a/xdg_shell.c b/xdg_shell.c index f964f76..5f2c9fd 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff --git a/xdg_shell.h b/xdg_shell.h index 60ba535..45d87db 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -1,7 +1,7 @@ #ifndef CG_XDG_SHELL_H #define CG_XDG_SHELL_H -#include +#include #include #include diff --git a/xwayland.c b/xwayland.c index 0cbe412..db31a93 100644 --- a/xwayland.c +++ b/xwayland.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff --git a/xwayland.h b/xwayland.h index fa9c62e..4cfd4b0 100644 --- a/xwayland.h +++ b/xwayland.h @@ -1,7 +1,7 @@ #ifndef CG_XWAYLAND_H #define CG_XWAYLAND_H -#include +#include #include #include "view.h" From 06ada15661ebc62780805069b531baa1d5b79203 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Dec 2019 16:10:11 +0100 Subject: [PATCH 016/233] Support multiple outputs Outputs are arranged in a horizontal layout in the order they are created in by wlroots. Maximized xdg_shell views will span all outputs, like the global fullscreen mode in sway. Fixes #87 --- cage.c | 1 + output.c | 57 ++++++++++++++++++++++++++++++++--------------------- output.h | 2 ++ seat.c | 30 ++++++++++++++++++++++++---- server.h | 2 +- view.c | 34 ++++++++++++++++++++++++-------- xdg_shell.c | 8 +++++--- 7 files changed, 95 insertions(+), 39 deletions(-) diff --git a/cage.c b/cage.c index 4b74305..5a4a855 100644 --- a/cage.c +++ b/cage.c @@ -220,6 +220,7 @@ main(int argc, char *argv[]) wlr_renderer_init_wl_display(renderer, server.wl_display); wl_list_init(&server.views); + wl_list_init(&server.outputs); server.output_layout = wlr_output_layout_create(); if (!server.output_layout) { diff --git a/output.c b/output.c index e5b545b..973f9e4 100644 --- a/output.c +++ b/output.c @@ -319,12 +319,20 @@ output_destroy(struct cg_output *output) wl_list_remove(&output->transform.link); wl_list_remove(&output->damage_frame.link); wl_list_remove(&output->damage_destroy.link); - free(output); - server->output = NULL; + wl_list_remove(&output->link); - /* Since there is no use in continuing without our (single) - * output, terminate. */ - wl_display_terminate(server->wl_display); + wlr_output_layout_remove(server->output_layout, output->wlr_output); + + struct cg_view *view; + wl_list_for_each(view, &output->server->views, link) { + view_position(view); + } + + free(output); + + if (wl_list_empty(&server->outputs)) { + wl_display_terminate(server->wl_display); + } } static void @@ -354,29 +362,32 @@ handle_new_output(struct wl_listener *listener, void *data) wlr_output_set_mode(wlr_output, preferred_mode); } - server->output = calloc(1, sizeof(struct cg_output)); - server->output->wlr_output = wlr_output; - server->output->server = server; - server->output->damage = wlr_output_damage_create(wlr_output); + struct cg_output *output = calloc(1, sizeof(struct cg_output)); + output->wlr_output = wlr_output; + output->server = server; + output->damage = wlr_output_damage_create(wlr_output); + wl_list_insert(&server->outputs, &output->link); - server->output->mode.notify = handle_output_mode; - wl_signal_add(&wlr_output->events.mode, &server->output->mode); - server->output->transform.notify = handle_output_transform; - wl_signal_add(&wlr_output->events.transform, &server->output->transform); - server->output->destroy.notify = handle_output_destroy; - wl_signal_add(&wlr_output->events.destroy, &server->output->destroy); - server->output->damage_frame.notify = handle_output_damage_frame; - wl_signal_add(&server->output->damage->events.frame, &server->output->damage_frame); - server->output->damage_destroy.notify = handle_output_damage_destroy; - wl_signal_add(&server->output->damage->events.destroy, &server->output->damage_destroy); + output->mode.notify = handle_output_mode; + wl_signal_add(&wlr_output->events.mode, &output->mode); + output->transform.notify = handle_output_transform; + wl_signal_add(&wlr_output->events.transform, &output->transform); + 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 cg_view *view; + wl_list_for_each(view, &output->server->views, link) { + view_position(view); + } wlr_output_set_transform(wlr_output, server->output_transform); wlr_output_layout_add_auto(server->output_layout, wlr_output); - /* Disconnect the signal now, because we only use one static output. */ - wl_list_remove(&server->new_output.link); - if (wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, @@ -385,7 +396,7 @@ handle_new_output(struct wl_listener *listener, void *data) /* Place the cursor in the center of the screen. */ wlr_cursor_warp(server->seat->cursor, NULL, wlr_output->width / 2, wlr_output->height / 2); - wlr_output_damage_add_whole(server->output->damage); + wlr_output_damage_add_whole(output->damage); } void diff --git a/output.h b/output.h index 9237c67..563e503 100644 --- a/output.h +++ b/output.h @@ -19,6 +19,8 @@ struct cg_output { struct wl_listener destroy; struct wl_listener damage_frame; struct wl_listener damage_destroy; + + struct wl_list link; }; void handle_new_output(struct wl_listener *listener, void *data); diff --git a/seat.c b/seat.c index 9402ec6..c955d85 100644 --- a/seat.c +++ b/seat.c @@ -158,7 +158,15 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) touch->destroy.notify = handle_touch_destroy; wl_signal_add(&touch->device->events.destroy, &touch->destroy); - wlr_cursor_map_input_to_output(seat->cursor, device, seat->server->output->wlr_output); + if (device->output_name != NULL) { + struct cg_output *output; + wl_list_for_each(output, &seat->server->outputs, link) { + if (strcmp(device->output_name, output->wlr_output->name) == 0) { + wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); + break; + } + } + } } static void @@ -192,7 +200,15 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) pointer->destroy.notify = handle_pointer_destroy; wl_signal_add(&device->events.destroy, &pointer->destroy); - wlr_cursor_map_input_to_output(seat->cursor, device, seat->server->output->wlr_output); + if (device->output_name != NULL) { + struct cg_output *output; + wl_list_for_each(output, &seat->server->outputs, link) { + if (strcmp(device->output_name, output->wlr_output->name) == 0) { + wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); + break; + } + } + } } static void @@ -568,7 +584,10 @@ handle_cursor_motion(struct wl_listener *listener, void *data) static void drag_icon_damage(struct cg_drag_icon *drag_icon) { - output_damage_drag_icon(drag_icon->seat->server->output, drag_icon); + struct cg_output *output; + wl_list_for_each(output, &drag_icon->seat->server->outputs, link) { + output_damage_drag_icon(output, drag_icon); + } } static void @@ -835,7 +854,10 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) view_activate(view, true); char *title = view_get_title(view); - output_set_window_title(server->output, title); + struct cg_output *output; + wl_list_for_each(output, &server->outputs, link) { + output_set_window_title(output, title); + } free(title); struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(wlr_seat); diff --git a/server.h b/server.h index ce43d5b..d05dabf 100644 --- a/server.h +++ b/server.h @@ -29,7 +29,7 @@ struct cg_server { struct wl_list inhibitors; struct wlr_output_layout *output_layout; - struct cg_output *output; + struct wl_list outputs; struct wl_listener new_output; struct wl_listener xdg_toplevel_decoration; diff --git a/view.c b/view.c index cc2f4b0..36a69d0 100644 --- a/view.c +++ b/view.c @@ -138,13 +138,19 @@ view_is_transient_for(struct cg_view *child, struct cg_view *parent) { void view_damage_surface(struct cg_view *view) { - output_damage_view_surface(view->server->output, view); + struct cg_output *output; + wl_list_for_each(output, &view->server->outputs, link) { + output_damage_view_surface(output, view); + } } void view_damage_whole(struct cg_view *view) { - output_damage_view_whole(view->server->output, view); + struct cg_output *output; + wl_list_for_each(output, &view->server->outputs, link) { + output_damage_view_whole(output, view); + } } void @@ -153,23 +159,35 @@ view_activate(struct cg_view *view, bool activate) view->impl->activate(view, activate); } +static void +get_view_output_dimensions(struct cg_view *view, int *output_width, int *output_height) +{ + *output_width = 0; + *output_height = 0; + struct cg_output *output; + wl_list_for_each(output, &view->server->outputs, link) { + int h, w; + wlr_output_transformed_resolution(output->wlr_output, &w, &h); + *output_width += w; + if (h > *output_height) { + *output_height = h; + } + } +} + static void view_maximize(struct cg_view *view) { - struct cg_output *output = view->server->output; int output_width, output_height; - - wlr_output_transformed_resolution(output->wlr_output, &output_width, &output_height); + get_view_output_dimensions(view, &output_width, &output_height); view->impl->maximize(view, output_width, output_height); } static void view_center(struct cg_view *view) { - struct wlr_output *output = view->server->output->wlr_output; - int output_width, output_height; - wlr_output_transformed_resolution(output, &output_width, &output_height); + get_view_output_dimensions(view, &output_width, &output_height); int width, height; view->impl->get_geometry(view, &width, &height); diff --git a/xdg_shell.c b/xdg_shell.c index 5f2c9fd..a5c439e 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -93,10 +93,12 @@ static void popup_unconstrain(struct cg_xdg_popup *popup) { struct cg_view *view = popup->view_child.view; - struct wlr_output *output = view->server->output->wlr_output; - struct wlr_output_layout *output_layout = view->server->output_layout; + struct cg_server *server = view->server; + struct wlr_box *popup_box = &popup->wlr_popup->geometry; - struct wlr_box *output_box = wlr_output_layout_get_box(output_layout, output); + struct wlr_output_layout *output_layout = server->output_layout; + struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, view->x + popup_box->x, view->y + popup_box->y); + struct wlr_box *output_box = wlr_output_layout_get_box(output_layout, wlr_output); struct wlr_box output_toplevel_box = { .x = output_box->x - view->x, From 739ba1fe6569f8a390949d7c1d0045b360982126 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 22 Dec 2019 01:00:45 +0100 Subject: [PATCH 017/233] Check calloc return value --- output.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/output.c b/output.c index 973f9e4..77148fa 100644 --- a/output.c +++ b/output.c @@ -363,6 +363,10 @@ handle_new_output(struct wl_listener *listener, void *data) } struct cg_output *output = calloc(1, sizeof(struct cg_output)); + if (!output) { + return; + } + output->wlr_output = wlr_output; output->server = server; output->damage = wlr_output_damage_create(wlr_output); From 24f48966d8d93a23e3adacdacef7162602ab16b1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 22 Dec 2019 01:01:06 +0100 Subject: [PATCH 018/233] Annotate wl_list link field --- output.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output.h b/output.h index 563e503..1563799 100644 --- a/output.h +++ b/output.h @@ -20,7 +20,7 @@ struct cg_output { struct wl_listener damage_frame; struct wl_listener damage_destroy; - struct wl_list link; + struct wl_list link; // cg_server::outputs }; void handle_new_output(struct wl_listener *listener, void *data); From bcd0086f136ea2f273e7cd00bdd3e9e99d75d556 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 26 Dec 2019 01:41:09 +0100 Subject: [PATCH 019/233] Set title on outputs that the focused surface is intersecting with --- seat.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/seat.c b/seat.c index c955d85..6d7448f 100644 --- a/seat.c +++ b/seat.c @@ -853,10 +853,19 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) } view_activate(view, true); + + struct wlr_box surface_box; + wlr_surface_get_extends(view->wlr_surface, &surface_box); + char *title = view_get_title(view); struct cg_output *output; wl_list_for_each(output, &server->outputs, link) { - output_set_window_title(output, title); + struct wlr_box *output_box = + wlr_output_layout_get_box(view->server->output_layout, output->wlr_output); + struct wlr_box intersection; + if (wlr_box_intersection(&intersection, &surface_box, output_box)) { + output_set_window_title(output, title); + } } free(title); From edfe4e07ce9c6f0047810e8f9e1182275a15a77a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 26 Dec 2019 01:44:21 +0100 Subject: [PATCH 020/233] Avoid excessive log messages with multiple outputs --- output.c | 1 - 1 file changed, 1 deletion(-) diff --git a/output.c b/output.c index 77148fa..b3eddb0 100644 --- a/output.c +++ b/output.c @@ -207,7 +207,6 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) } if (!needs_frame) { - wlr_log(WLR_DEBUG, "Output doesn't need frame and isn't damaged"); goto buffer_damage_finish; } From 4e832c6aaf09250af8e055f6828f07ca1ac9b663 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 26 Dec 2019 16:10:27 +0100 Subject: [PATCH 021/233] Revert "Set title on outputs that the focused surface is intersecting with" This reverts commit 915c6df2444fdb6984db82a5e60fa8855346679b. --- seat.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/seat.c b/seat.c index 6d7448f..c955d85 100644 --- a/seat.c +++ b/seat.c @@ -853,19 +853,10 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) } view_activate(view, true); - - struct wlr_box surface_box; - wlr_surface_get_extends(view->wlr_surface, &surface_box); - char *title = view_get_title(view); struct cg_output *output; wl_list_for_each(output, &server->outputs, link) { - struct wlr_box *output_box = - wlr_output_layout_get_box(view->server->output_layout, output->wlr_output); - struct wlr_box intersection; - if (wlr_box_intersection(&intersection, &surface_box, output_box)) { - output_set_window_title(output, title); - } + output_set_window_title(output, title); } free(title); From 22adaae7151b186c1d9a0cae7fb3d2d8208f1416 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 26 Dec 2019 17:25:22 +0100 Subject: [PATCH 022/233] output: log error when failing to allocate output --- output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/output.c b/output.c index b3eddb0..4e20d31 100644 --- a/output.c +++ b/output.c @@ -363,6 +363,7 @@ handle_new_output(struct wl_listener *listener, void *data) struct cg_output *output = calloc(1, sizeof(struct cg_output)); if (!output) { + wlr_log(WLR_ERROR, "Failed to allocate output"); return; } From 21229984ffa794c36a24d3671cb2adfd50ab7f16 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 29 Dec 2019 13:17:30 +0100 Subject: [PATCH 023/233] view: use output layout to set x,y coordinates --- view.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/view.c b/view.c index 36a69d0..bd425d6 100644 --- a/view.c +++ b/view.c @@ -159,41 +159,26 @@ view_activate(struct cg_view *view, bool activate) view->impl->activate(view, activate); } -static void -get_view_output_dimensions(struct cg_view *view, int *output_width, int *output_height) -{ - *output_width = 0; - *output_height = 0; - struct cg_output *output; - wl_list_for_each(output, &view->server->outputs, link) { - int h, w; - wlr_output_transformed_resolution(output->wlr_output, &w, &h); - *output_width += w; - if (h > *output_height) { - *output_height = h; - } - } -} - static void view_maximize(struct cg_view *view) { - int output_width, output_height; - get_view_output_dimensions(view, &output_width, &output_height); - view->impl->maximize(view, output_width, output_height); + struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); + + view->x = layout_box->x; + view->y = layout_box->y; + view->impl->maximize(view, layout_box->width, layout_box->height); } static void view_center(struct cg_view *view) { - int output_width, output_height; - get_view_output_dimensions(view, &output_width, &output_height); + struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); int width, height; view->impl->get_geometry(view, &width, &height); - view->x = (output_width - width) / 2; - view->y = (output_height - height) / 2; + view->x = (layout_box->width - width) / 2; + view->y = (layout_box->height - height) / 2; } void From 95b7782c728f2f4c7636f14475e14bf74f57a1a9 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 29 Dec 2019 16:07:14 +0100 Subject: [PATCH 024/233] Be explicit about output- and layout coordinates --- output.c | 61 ++++++++++++++++++++++++++++------------------------- seat.c | 4 ++-- seat.h | 5 +++-- view.c | 8 +++---- view.h | 4 +++- xdg_shell.c | 6 +++--- 6 files changed, 47 insertions(+), 41 deletions(-) diff --git a/output.c b/output.c index 4e20d31..47f8b93 100644 --- a/output.c +++ b/output.c @@ -64,8 +64,9 @@ send_frame_done(struct wlr_surface *surface, int _unused, int _not_used, void *d /* Used to move all of the data necessary to damage a surface. */ struct damage_data { struct cg_output *output; - double x; - double y; + + /* Output-local coordinates. */ + double ox, oy; bool whole; }; @@ -80,12 +81,9 @@ damage_surface(struct wlr_surface *surface, int sx, int sy, void *data) return; } - double x = ddata->x + sx, y = ddata->y + sy; - wlr_output_layout_output_coords(output->server->output_layout, wlr_output, &x, &y); - struct wlr_box box = { - .x = x * wlr_output->scale, - .y = y * wlr_output->scale, + .x = (ddata->ox + sx) * wlr_output->scale, + .y = (ddata->oy + sy) * wlr_output->scale, .width = surface->current.width * wlr_output->scale, .height = surface->current.height * wlr_output->scale, }; @@ -118,7 +116,9 @@ struct render_data { struct wlr_output *output; struct timespec *when; pixman_region32_t *damage; - double x, y; + + /* Output-local coordinates. */ + double ox, oy; }; static void @@ -137,12 +137,9 @@ render_surface(struct wlr_surface *surface, int sx, int sy, void *data) return; } - double x = rdata->x + sx, y = rdata->y + sy; - wlr_output_layout_output_coords(rdata->output_layout, output, &x, &y); - struct wlr_box box = { - .x = x * output->scale, - .y = y * output->scale, + .x = (rdata->ox + sx) * output->scale, + .y = (rdata->oy + sy) * output->scale, .width = surface->current.width * output->scale, .height = surface->current.height * output->scale, }; @@ -175,14 +172,16 @@ drag_icons_for_each_surface(struct cg_server *server, wlr_surface_iterator_func_ void *data) { struct render_data *rdata = data; + struct wlr_output *wlr_output = rdata->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) { continue; } - rdata->x = drag_icon->x; - rdata->y = drag_icon->y; + rdata->ox = drag_icon->x; + rdata->oy = drag_icon->y; + wlr_output_layout_output_coords(server->output_layout, wlr_output, &rdata->ox, &rdata->oy); wlr_surface_for_each_surface(drag_icon->wlr_drag_icon->surface, iterator, data); @@ -240,8 +239,9 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) struct cg_view *view; wl_list_for_each_reverse(view, &output->server->views, link) { - rdata.x = view->x; - rdata.y = view->y; + rdata.ox = view->lx; + rdata.oy = view->ly; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &rdata.ox, &rdata.oy); view_for_each_surface(view, render_surface, &rdata); } @@ -404,38 +404,41 @@ handle_new_output(struct wl_listener *listener, void *data) } void -output_damage_view_surface(struct cg_output *cg_output, struct cg_view *view) +output_damage_view_surface(struct cg_output *output, struct cg_view *view) { struct damage_data data = { - .output = cg_output, - .x = view->x, - .y = view->y, + .output = output, + .ox = view->lx, + .oy = view->ly, .whole = false, }; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); view_for_each_surface(view, damage_surface, &data); } void -output_damage_view_whole(struct cg_output *cg_output, struct cg_view *view) +output_damage_view_whole(struct cg_output *output, struct cg_view *view) { struct damage_data data = { - .output = cg_output, - .x = view->x, - .y = view->y, + .output = output, + .ox = view->lx, + .oy = view->ly, .whole = true, }; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); view_for_each_surface(view, damage_surface, &data); } void -output_damage_drag_icon(struct cg_output *cg_output, struct cg_drag_icon *drag_icon) +output_damage_drag_icon(struct cg_output *output, struct cg_drag_icon *drag_icon) { struct damage_data data = { - .output = cg_output, - .x = drag_icon->x, - .y = drag_icon->y, + .output = output, + .ox = drag_icon->x, + .oy = drag_icon->y, .whole = true, }; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); wlr_surface_for_each_surface(drag_icon->wlr_drag_icon->surface, damage_surface, &data); diff --git a/seat.c b/seat.c index c955d85..bf73bb0 100644 --- a/seat.c +++ b/seat.c @@ -43,8 +43,8 @@ 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->x; - double view_sy = ly - view->y; + 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); diff --git a/seat.h b/seat.h index 11acf56..c81dfa6 100644 --- a/seat.h +++ b/seat.h @@ -78,8 +78,9 @@ struct cg_drag_icon { struct wl_list link; // seat::drag_icons struct cg_seat *seat; struct wlr_drag_icon *wlr_drag_icon; - double x; - double y; + + /* The drag icon has a position in layout coordinates. */ + double x, y; struct wl_listener destroy; }; diff --git a/view.c b/view.c index bd425d6..3a50d8f 100644 --- a/view.c +++ b/view.c @@ -164,8 +164,8 @@ view_maximize(struct cg_view *view) { struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); - view->x = layout_box->x; - view->y = layout_box->y; + view->lx = layout_box->x; + view->ly = layout_box->y; view->impl->maximize(view, layout_box->width, layout_box->height); } @@ -177,8 +177,8 @@ view_center(struct cg_view *view) int width, height; view->impl->get_geometry(view, &width, &height); - view->x = (layout_box->width - width) / 2; - view->y = (layout_box->height - height) / 2; + view->lx = (layout_box->width - width) / 2; + view->ly = (layout_box->height - height) / 2; } void diff --git a/view.h b/view.h index d574f4f..e163073 100644 --- a/view.h +++ b/view.h @@ -26,7 +26,9 @@ struct cg_view { struct wl_list link; // server::views struct wl_list children; // cg_view_child::link struct wlr_surface *wlr_surface; - int x, y; + + /* The view has a position in layout coordinates. */ + int lx, ly; enum cg_view_type type; const struct cg_view_impl *impl; diff --git a/xdg_shell.c b/xdg_shell.c index a5c439e..2e47eb2 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -97,12 +97,12 @@ popup_unconstrain(struct cg_xdg_popup *popup) struct wlr_box *popup_box = &popup->wlr_popup->geometry; struct wlr_output_layout *output_layout = server->output_layout; - struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, view->x + popup_box->x, view->y + popup_box->y); + struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, view->lx + popup_box->x, view->ly + popup_box->y); struct wlr_box *output_box = wlr_output_layout_get_box(output_layout, wlr_output); struct wlr_box output_toplevel_box = { - .x = output_box->x - view->x, - .y = output_box->y - view->y, + .x = output_box->x - view->lx, + .y = output_box->y - view->ly, .width = output_box->width, .height = output_box->height }; From 1c59946e2081c4d096e9163aea0641cd7793b26d Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 26 Dec 2019 12:03:38 +0100 Subject: [PATCH 025/233] Rename view_damage_surface to view_damage_part To better align it with its counterpart view_damage_whole --- view.c | 4 ++-- view.h | 2 +- xdg_shell.c | 2 +- xwayland.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/view.c b/view.c index 3a50d8f..ee3ba73 100644 --- a/view.c +++ b/view.c @@ -28,7 +28,7 @@ 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_surface(child->view); + view_damage_part(child->view); } static void subsurface_create(struct cg_view *view, struct wlr_subsurface *wlr_subsurface); @@ -136,7 +136,7 @@ view_is_transient_for(struct cg_view *child, struct cg_view *parent) { } void -view_damage_surface(struct cg_view *view) +view_damage_part(struct cg_view *view) { struct cg_output *output; wl_list_for_each(output, &view->server->outputs, link) { diff --git a/view.h b/view.h index e163073..ffbd364 100644 --- a/view.h +++ b/view.h @@ -71,7 +71,7 @@ struct cg_subsurface { 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_surface(struct cg_view *view); +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); diff --git a/xdg_shell.c b/xdg_shell.c index 2e47eb2..3334082 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -242,7 +242,7 @@ 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_surface(view); + view_damage_part(view); } static void diff --git a/xwayland.c b/xwayland.c index db31a93..08c181f 100644 --- a/xwayland.c +++ b/xwayland.c @@ -120,7 +120,7 @@ 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_surface(view); + view_damage_part(view); } static void From 530b32d49612bdc0baa050d9cc09cda548201ac0 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 5 Jan 2020 12:59:00 +0100 Subject: [PATCH 026/233] xwayland: fix regression after 95b7782 Fixes #101 --- xwayland.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xwayland.c b/xwayland.c index 08c181f..7d82fb5 100644 --- a/xwayland.c +++ b/xwayland.c @@ -143,8 +143,8 @@ handle_xwayland_surface_map(struct wl_listener *listener, void *data) struct cg_view *view = &xwayland_view->view; if (!xwayland_view_should_manage(view)) { - view->x = xwayland_view->xwayland_surface->x; - view->y = xwayland_view->xwayland_surface->y; + view->lx = xwayland_view->xwayland_surface->x; + view->ly = xwayland_view->xwayland_surface->y; } xwayland_view->commit.notify = handle_xwayland_surface_commit; From 651d579c30e8636cc047272136702296076dba8a Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 5 Jan 2020 13:13:32 +0100 Subject: [PATCH 027/233] seat: be explicit about output- and layout coordinates This commit follows up on 95b7782c728f2f4c7636f14475e14bf74f57a1a9 --- output.c | 8 ++++---- seat.c | 18 +++++++++--------- seat.h | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/output.c b/output.c index 47f8b93..733bc4f 100644 --- a/output.c +++ b/output.c @@ -179,8 +179,8 @@ drag_icons_for_each_surface(struct cg_server *server, wlr_surface_iterator_func_ if (!drag_icon->wlr_drag_icon->mapped) { continue; } - rdata->ox = drag_icon->x; - rdata->oy = drag_icon->y; + rdata->ox = drag_icon->lx; + rdata->oy = drag_icon->ly; wlr_output_layout_output_coords(server->output_layout, wlr_output, &rdata->ox, &rdata->oy); wlr_surface_for_each_surface(drag_icon->wlr_drag_icon->surface, iterator, @@ -434,8 +434,8 @@ output_damage_drag_icon(struct cg_output *output, struct cg_drag_icon *drag_icon { struct damage_data data = { .output = output, - .ox = drag_icon->x, - .oy = drag_icon->y, + .ox = drag_icon->lx, + .oy = drag_icon->ly, .whole = true, }; wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); diff --git a/seat.c b/seat.c index bf73bb0..a723eac 100644 --- a/seat.c +++ b/seat.c @@ -428,8 +428,8 @@ handle_touch_down(struct wl_listener *listener, void *data) if (serial && wlr_seat_touch_num_points(seat->seat) == 1) { seat->touch_id = event->touch_id; - seat->touch_x = lx; - seat->touch_y = ly; + seat->touch_lx = lx; + seat->touch_ly = ly; press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); } @@ -450,7 +450,7 @@ handle_touch_up(struct wl_listener *listener, void *data) if (wlr_seat_touch_num_points(seat->seat) == 1) { press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED, - seat->touch_x, seat->touch_y); + seat->touch_lx, seat->touch_ly); } wlr_seat_touch_notify_up(seat->seat, event->time_msec, event->touch_id); @@ -487,8 +487,8 @@ handle_touch_motion(struct wl_listener *listener, void *data) } if (event->touch_id == seat->touch_id) { - seat->touch_x = lx; - seat->touch_y = ly; + seat->touch_lx = lx; + seat->touch_ly = ly; } wlr_idle_notify_activity(seat->server->idle, seat->seat); @@ -603,16 +603,16 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) case WLR_DRAG_GRAB_KEYBOARD: return; case WLR_DRAG_GRAB_KEYBOARD_POINTER: - drag_icon->x = seat->cursor->x; - drag_icon->y = seat->cursor->y; + drag_icon->lx = seat->cursor->x; + drag_icon->ly = seat->cursor->y; break; case WLR_DRAG_GRAB_KEYBOARD_TOUCH: point = wlr_seat_touch_get_point(seat->seat, wlr_icon->drag->touch_id); if (!point) { return; } - drag_icon->x = seat->touch_x; - drag_icon->y = seat->touch_y; + drag_icon->lx = seat->touch_lx; + drag_icon->ly = seat->touch_ly; break; } diff --git a/seat.h b/seat.h index c81dfa6..f4a4af2 100644 --- a/seat.h +++ b/seat.h @@ -33,8 +33,8 @@ struct cg_seat { struct wl_listener cursor_frame; int32_t touch_id; - double touch_x; - double touch_y; + double touch_lx; + double touch_ly; struct wl_listener touch_down; struct wl_listener touch_up; struct wl_listener touch_motion; @@ -80,7 +80,7 @@ struct cg_drag_icon { struct wlr_drag_icon *wlr_drag_icon; /* The drag icon has a position in layout coordinates. */ - double x, y; + double lx, ly; struct wl_listener destroy; }; From 8f6ffa1419dcbd07588f55bfc1568f67daf5765e Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 5 Jan 2020 13:42:17 +0100 Subject: [PATCH 028/233] Use hard tabs --- cage.c | 4 ++-- output.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cage.c b/cage.c index 5a4a855..64cd6df 100644 --- a/cage.c +++ b/cage.c @@ -343,7 +343,7 @@ main(int argc, char *argv[]) xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); if (!xcursor_manager) { wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); - ret = 1; + ret = 1; goto end; } @@ -371,7 +371,7 @@ main(int argc, char *argv[]) if (!socket) { wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket"); ret = 1; - goto end; + goto end; } if (!wlr_backend_start(server.backend)) { diff --git a/output.c b/output.c index 733bc4f..e6a87a9 100644 --- a/output.c +++ b/output.c @@ -273,7 +273,7 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) pixman_region32_fini(&frame_damage); if (!wlr_output_commit(output->wlr_output)) { - wlr_log(WLR_ERROR, "Could not commit output"); + wlr_log(WLR_ERROR, "Could not commit output"); goto buffer_damage_finish; } From 51e6c760da51e2b885737d61a61cdc965bb9269d Mon Sep 17 00:00:00 2001 From: Tristan Daniel Date: Mon, 6 Jan 2020 03:30:41 +0100 Subject: [PATCH 029/233] Update new output handler for wlroots 0.9.0 Following breaking changes in wlroots 0.9.0, wlr_output_commit must be called after wlr_output_set_mode, wlr_output_set_transform and wlr_output_enable. Additionally, wlr_output_enable is no longer implicitly called by wlr_output_set_mode. Fixes #102 --- output.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/output.c b/output.c index e6a87a9..1171a6e 100644 --- a/output.c +++ b/output.c @@ -401,6 +401,9 @@ handle_new_output(struct wl_listener *listener, void *data) /* Place the cursor in the center of the screen. */ wlr_cursor_warp(server->seat->cursor, NULL, wlr_output->width / 2, wlr_output->height / 2); wlr_output_damage_add_whole(output->damage); + + wlr_output_enable(wlr_output, true); + wlr_output_commit(wlr_output); } void From 84216ca2a417b237ad61c11e2f3ebbcb91681ece Mon Sep 17 00:00:00 2001 From: Tristan Daniel Date: Mon, 6 Jan 2020 20:03:09 +0100 Subject: [PATCH 030/233] output: call wlr_output_rollback if not rendering Required by wlroots 0.9.0. --- output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/output.c b/output.c index 1171a6e..4517c80 100644 --- a/output.c +++ b/output.c @@ -206,6 +206,7 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) } if (!needs_frame) { + wlr_output_rollback(output->wlr_output); goto buffer_damage_finish; } From bfd7d605b89fc5436505611ad01806fc11aa9a08 Mon Sep 17 00:00:00 2001 From: Tristan Daniel Date: Mon, 6 Jan 2020 20:21:14 +0100 Subject: [PATCH 031/233] meson: require wlroots 0.9.1 And update CI builds accordingly. --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 3 +-- .builds/freebsd.yml | 3 +-- meson.build | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 5ed154d..ad5f045 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -17,7 +17,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.8.1 + git checkout 0.9.1 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 7a5b8f1..54bc9fd 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -15,8 +15,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # Need this to compile 0.8.1. - git checkout d113e48a2a32542fe6e12f1759f07888364609bf + git checkout 0.9.1 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index dba93eb..dd0d35d 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -18,8 +18,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - # Need this to compile 0.8.1 - git checkout d113e48a2a32542fe6e12f1759f07888364609bf + git checkout 0.9.1 meson --prefix=/usr/local build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/meson.build b/meson.build index 0f2c9ff..cbb8f2b 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.6.0') +wlroots = dependency('wlroots', version: '>= 0.9.1') wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') pixman = dependency('pixman-1') From 2db815aa2375c6b89230651737b2017830ef0fa9 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 26 Dec 2019 12:00:51 +0100 Subject: [PATCH 032/233] Refactor surface damaging and rendering code This is based on code from Sway, which is also MIT licensed hence compatible. This makes the surface damaging and rendering code easier to follow and makes it easier to import future changes to Sway as well. --- LICENSE | 3 +- meson.build | 4 + output.c | 382 ++++++++++++++++++++-------------------------------- output.h | 8 +- render.c | 188 ++++++++++++++++++++++++++ render.h | 8 ++ seat.c | 5 +- util.c | 36 +++++ util.h | 11 ++ view.c | 6 +- 10 files changed, 408 insertions(+), 243 deletions(-) create mode 100644 render.c create mode 100644 render.h create mode 100644 util.c create mode 100644 util.h diff --git a/LICENSE b/LICENSE index 41a8d9f..b047cf6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2018-2019 Jente Hidskes +Copyright (c) 2018-2020 Jente Hidskes +Copyright (c) 2019 The Sway authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/meson.build b/meson.build index cbb8f2b..6121eee 100644 --- a/meson.build +++ b/meson.build @@ -83,7 +83,9 @@ cage_sources = [ 'cage.c', 'idle_inhibit_v1.c', 'output.c', + 'render.c', 'seat.c', + 'util.c', 'view.c', 'xdg_shell.c', ] @@ -94,8 +96,10 @@ cage_headers = [ configuration: conf_data), 'idle_inhibit_v1.h', 'output.h', + 'render.h', 'seat.h', 'server.h', + 'util.h', 'view.h', 'xdg_shell.h', ] diff --git a/output.c b/output.c index 4517c80..862911e 100644 --- a/output.c +++ b/output.c @@ -1,7 +1,8 @@ /* * Cage: A Wayland kiosk. * - * Copyright (C) 2018-2019 Jente Hidskes + * Copyright (C) 2018-2020 Jente Hidskes + * Copyright (C) 2019 The Sway authors * * See the LICENSE file accompanying this file. */ @@ -31,65 +32,133 @@ #include #include "output.h" +#include "render.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); +static void output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data); - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; +struct surface_iterator_data { + cg_surface_iterator_func_t user_iterator; + void *user_data; - 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); -} - -static void -send_frame_done(struct wlr_surface *surface, int _unused, int _not_used, void *data) -{ - struct timespec *now = data; - wlr_surface_send_frame_done(surface, now); -} - -/* Used to move all of the data necessary to damage a surface. */ -struct damage_data { struct cg_output *output; /* Output-local coordinates. */ double ox, oy; - bool whole; }; -static void -damage_surface(struct wlr_surface *surface, int sx, int sy, void *data) +// TODO: this doesn't just get the surface box; it also indicates if said box overlaps +// with the current output box. +static bool // TODO: remove surface_iterator_data argument? +get_surface_box(struct surface_iterator_data *data, + struct wlr_surface *surface, int sx, int sy, + struct wlr_box *surface_box) { - struct damage_data *ddata = data; - struct cg_output *output = ddata->output; - struct wlr_output *wlr_output = output->wlr_output; + struct cg_output *output = data->output; if (!wlr_surface_has_buffer(surface)) { - return; + return false; } struct wlr_box box = { - .x = (ddata->ox + sx) * wlr_output->scale, - .y = (ddata->oy + sy) * wlr_output->scale, - .width = surface->current.width * wlr_output->scale, - .height = surface->current.height * wlr_output->scale, + .x = sx + surface->sx, + .y = sy + surface->sy, + .width = surface->current.width, + .height = surface->current.height, }; - if (ddata->whole) { - wlr_output_damage_add_box(output->damage, &box); + struct cg_server *server = output->server; + struct wlr_box *output_box = wlr_output_layout_get_box(server->output_layout, output->wlr_output); + + struct wlr_box intersection; + bool intersects = wlr_box_intersection(&intersection, output_box, &box); + + // TODO: why can't we do this before the intersection check? + box.x += data->ox; + box.y += data->oy; + + if (surface_box) { + memcpy(surface_box, &box, sizeof(struct wlr_box)); + } + + return intersects; +} + +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 wlr_box box; + bool intersects = get_surface_box(data, surface, sx, sy, &box); + if (!intersects) { + return; + } + + data->user_iterator(data->output, surface, &box, data->user_data); +} + +static 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); +} + +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); +} + +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 +damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_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); @@ -103,188 +172,74 @@ damage_surface(struct wlr_surface *surface, int sx, int sy, void *data) wlr_region_expand(&damage, &damage, ceil(wlr_output->scale) - surface->current.scale); } - pixman_region32_translate(&damage, box.x, box.y); + pixman_region32_translate(&damage, box->x, box->y); wlr_output_damage_add(output->damage, &damage); pixman_region32_fini(&damage); } } -/* Used to move all of the data necessary to render a surface from the - * top-level frame handler to the per-surface render function. */ -struct render_data { - struct wlr_output_layout *output_layout; - struct wlr_output *output; - struct timespec *when; - pixman_region32_t *damage; - - /* Output-local coordinates. */ - double ox, oy; -}; - -static void -render_surface(struct wlr_surface *surface, int sx, int sy, void *data) +void +output_damage_surface(struct cg_output *output, struct wlr_surface *surface, + double lx, double ly, bool whole) { - struct render_data *rdata = data; - struct wlr_output *output = rdata->output; + 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); +} - if (!wlr_surface_has_buffer(surface)) { - return; +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); + } } - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - wlr_log(WLR_DEBUG, "Cannot obtain surface texture"); - return; - } - - struct wlr_box box = { - .x = (rdata->ox + sx) * output->scale, - .y = (rdata->oy + sy) * output->scale, - .width = surface->current.width * output->scale, - .height = surface->current.height * output->scale, - }; - - 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, rdata->damage); - if (!pixman_region32_not_empty(&damage)) { - goto buffer_damage_finish; - } - - float matrix[9]; - enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix); - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; i++) { - scissor_output(output, &rects[i]); - wlr_render_texture_with_matrix(surface->renderer, texture, matrix, 1); - } - - buffer_damage_finish: - pixman_region32_fini(&damage); } static void -drag_icons_for_each_surface(struct cg_server *server, wlr_surface_iterator_func_t iterator, - void *data) +output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data) { - struct render_data *rdata = data; - struct wlr_output *wlr_output = rdata->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) { - continue; - } - rdata->ox = drag_icon->lx; - rdata->oy = drag_icon->ly; - wlr_output_layout_output_coords(server->output_layout, wlr_output, &rdata->ox, &rdata->oy); - wlr_surface_for_each_surface(drag_icon->wlr_drag_icon->surface, - iterator, - 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); } static void handle_output_damage_frame(struct wl_listener *listener, void *data) { struct cg_output *output = wl_container_of(listener, output, damage_frame); - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->server->backend); - - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); bool needs_frame; - pixman_region32_t buffer_damage; - pixman_region32_init(&buffer_damage); - if (!wlr_output_damage_attach_render(output->damage, &needs_frame, &buffer_damage)) { + 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 buffer_damage_finish; + goto damage_finish; } if (!needs_frame) { wlr_output_rollback(output->wlr_output); - goto buffer_damage_finish; + goto damage_finish; } - wlr_renderer_begin(renderer, output->wlr_output->width, output->wlr_output->height); + output_render(output, &damage); - if (!pixman_region32_not_empty(&buffer_damage)) { - wlr_log(WLR_DEBUG, "Output isn't damaged but needs a buffer frame"); - goto renderer_end; - } + damage_finish: + pixman_region32_fini(&damage); -#ifdef DEBUG - if (output->server->debug_damage_tracking) { - wlr_renderer_clear(renderer, (float[]){1, 0, 0, 1}); - } -#endif - - float color[4] = {0, 0, 0, 1.0}; - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&buffer_damage, &nrects); - for (int i = 0; i < nrects; i++) { - scissor_output(output->wlr_output, &rects[i]); - wlr_renderer_clear(renderer, color); - } - - struct render_data rdata = { - .output_layout = output->server->output_layout, - .output = output->wlr_output, - .when = &now, - .damage = &buffer_damage, - }; - - struct cg_view *view; - wl_list_for_each_reverse(view, &output->server->views, link) { - rdata.ox = view->lx; - rdata.oy = view->ly; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &rdata.ox, &rdata.oy); - view_for_each_surface(view, render_surface, &rdata); - } - - drag_icons_for_each_surface(output->server, render_surface, &rdata); - - 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(output->wlr_output, &buffer_damage); - wlr_renderer_scissor(renderer, NULL); - wlr_renderer_end(renderer); - - int output_width, output_height; - wlr_output_transformed_resolution(output->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(output->wlr_output->transform); - wlr_region_transform(&frame_damage, &output->damage->current, transform, output_width, output_height); - -#ifdef DEBUG - if (output->server->debug_damage_tracking) { - pixman_region32_union_rect(&frame_damage, &frame_damage, 0, 0, output_width, output_height); - } -#endif - - wlr_output_set_damage(output->wlr_output, &frame_damage); - pixman_region32_fini(&frame_damage); - - if (!wlr_output_commit(output->wlr_output)) { - wlr_log(WLR_ERROR, "Could not commit output"); - goto buffer_damage_finish; - } - - buffer_damage_finish: - pixman_region32_fini(&buffer_damage); - - wl_list_for_each_reverse(view, &output->server->views, link) { - view_for_each_surface(view, send_frame_done, &now); - } - drag_icons_for_each_surface(output->server, send_frame_done, &now); + struct send_frame_done_data frame_data = {0}; + clock_gettime(CLOCK_MONOTONIC, &frame_data.when); + send_frame_done(output, &frame_data); } static void @@ -407,47 +362,6 @@ handle_new_output(struct wl_listener *listener, void *data) wlr_output_commit(wlr_output); } -void -output_damage_view_surface(struct cg_output *output, struct cg_view *view) -{ - struct damage_data data = { - .output = output, - .ox = view->lx, - .oy = view->ly, - .whole = false, - }; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - view_for_each_surface(view, damage_surface, &data); -} - -void -output_damage_view_whole(struct cg_output *output, struct cg_view *view) -{ - struct damage_data data = { - .output = output, - .ox = view->lx, - .oy = view->ly, - .whole = true, - }; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - view_for_each_surface(view, damage_surface, &data); -} - -void -output_damage_drag_icon(struct cg_output *output, struct cg_drag_icon *drag_icon) -{ - struct damage_data data = { - .output = output, - .ox = drag_icon->lx, - .oy = drag_icon->ly, - .whole = true, - }; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - wlr_surface_for_each_surface(drag_icon->wlr_drag_icon->surface, - damage_surface, - &data); -} - void output_set_window_title(struct cg_output *output, const char *title) { diff --git a/output.h b/output.h index 1563799..608f762 100644 --- a/output.h +++ b/output.h @@ -23,10 +23,12 @@ struct cg_output { 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_damage_view_surface(struct cg_output *output, struct cg_view *view); -void output_damage_view_whole(struct cg_output *cg_output, struct cg_view *view); -void output_damage_drag_icon(struct cg_output *output, struct cg_drag_icon *icon); +void output_view_for_each_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 new file mode 100644 index 0000000..b75ad7d --- /dev/null +++ b/render.c @@ -0,0 +1,188 @@ +/* + * Cage: A Wayland kiosk. + * + * Copyright (C) 2018-2020 Jente Hidskes + * Copyright (C) 2019 The Sway authors + * + * See the LICENSE file accompanying this file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "output.h" +#include "seat.h" +#include "server.h" +#include "util.h" +#include "view.h" + +static void +scissor_output(struct wlr_output *output, pixman_box32_t *rect) +{ + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + + int output_width, output_height; + wlr_output_transformed_resolution(output, &output_width, &output_height); + enum wl_output_transform transform = wlr_output_transform_invert(output->transform); + wlr_box_transform(&box, &box, transform, output_width, output_height); + + wlr_renderer_scissor(renderer, &box); +} + +struct render_data { + pixman_region32_t *damage; +}; + +static void +render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage, + struct wlr_texture *texture, const struct wlr_box *box, + const float matrix[static 9]) +{ + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union_rect(&damage, &damage, box->x, box->y, box->width, box->height); + pixman_region32_intersect(&damage, &damage, output_damage); + if (!pixman_region32_not_empty(&damage)) { + goto damage_finish; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; i++) { + scissor_output(wlr_output, &rects[i]); + wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); + } + + damage_finish: + pixman_region32_fini(&damage); +} + +static void +render_surface_iterator(struct cg_output *output, struct wlr_surface *surface, + struct wlr_box *box, void *user_data) +{ + struct render_data *data = user_data; + struct wlr_output *wlr_output = output->wlr_output; + pixman_region32_t *output_damage = data->damage; + + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (!texture) { + wlr_log(WLR_DEBUG, "Cannot obtain surface texture"); + return; + } + + scale_box(box, wlr_output->scale); + + float matrix[9]; + enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); + wlr_matrix_project_box(matrix, box, transform, 0.0f, wlr_output->transform_matrix); + + render_texture(wlr_output, output_damage, texture, box, matrix); +} + +static void +render_drag_icons(struct cg_output *output, pixman_region32_t *damage, struct wl_list *drag_icons) +{ + struct render_data data = { + .damage = damage, + }; + output_drag_icons_for_each_surface(output, drag_icons, render_surface_iterator, &data); +} + +/** + * Render all toplevels without descending into popups. + */ +static void +render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage) +{ + struct render_data data = { + .damage = damage, + }; + + output_view_for_each_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(server->backend); + 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); + // TODO: popups on top view, possibly use focused view for this + // TODO: render only top view, possibly use focused view for this + } + + 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 new file mode 100644 index 0000000..085b00b --- /dev/null +++ b/render.h @@ -0,0 +1,8 @@ +#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 a723eac..3f400db 100644 --- a/seat.c +++ b/seat.c @@ -1,7 +1,7 @@ /* * Cage: A Wayland kiosk. * - * Copyright (C) 2018-2019 Jente Hidskes + * Copyright (C) 2018-2020 Jente Hidskes * * See the LICENSE file accompanying this file. */ @@ -586,7 +586,8 @@ 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_drag_icon(output, drag_icon); + output_damage_surface(output, drag_icon->wlr_drag_icon->surface, + drag_icon->lx, drag_icon->ly, true); } } diff --git a/util.c b/util.c new file mode 100644 index 0000000..95de499 --- /dev/null +++ b/util.c @@ -0,0 +1,36 @@ +/* + * Cage: A Wayland kiosk. + * + * Copyright (C) 2019 The Sway authors + * + * See the LICENSE file accompanying this file. + */ + +#include + +#include "util.h" + +int +scale_length(int length, int offset, float scale) +{ + /** + * One does not simply multiply the width by the scale. We allow fractional + * scaling, which means the resulting scaled width might be a decimal. + * So we round it. + * + * But even this can produce undesirable results depending on the X or Y + * offset of the box. For example, with a scale of 1.5, a box with + * width=1 should not scale to 2px if its X coordinate is 1, because the + * X coordinate would have scaled to 2px. + */ + return round((offset + length) * scale) - round(offset * scale); +} + +void +scale_box(struct wlr_box *box, float scale) +{ + box->width = scale_length(box->width, box->x, scale); + box->height = scale_length(box->height, box->y, scale); + box->x = round(box->x * scale); + box->y = round(box->y * scale); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..db6bc7d --- /dev/null +++ b/util.h @@ -0,0 +1,11 @@ +#ifndef CG_UTIL_H +#define CG_UTIL_H + +#include + +/** Apply scale to a width or height. */ +int scale_length(int length, int offset, float scale); + +void scale_box(struct wlr_box *box, float scale); + +#endif diff --git a/view.c b/view.c index ee3ba73..e22ab04 100644 --- a/view.c +++ b/view.c @@ -1,7 +1,7 @@ /* * Cage: A Wayland kiosk. * - * Copyright (C) 2018-2019 Jente Hidskes + * Copyright (C) 2018-2020 Jente Hidskes * * See the LICENSE file accompanying this file. */ @@ -140,7 +140,7 @@ view_damage_part(struct cg_view *view) { struct cg_output *output; wl_list_for_each(output, &view->server->outputs, link) { - output_damage_view_surface(output, view); + output_damage_surface(output, view->wlr_surface, view->lx, view->ly, false); } } @@ -149,7 +149,7 @@ view_damage_whole(struct cg_view *view) { struct cg_output *output; wl_list_for_each(output, &view->server->outputs, link) { - output_damage_view_whole(output, view); + output_damage_surface(output, view->wlr_surface, view->lx, view->ly, true); } } From a53dca91ce52638113e6665a2f78c4871a1a3757 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 5 Jan 2020 14:39:56 +0100 Subject: [PATCH 033/233] Render popups separately from their toplevel view when possible --- output.c | 74 ++++++++++++++++++++++++++++++++--------------------- output.h | 5 +++- render.c | 33 +++++++++++++++++++++--- view.c | 9 +++++++ view.h | 3 +++ xdg_shell.c | 8 ++++++ xwayland.c | 2 ++ 7 files changed, 101 insertions(+), 33 deletions(-) diff --git a/output.c b/output.c index 862911e..84b61aa 100644 --- a/output.c +++ b/output.c @@ -100,7 +100,7 @@ output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, vo data->user_iterator(data->output, surface, &box, data->user_data); } -static void +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) @@ -116,7 +116,7 @@ output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *su wlr_surface_for_each_surface(surface, output_for_each_surface_iterator, &data); } -void +static void output_view_for_each_surface(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, void *user_data) { @@ -132,6 +132,49 @@ output_view_for_each_surface(struct cg_output *output, struct cg_view *view, view_for_each_surface(view, output_for_each_surface_iterator, &data); } +void +output_view_for_each_popup(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(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; }; @@ -187,33 +230,6 @@ output_damage_surface(struct cg_output *output, struct wlr_surface *surface, output_surface_for_each_surface(output, surface, ox, oy, damage_surface_iterator, &whole); } -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); -} - static void handle_output_damage_frame(struct wl_listener *listener, void *data) { diff --git a/output.h b/output.h index 608f762..081c9fd 100644 --- a/output.h +++ b/output.h @@ -26,7 +26,10 @@ struct cg_output { 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_view_for_each_surface(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, void *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); +void output_view_for_each_popup(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); diff --git a/render.c b/render.c index b75ad7d..c222b8f 100644 --- a/render.c +++ b/render.c @@ -115,8 +115,32 @@ render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_reg 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); +} - output_view_for_each_surface(output, view, render_surface_iterator, &data); +static void +render_popup_iterator(struct cg_output *output, struct wlr_surface *surface, + struct wlr_box *box, void *data) +{ + /* Render this popup's surface. */ + render_surface_iterator(output, surface, box, data); + + /* Render this popup's child toplevels. */ + output_surface_for_each_surface(output, surface, box->x, box->y, + 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(output, view, render_popup_iterator, &data); } void @@ -151,8 +175,11 @@ output_render(struct cg_output *output, pixman_region32_t *damage) struct cg_view *view; wl_list_for_each_reverse(view, &server->views, link) { render_view_toplevels(view, output, damage); - // TODO: popups on top view, possibly use focused view for this - // TODO: render only top view, possibly use focused view for this + } + + 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); diff --git a/view.c b/view.c index e22ab04..b19248b 100644 --- a/view.c +++ b/view.c @@ -197,6 +197,15 @@ view_for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator view->impl->for_each_surface(view, iterator, data); } +void +view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) +{ + if (!view->impl->for_each_popup) { + return; + } + view->impl->for_each_popup(view, iterator, data); +} + void view_unmap(struct cg_view *view) { diff --git a/view.h b/view.h index ffbd364..1da861c 100644 --- a/view.h +++ b/view.h @@ -46,6 +46,8 @@ struct cg_view_impl { 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)(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); }; @@ -76,6 +78,7 @@ 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(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); diff --git a/xdg_shell.c b/xdg_shell.c index 3334082..4c6d0ee 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -222,6 +222,13 @@ for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, voi wlr_xdg_surface_for_each_surface(xdg_shell_view->xdg_surface, iterator, data); } +static void +for_each_popup(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(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) { @@ -297,6 +304,7 @@ static const struct cg_view_impl xdg_shell_view_impl = { .maximize = maximize, .destroy = destroy, .for_each_surface = for_each_surface, + .for_each_popup = for_each_popup, .wlr_surface_at = wlr_surface_at, }; diff --git a/xwayland.c b/xwayland.c index 7d82fb5..180a194 100644 --- a/xwayland.c +++ b/xwayland.c @@ -180,6 +180,8 @@ static const struct cg_view_impl xwayland_view_impl = { .maximize = maximize, .destroy = destroy, .for_each_surface = for_each_surface, + /* XWayland doesn't have a separate popup iterator. */ + .for_each_popup = NULL, .wlr_surface_at = wlr_surface_at, }; From 23f8d609ce04102b412471a356fcc86d0bc5967c Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 7 Jan 2020 14:19:34 +0100 Subject: [PATCH 034/233] output: check whether outputs are enabled --- output.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/output.c b/output.c index 84b61aa..5516f48 100644 --- a/output.c +++ b/output.c @@ -235,6 +235,10 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) { struct cg_output *output = wl_container_of(listener, output, damage_frame); + if (!output->wlr_output->enabled) { + return; + } + bool needs_frame; pixman_region32_t damage; pixman_region32_init(&damage); @@ -263,6 +267,10 @@ handle_output_transform(struct wl_listener *listener, void *data) { struct cg_output *output = wl_container_of(listener, output, transform); + if (!output->wlr_output->enabled) { + return; + } + struct cg_view *view; wl_list_for_each(view, &output->server->views, link) { view_position(view); @@ -274,6 +282,10 @@ handle_output_mode(struct wl_listener *listener, void *data) { struct cg_output *output = wl_container_of(listener, output, mode); + if (!output->wlr_output->enabled) { + return; + } + struct cg_view *view; wl_list_for_each(view, &output->server->views, link) { view_position(view); From 2f9442906d50912e76570fcbe9423e42b282ec59 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 11 Jan 2020 16:10:38 +0100 Subject: [PATCH 035/233] output: refactor get_surface_box The function also did an intersection check, so it did more than just getting the surface box. This refactoring makes it more clear. This commit also fixes a bug in coordinate spaces that makes dialogs render properly over multiple outputs. --- output.c | 58 +++++++++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/output.c b/output.c index 5516f48..48116be 100644 --- a/output.c +++ b/output.c @@ -49,55 +49,41 @@ struct surface_iterator_data { double ox, oy; }; -// TODO: this doesn't just get the surface box; it also indicates if said box overlaps -// with the current output box. -static bool // TODO: remove surface_iterator_data argument? -get_surface_box(struct surface_iterator_data *data, - struct wlr_surface *surface, int sx, int sy, - struct wlr_box *surface_box) +static bool +intersects_with_output(struct cg_output *output, struct wlr_output_layout *output_layout, struct wlr_box *surface_box) { - struct cg_output *output = data->output; - - if (!wlr_surface_has_buffer(surface)) { - return false; - } - - struct wlr_box box = { - .x = sx + surface->sx, - .y = sy + surface->sy, - .width = surface->current.width, - .height = surface->current.height, - }; - - struct cg_server *server = output->server; - struct wlr_box *output_box = wlr_output_layout_get_box(server->output_layout, output->wlr_output); + /* 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; - bool intersects = wlr_box_intersection(&intersection, output_box, &box); - - // TODO: why can't we do this before the intersection check? - box.x += data->ox; - box.y += data->oy; - - if (surface_box) { - memcpy(surface_box, &box, sizeof(struct wlr_box)); - } - - return intersects; + 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; - struct wlr_box box; - bool intersects = get_surface_box(data, surface, sx, sy, &box); - if (!intersects) { + if (!wlr_surface_has_buffer(surface)) { return; } - data->user_iterator(data->output, surface, &box, data->user_data); + 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 From 12aa43abba1bb8e7b4b17b21555fa480181cd04c Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 11 Jan 2020 16:26:14 +0100 Subject: [PATCH 036/233] output: initialise wlr_output before positioning views --- output.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/output.c b/output.c index 48116be..9d34a5a 100644 --- a/output.c +++ b/output.c @@ -324,12 +324,6 @@ 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; - struct wlr_output_mode *preferred_mode; - - preferred_mode = wlr_output_preferred_mode(wlr_output); - if (preferred_mode) { - wlr_output_set_mode(wlr_output, preferred_mode); - } struct cg_output *output = calloc(1, sizeof(struct cg_output)); if (!output) { @@ -353,15 +347,18 @@ handle_new_output(struct wl_listener *listener, void *data) 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); + } + wlr_output_set_transform(wlr_output, server->output_transform); + wlr_output_layout_add_auto(server->output_layout, wlr_output); + struct cg_view *view; wl_list_for_each(view, &output->server->views, link) { view_position(view); } - wlr_output_set_transform(wlr_output, server->output_transform); - - wlr_output_layout_add_auto(server->output_layout, wlr_output); - if (wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, From fbff19939af49976015c3615e7bcd17fe3f80ccc Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 11 Jan 2020 16:46:18 +0100 Subject: [PATCH 037/233] README: update Copyright to include 2020 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1369c6b..787226d 100644 --- a/README.md +++ b/README.md @@ -59,4 +59,4 @@ Please see [LICENSE](https://github.com/Hjdskes/cage/blob/master/LICENSE) on [GitHub](https://github.com/Hjdskes/cage). -Copyright © 2018-2019 Jente Hidskes +Copyright © 2018-2020 Jente Hidskes From cfb15d20bab983960d03815dc75a80446d1ca899 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 11 Jan 2020 16:59:55 +0100 Subject: [PATCH 038/233] xwayland: use view's (x,y) coordinate when maximizing It might happen that the (x,y) coordinate of the left-most monitor is not 0. If it isn't, this doesn't cost us anything, so better safe than sorry. --- xwayland.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xwayland.c b/xwayland.c index 180a194..cfc33f9 100644 --- a/xwayland.c +++ b/xwayland.c @@ -1,7 +1,7 @@ /* * Cage: A Wayland kiosk. * - * Copyright (C) 2018-2019 Jente Hidskes + * Copyright (C) 2018-2020 Jente Hidskes * * See the LICENSE file accompanying this file. */ @@ -84,7 +84,7 @@ static void maximize(struct cg_view *view, int output_width, int output_height) { struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); - wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, 0, 0, output_width, output_height); + wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, view->lx, view->ly, output_width, output_height); wlr_xwayland_surface_set_maximized(xwayland_view->xwayland_surface, true); } From e3f99595196916316a7f47972f26c9a3d4a1cf1b Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 11 Jan 2020 17:06:39 +0100 Subject: [PATCH 039/233] view: maximize dialog if it extends output layout If the dialog extends the output layout in at least one dimension, then the part of it that is larger than the output will be rendered of-screen. This commit maximizes such dialogs instead. Fixes #110. --- view.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/view.c b/view.c index b19248b..5f9bed0 100644 --- a/view.c +++ b/view.c @@ -159,21 +159,26 @@ view_activate(struct cg_view *view, bool activate) view->impl->activate(view, activate); } -static void -view_maximize(struct cg_view *view) +static bool +view_extends_output_layout(struct cg_view *view, struct wlr_box *layout_box) { - struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); + int width, height; + view->impl->get_geometry(view, &width, &height); + return (layout_box->height < height || layout_box->width < width); +} + +static void +view_maximize(struct cg_view *view, struct wlr_box *layout_box) +{ view->lx = layout_box->x; view->ly = layout_box->y; view->impl->maximize(view, layout_box->width, layout_box->height); } static void -view_center(struct cg_view *view) +view_center(struct cg_view *view, struct wlr_box *layout_box) { - struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); - int width, height; view->impl->get_geometry(view, &width, &height); @@ -184,10 +189,12 @@ view_center(struct cg_view *view) void view_position(struct cg_view *view) { - if (view_is_primary(view)) { - view_maximize(view); + struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); + + if (view_is_primary(view) || view_extends_output_layout(view, layout_box)) { + view_maximize(view, layout_box); } else { - view_center(view); + view_center(view, layout_box); } } From cc1f975c442ebd691b70196d76aa120ead717810 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 18 Jan 2020 11:57:16 +0100 Subject: [PATCH 040/233] cage: center cursor only on initial startup With Cage now supporting hotplugging of outputs, we shouldn't warp the cursor to the center of every new output. Rather, we should warp it only on the initial startup. --- cage.c | 4 ++++ output.c | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cage.c b/cage.c index 64cd6df..b911370 100644 --- a/cage.c +++ b/cage.c @@ -397,6 +397,10 @@ main(int argc, char *argv[]) goto end; } + /* Place the cursor in the center of the output layout. */ + struct wlr_box *layout_box = wlr_output_layout_get_box(server.output_layout, NULL); + wlr_cursor_warp(server.seat->cursor, NULL, layout_box->width / 2, layout_box->height / 2); + wl_display_run(server.wl_display); #if CAGE_HAS_XWAYLAND diff --git a/output.c b/output.c index 9d34a5a..5b79e76 100644 --- a/output.c +++ b/output.c @@ -365,12 +365,10 @@ handle_new_output(struct wl_listener *listener, void *data) wlr_output->scale); } - /* Place the cursor in the center of the screen. */ - wlr_cursor_warp(server->seat->cursor, NULL, wlr_output->width / 2, wlr_output->height / 2); - wlr_output_damage_add_whole(output->damage); - wlr_output_enable(wlr_output, true); wlr_output_commit(wlr_output); + + wlr_output_damage_add_whole(output->damage); } void From 30d805d6ff82f7a7d55ee7ecf07922753b49e42e Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 25 Jan 2020 22:40:39 +0100 Subject: [PATCH 041/233] CI: build against wlroots 0.10.0 There are no breaking changes otherwise, so in meson.build we can leave the version to anything greater than 0.9.1. --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index ad5f045..280d3e9 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -17,7 +17,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.9.1 + git checkout 0.10.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 54bc9fd..dfb60c7 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -15,7 +15,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.9.1 + git checkout 0.10.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index dd0d35d..ae5b93d 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -18,7 +18,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.9.1 + git checkout 0.10.0 meson --prefix=/usr/local build -Dexamples=false ninja -C build sudo ninja -C build install From a63c75c849da07c6437636a1c47e14c7626ca7ad Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 25 Jan 2020 22:51:15 +0100 Subject: [PATCH 042/233] Cage: check if XDG_RUNTIME_DIR is set Wayland requires this environment variable to be set, see https://manpages.debian.org/experimental/libwayland-doc/wl_display_connect.3.en.html --- cage.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cage.c b/cage.c index b911370..9526e82 100644 --- a/cage.c +++ b/cage.c @@ -194,6 +194,12 @@ main(int argc, char *argv[]) wlr_log_init(WLR_ERROR, NULL); #endif + /* Wayland requires XDG_RUNTIME_DIR to be set. */ + if (!getenv("XDG_RUNTIME_DIR")) { + wlr_log(WLR_ERROR, "XDG_RUNTIME_DIR is not set in the environment"); + return 1; + } + server.wl_display = wl_display_create(); if (!server.wl_display) { wlr_log(WLR_ERROR, "Cannot allocate a Wayland display"); From 5e27683961087a39c3839a073e0a983d63bc54f8 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Jan 2020 16:03:05 +0100 Subject: [PATCH 043/233] Move docs to the wiki --- README.md | 8 ++++---- docs/env_vars.md | 35 ----------------------------------- 2 files changed, 4 insertions(+), 39 deletions(-) delete mode 100644 docs/env_vars.md diff --git a/README.md b/README.md index 787226d..8c702ec 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ This is Cage, a Wayland kiosk. A kiosk runs a single, maximized application. -This README is only relevant for development resources and -instructions. For a description of Cage and installation instructions -for end-users, please see [its project +This README is only relevant for development resources and instructions. For a +description of Cage and installation instructions for end-users, please see +[the Wiki](https://github.com/Hjdskes/cage/wiki/) and [its project page](https://www.hjdskes.nl/projects/cage). ## Release signatures @@ -43,7 +43,7 @@ a TTY, it'll run with the KMS+DRM backend. In debug mode (default build type with Meson), press Alt+Esc to quit. To build a release build, use `meson build --buildtype=release`. -For more information, see the `docs/` folder. +For more information, see the [Wiki](https://github.com/Hjdskes/cage/wiki). Cage is based on the annotated source of tinywl and rootston. diff --git a/docs/env_vars.md b/docs/env_vars.md deleted file mode 100644 index c24a14f..0000000 --- a/docs/env_vars.md +++ /dev/null @@ -1,35 +0,0 @@ -# Environment variables - -Cage sets the following environment variables: - -* `DISPLAY`: if compiled with Xwayland support, this will be set to the name of - the X display used for Xwayland. -* `WAYLAND_DISPLAY`: specifies the name of the Wayland display that Cage is - running on. - -The following environment variables can be used to configure behavior of -libraries that Cage uses. Effectively, these environment variables configure -the Cage session. - -## XKB environment variables - -``` -XKB_DEFAULT_RULES -XKB_DEFAULT_MODEL -XKB_DEFAULT_LAYOUT -XKB_DEFAULT_VARIANT -XKB_DEFAULT_OPTIONS -``` - -These environment variables configure the XKB keyboard settings. See -xkeyboard-config(7). - -## Wlroots environment variables - -* `DISPLAY`: if set probe X11 backend. -* `WAYLAND_DISPLAY`, `_WAYLAND_DISPLAY`, `WAYLAND_SOCKET`: if set probe Wayland - backend. -* `XCURSOR_PATH`: directory where xcursors are located. - -For a complete list of wlroots environment variables, see -https://github.com/swaywm/wlroots/blob/master/docs/env_vars.md. From 15eeb7784e8f9b2940c04135b9f128444832fc0f Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Jan 2020 17:49:26 +0100 Subject: [PATCH 044/233] cage: add -v argument to print version --- cage.c | 10 +++++++--- config.h.in | 2 ++ meson.build | 20 ++++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/cage.c b/cage.c index 9526e82..54945db 100644 --- a/cage.c +++ b/cage.c @@ -115,6 +115,7 @@ usage(FILE *file, const char *cage) " -D\t Turn on damage tracking debugging\n" #endif " -h\t Display this help message\n" + " -v\t Show the version number and exit\n" "\n" " Use -- when you want to pass arguments to APPLICATION\n", cage); @@ -125,9 +126,9 @@ parse_args(struct cg_server *server, int argc, char *argv[]) { int c; #ifdef DEBUG - while ((c = getopt(argc, argv, "drDh")) != -1) { + while ((c = getopt(argc, argv, "drDhv")) != -1) { #else - while ((c = getopt(argc, argv, "drh")) != -1) { + while ((c = getopt(argc, argv, "drhv")) != -1) { #endif switch (c) { case 'd': @@ -147,6 +148,9 @@ parse_args(struct cg_server *server, int argc, char *argv[]) case 'h': usage(stdout, argv[0]); return false; + case 'v': + fprintf(stdout, "Cage version " CAGE_VERSION "\n"); + exit(0); default: usage(stderr, argv[0]); return false; @@ -390,7 +394,7 @@ main(int argc, char *argv[]) wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.", "Clients may not be able to connect"); } else { - wlr_log(WLR_DEBUG, "Cage is running on Wayland display %s", socket); + wlr_log(WLR_DEBUG, "Cage " CAGE_VERSION " is running on Wayland display %s", socket); } #if CAGE_HAS_XWAYLAND diff --git a/config.h.in b/config.h.in index 3305da9..51137ec 100644 --- a/config.h.in +++ b/config.h.in @@ -3,4 +3,6 @@ #mesondefine CAGE_HAS_XWAYLAND +#mesondefine CAGE_VERSION + #endif diff --git a/meson.build b/meson.build index 6121eee..e7053d1 100644 --- a/meson.build +++ b/meson.build @@ -76,8 +76,24 @@ else have_xwayland = false endif +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']) + if git_commit.returncode() == 0 and git_branch.returncode() == 0 + version = '@0@-@1@ (branch \'@2@\')'.format( + meson.project_version(), + git_commit.stdout().strip(), + git_branch.stdout().strip(), + ) + endif +else + version = '@0@'.format(meson.project_version()) +endif + conf_data = configuration_data() conf_data.set10('CAGE_HAS_XWAYLAND', have_xwayland) +conf_data.set_quoted('CAGE_VERSION', version) cage_sources = [ 'cage.c', @@ -125,9 +141,9 @@ executable( summary = [ '', - 'Cage @0@'.format(meson.project_version()), + 'Cage @0@'.format(version), '', - ' xwayland: @0@'.format(conf_data.get('CAGE_HAS_XWAYLAND', false)), + ' xwayland: @0@'.format(have_xwayland), '' ] message('\n'.join(summary)) From 33cd4c2af9a25b4079107fa2c4b10e4749776526 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 31 Jan 2020 22:55:16 +0100 Subject: [PATCH 045/233] meson: don't build with -Werror by default Fixes #70. For development, initialise meson with the `--werror` option: ``` meson build --werror ``` Alternatively, for an existing build, run ``` cd build meson configure -Dwerror=true ``` --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index e7053d1..84eac11 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,6 @@ project('cage', 'c', default_options: [ 'c_std=c11', 'warning_level=3', - 'werror=true', ], ) From 66313efb0171e6585f032c99d2bd39668b5f309b Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 31 Jan 2020 22:58:15 +0100 Subject: [PATCH 046/233] CI: build with --werror --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 4 ++-- .builds/freebsd.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 280d3e9..9737be6 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -23,5 +23,5 @@ tasks: sudo ninja -C build install - build: | cd cage - meson build -Dxwayland=true + meson build --werror -Dxwayland=true ninja -C build diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index dfb60c7..a8d1d8e 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -21,9 +21,9 @@ tasks: sudo ninja -C build install - build: | cd cage - meson build -Dxwayland=true + meson build --werror -Dxwayland=true ninja -C build - scan-build: | cd cage - CC=clang meson build -Dxwayland=true + CC=clang meson build --werror -Dxwayland=true CC=clang ninja -C build scan-build diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index ae5b93d..0c62d4c 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -24,5 +24,5 @@ tasks: sudo ninja -C build install - build: | cd cage - PKG_CONFIG_PATH=/usr/local/lib/pkgconfig meson build -Dxwayland=true + PKG_CONFIG_PATH=/usr/local/lib/pkgconfig meson build --werror -Dxwayland=true PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ninja -C build From e664fdce79e19f61336eb0bd443ea1462c376081 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 1 Feb 2020 16:17:58 +0100 Subject: [PATCH 047/233] README: update build instructions --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8c702ec..6f8a7de 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ application. This README is only relevant for development resources and instructions. For a description of Cage and installation instructions for end-users, please see -[the Wiki](https://github.com/Hjdskes/cage/wiki/) and [its project -page](https://www.hjdskes.nl/projects/cage). +[its project page](https://www.hjdskes.nl/projects/cage) and [the +Wiki](https://github.com/Hjdskes/cage/wiki/). ## Release signatures @@ -30,20 +30,21 @@ $ meson build $ ninja -C build ``` +By default, this builds a debug build. To build a release build, use `meson +build --buildtype=release`. + Cage comes with compile-time support for XWayland. To enable this, first make sure that your version of wlroots is compiled with this option. Then, add `-Dxwayland=true` to the `meson` command above. Note that you'll need to have the XWayland binary installed on your system for this to work. -You can run Cage by running `./build/cage APPLICATION`. If you run it -from within an existing X11 or Wayland session, it will open in a -virtual output as a window in your existing session. If you run it at -a TTY, it'll run with the KMS+DRM backend. In debug mode (default -build type with Meson), press Alt+Esc to quit. To build a release -build, use `meson build --buildtype=release`. - -For more information, see the [Wiki](https://github.com/Hjdskes/cage/wiki). +You can run Cage by running `./build/cage APPLICATION`. If you run it from +within an existing X11 or Wayland session, it will open in a virtual output as +a window in your existing session. If you run it at a TTY, it'll run with the +KMS+DRM backend. In debug mode (default build type with Meson), press +Alt+Esc to quit. For more configuration options, see +[Configuration](https://github.com/Hjdskes/cage/wiki/Configuration). Cage is based on the annotated source of tinywl and rootston. From b04e02cd6035d24655775a0db78d43beef47ed19 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 1 Feb 2020 22:11:25 +0100 Subject: [PATCH 048/233] output: add support for direct scan-out Fixes #88. --- output.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/output.c b/output.c index 5b79e76..a32807e 100644 --- a/output.c +++ b/output.c @@ -36,6 +36,7 @@ #include "server.h" #include "util.h" #include "view.h" +#include "xwayland.h" static void output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data); @@ -178,6 +179,64 @@ 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; + } + + if (!wlr_output_attach_buffer(wlr_output, surface->buffer)) { + return false; + } + + return wlr_output_commit(wlr_output); +} + static void damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data) { @@ -220,11 +279,28 @@ 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); @@ -243,7 +319,7 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) damage_finish: pixman_region32_fini(&damage); - struct send_frame_done_data frame_data = {0}; + frame_done: clock_gettime(CLOCK_MONOTONIC, &frame_data.when); send_frame_done(output, &frame_data); } From e3be8159b3d3b1580e4025bbc751a24bede4443b Mon Sep 17 00:00:00 2001 From: Damon Date: Mon, 3 Feb 2020 20:14:29 +0000 Subject: [PATCH 049/233] output: wrap xwayland.h include in CAGE_HAS_XWAYLAND (#120) * move xwayland.h include to ifdef block for X11 * use correct ifdef CAGE_HAS_XWAYLAND --- output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/output.c b/output.c index a32807e..488b02e 100644 --- a/output.c +++ b/output.c @@ -36,7 +36,9 @@ #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); From 8a6d16391fa1dd6600ea13b7edf9e8f1bb444ced Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 3 Feb 2020 21:23:39 +0100 Subject: [PATCH 050/233] output: include seat.h --- output.c | 1 + output.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/output.c b/output.c index 488b02e..15773e2 100644 --- a/output.c +++ b/output.c @@ -33,6 +33,7 @@ #include "output.h" #include "render.h" +#include "seat.h" #include "server.h" #include "util.h" #include "view.h" diff --git a/output.h b/output.h index 081c9fd..9e6a0dd 100644 --- a/output.h +++ b/output.h @@ -5,7 +5,6 @@ #include #include -#include "seat.h" #include "server.h" #include "view.h" From 8069893b0d13d817602850afeae14f8227ed0626 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Jan 2020 01:08:59 +0100 Subject: [PATCH 051/233] render: use output backend to get renderer This prevents a segfault when shutting down during startup, when a client is passed that doesn't spawn a window. It also brings us one step closer to not having to have a pointer to the backend in cg_server. --- render.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/render.c b/render.c index c222b8f..2fd309a 100644 --- a/render.c +++ b/render.c @@ -149,7 +149,12 @@ 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(server->backend); + 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)) { From acf5925a86e02c4073611b8f450807e15cc99125 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Jan 2020 11:53:10 +0100 Subject: [PATCH 052/233] cage: return 0 always in the signal handler According to the Wayland docs: If the event source is registered for re-check with wl_event_source_check(): 0 for all done, 1 for needing a re-check. If not registered, the return value is ignored and should be zero. See e.g. http://manpages.ubuntu.com/manpages/cosmic/man3/wl_event_source.3.html Since we don't register any of these for re-checking, we should return 0. --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 54945db..1396e14 100644 --- a/cage.c +++ b/cage.c @@ -100,7 +100,7 @@ handle_signal(int signal, void *data) wl_display_terminate(display); return 0; default: - return 1; + return 0; } } From f33fe5d6f2c2267bae49a48e669f044f638892be Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Jan 2020 11:56:59 +0100 Subject: [PATCH 053/233] cage: change copyright to include 2020 --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 1396e14..a05afcf 100644 --- a/cage.c +++ b/cage.c @@ -1,7 +1,7 @@ /* * Cage: A Wayland kiosk. * - * Copyright (C) 2018-2019 Jente Hidskes + * Copyright (C) 2018-2020 Jente Hidskes * * See the LICENSE file accompanying this file. */ From bb5d4cf52e10f90d3be0f89c3512cb290e97890c Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Wed, 27 Feb 2019 18:27:25 +0100 Subject: [PATCH 054/233] cage: handle SIGCHLD of primary client Fixes #13, #53. --- cage.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cage.c b/cage.c index a05afcf..eba139a 100644 --- a/cage.c +++ b/cage.c @@ -97,6 +97,8 @@ handle_signal(int signal, void *data) case SIGINT: /* Fallthrough */ case SIGTERM: + /* Fallthrough */ + case SIGCHLD: wl_display_terminate(display); return 0; default: @@ -172,6 +174,7 @@ main(int argc, char *argv[]) struct wl_event_loop *event_loop = NULL; 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; @@ -213,6 +216,7 @@ main(int argc, char *argv[]) event_loop = wl_display_get_event_loop(server.wl_display); sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); + sigchld_source = wl_event_loop_add_signal(event_loop, SIGCHLD, handle_signal, &server.wl_display); server.backend = wlr_backend_autocreate(server.wl_display, NULL); if (!server.backend) { @@ -424,6 +428,7 @@ main(int argc, char *argv[]) end: wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); + wl_event_source_remove(sigchld_source); seat_destroy(server.seat); wlr_output_layout_destroy(server.output_layout); /* This function is not null-safe, but we only ever get here From b570cdb22ca0abca4ff111845ac0f4da885d620f Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Jan 2020 15:00:34 +0100 Subject: [PATCH 055/233] cage: report on exit status of primary client --- cage.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cage.c b/cage.c index eba139a..7b71285 100644 --- a/cage.c +++ b/cage.c @@ -69,6 +69,20 @@ spawn_primary_client(char *argv[], pid_t *pid_out) return true; } +static void +cleanup_primary_client(pid_t pid) +{ + int status; + + waitpid(pid, &status, 0); + + if (WIFEXITED(status)) { + wlr_log(WLR_DEBUG, "Child exited normally with exit status %d", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + wlr_log(WLR_DEBUG, "Child was terminated by a signal (%d)", WTERMSIG(status)); + } +} + static bool drop_permissions(void) { @@ -423,7 +437,7 @@ main(int argc, char *argv[]) #endif wl_display_destroy_clients(server.wl_display); - waitpid(pid, NULL, 0); + cleanup_primary_client(pid); end: wl_event_source_remove(sigint_source); From 6be4306b4d085dfcb111ab88b24bfe56db206751 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 28 Jan 2020 21:19:50 +0100 Subject: [PATCH 056/233] cage: destroy output_layout after wl_display wl_display will destroy the outputs, whose destroy handler will remove them from the output layout. But by that point, the output layout has already been destroyed. --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 7b71285..ecc19dd 100644 --- a/cage.c +++ b/cage.c @@ -444,9 +444,9 @@ end: wl_event_source_remove(sigterm_source); wl_event_source_remove(sigchld_source); seat_destroy(server.seat); - wlr_output_layout_destroy(server.output_layout); /* This function is not null-safe, but we only ever get here with a proper wl_display. */ wl_display_destroy(server.wl_display); + wlr_output_layout_destroy(server.output_layout); return ret; } From 009cca3fa9ce642edd311f99869e64d2bedceca4 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Tue, 28 Jan 2020 21:32:45 +0100 Subject: [PATCH 057/233] cage: switch SIGCHLD handling for pipe As explained in [1] and [2], SIGCHLD is a tricky signal to handle. A pipe can be used to signal completion instead. [1]: https://github.com/swaywm/wlroots/issues/2012#issuecomment-578908333 [2]: https://stackoverflow.com/questions/8976004/using-waitpid-or-sigaction/8976461#8976461 --- cage.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/cage.c b/cage.c index ecc19dd..b6d537f 100644 --- a/cage.c +++ b/cage.c @@ -49,14 +49,40 @@ #include "xwayland.h" #endif -static bool -spawn_primary_client(char *argv[], pid_t *pid_out) +static int +sigchld_handler(int fd, uint32_t mask, void *data) { + struct wl_display *display = data; + + /* Close Cage's read pipe. */ + close(fd); + + if (mask & WL_EVENT_HANGUP) { + wlr_log(WLR_DEBUG, "Child process closed normally"); + } else if (mask & WL_EVENT_ERROR) { + wlr_log(WLR_DEBUG, "Connection closed by server"); + } + + wl_display_terminate(display); + return 0; +} + +static bool +spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, struct wl_event_source **sigchld_source) +{ + int fd[2]; + if (pipe(fd) != 0) { + wlr_log(WLR_ERROR, "Unable to create pipe"); + return false; + } + pid_t pid = fork(); if (pid == 0) { sigset_t set; sigemptyset(&set); sigprocmask(SIG_SETMASK, &set, NULL); + /* Close read, we only need write in the primary client process. */ + close(fd[0]); execvp(argv[0], argv); _exit(1); } else if (pid == -1) { @@ -64,6 +90,13 @@ spawn_primary_client(char *argv[], pid_t *pid_out) return false; } + /* Close write, we only need read in Cage. */ + close(fd[1]); + + struct wl_event_loop *event_loop = wl_display_get_event_loop(display); + uint32_t mask = WL_EVENT_HANGUP | WL_EVENT_ERROR; + *sigchld_source = wl_event_loop_add_fd(event_loop, fd[0], mask, sigchld_handler, display); + *pid_out = pid; wlr_log(WLR_DEBUG, "Child process created with pid %d", pid); return true; @@ -111,8 +144,6 @@ handle_signal(int signal, void *data) case SIGINT: /* Fallthrough */ case SIGTERM: - /* Fallthrough */ - case SIGCHLD: wl_display_terminate(display); return 0; default: @@ -230,7 +261,6 @@ main(int argc, char *argv[]) event_loop = wl_display_get_event_loop(server.wl_display); sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); - sigchld_source = wl_event_loop_add_signal(event_loop, SIGCHLD, handle_signal, &server.wl_display); server.backend = wlr_backend_autocreate(server.wl_display, NULL); if (!server.backend) { @@ -420,7 +450,7 @@ main(int argc, char *argv[]) #endif pid_t pid; - if (!spawn_primary_client(argv + optind, &pid)) { + if (!spawn_primary_client(server.wl_display, argv + optind, &pid, &sigchld_source)) { ret = 1; goto end; } From 24cc576377a33bd9ee06b206239dbee4272cc34e Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 6 Feb 2020 23:07:03 +0100 Subject: [PATCH 058/233] cage: set CLOEXEC on the file descriptors As mentioned by @emersion: By default, pipe creates FDs without the CLOEXEC flag set, which means they will be leaked to any other child process spawned. Would be nice to set the CLOEXEC flag to prevent the leak. --- cage.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cage.c b/cage.c index b6d537f..a9ced27 100644 --- a/cage.c +++ b/cage.c @@ -10,6 +10,7 @@ #include "config.h" +#include #include #include #include @@ -67,6 +68,25 @@ sigchld_handler(int fd, uint32_t mask, void *data) return 0; } +static bool +set_cloexec(int fd) +{ + int flags = fcntl(fd, F_GETFD); + + if (flags == -1) { + wlr_log(WLR_ERROR, "Unable to set the CLOEXEC flag: fnctl failed"); + return false; + } + + flags = flags | FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) { + wlr_log(WLR_ERROR, "Unable to set the CLOEXEC flag: fnctl failed"); + return false; + } + + return true; +} + static bool spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, struct wl_event_source **sigchld_source) { @@ -90,6 +110,10 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s return false; } + if (!set_cloexec(fd[0]) || !set_cloexec(fd[1])) { + return false; + } + /* Close write, we only need read in Cage. */ close(fd[1]); From dc002acd207f256bf462e8002c3447c67e87b99a Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 7 Feb 2020 18:55:07 +0100 Subject: [PATCH 059/233] cage: cleanup_primary_client when jumping to 'end' With the new CLOEXEC setting, spawning the primary client can fail *after* forking. In this case, the client process has been forked and will need to be cleaned up. In case something fails before pid has been set, it's set to 0. From waitpid(2): The value of pid can be: 0 meaning wait for any child process whose process group ID is equal to that of the calling process at the time of the call to waitpid(). That will be none in this case, and hence this won't block and is thus safe. --- cage.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cage.c b/cage.c index a9ced27..1832059 100644 --- a/cage.c +++ b/cage.c @@ -110,6 +110,9 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s return false; } + /* Set this early so that if we fail, the client process will be cleaned up properly. */ + *pid_out = pid; + if (!set_cloexec(fd[0]) || !set_cloexec(fd[1])) { return false; } @@ -121,7 +124,6 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s uint32_t mask = WL_EVENT_HANGUP | WL_EVENT_ERROR; *sigchld_source = wl_event_loop_add_fd(event_loop, fd[0], mask, sigchld_handler, display); - *pid_out = pid; wlr_log(WLR_DEBUG, "Child process created with pid %d", pid); return true; } @@ -258,6 +260,7 @@ main(int argc, char *argv[]) struct wlr_xwayland *xwayland = NULL; struct wlr_xcursor_manager *xcursor_manager = NULL; #endif + pid_t pid = 0; int ret = 0; if (!parse_args(&server, argc, argv)) { @@ -473,7 +476,6 @@ main(int argc, char *argv[]) wlr_xwayland_set_seat(xwayland, server.seat->seat); #endif - pid_t pid; if (!spawn_primary_client(server.wl_display, argv + optind, &pid, &sigchld_source)) { ret = 1; goto end; @@ -491,9 +493,9 @@ main(int argc, char *argv[]) #endif wl_display_destroy_clients(server.wl_display); +end: cleanup_primary_client(pid); -end: wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); wl_event_source_remove(sigchld_source); From 42782bda1df5f4ef855a74531bec3cfc4169388d Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 8 Feb 2020 16:49:12 +0100 Subject: [PATCH 060/233] server: remove backend pointer --- cage.c | 13 +++++++------ seat.c | 4 ++-- seat.h | 2 +- server.h | 2 -- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/cage.c b/cage.c index 1832059..691024e 100644 --- a/cage.c +++ b/cage.c @@ -246,6 +246,7 @@ 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_backend *backend = NULL; struct wlr_renderer *renderer = NULL; struct wlr_compositor *compositor = NULL; struct wlr_data_device_manager *data_device_manager = NULL; @@ -289,8 +290,8 @@ main(int argc, char *argv[]) sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); - server.backend = wlr_backend_autocreate(server.wl_display, NULL); - if (!server.backend) { + backend = wlr_backend_autocreate(server.wl_display, NULL); + if (!backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); ret = 1; goto end; @@ -301,7 +302,7 @@ main(int argc, char *argv[]) goto end; } - renderer = wlr_backend_get_renderer(server.backend); + renderer = wlr_backend_get_renderer(backend); wlr_renderer_init_wl_display(renderer, server.wl_display); wl_list_init(&server.views); @@ -332,9 +333,9 @@ main(int argc, char *argv[]) * available on the backend. We use this only to detect the * first output and ignore subsequent outputs. */ server.new_output.notify = handle_new_output; - wl_signal_add(&server.backend->events.new_output, &server.new_output); + wl_signal_add(&backend->events.new_output, &server.new_output); - server.seat = seat_create(&server); + server.seat = seat_create(&server, backend); if (!server.seat) { wlr_log(WLR_ERROR, "Unable to create the seat"); ret = 1; @@ -459,7 +460,7 @@ main(int argc, char *argv[]) goto end; } - if (!wlr_backend_start(server.backend)) { + if (!wlr_backend_start(backend)) { wlr_log(WLR_ERROR, "Unable to start the wlroots backend"); ret = 1; goto end; diff --git a/seat.c b/seat.c index 3f400db..f08cfae 100644 --- a/seat.c +++ b/seat.c @@ -720,7 +720,7 @@ handle_destroy(struct wl_listener *listener, void *data) } struct cg_seat * -seat_create(struct cg_server *server) +seat_create(struct cg_server *server, struct wlr_backend *backend) { struct cg_seat *seat = calloc(1, sizeof(struct cg_seat)); if (!seat) { @@ -788,7 +788,7 @@ seat_create(struct cg_server *server) wl_list_init(&seat->touch); seat->new_input.notify = handle_new_input; - wl_signal_add(&server->backend->events.new_input, &seat->new_input); + wl_signal_add(&backend->events.new_input, &seat->new_input); wl_list_init(&seat->drag_icons); seat->request_start_drag.notify = handle_request_start_drag; diff --git a/seat.h b/seat.h index f4a4af2..de3ddc8 100644 --- a/seat.h +++ b/seat.h @@ -85,7 +85,7 @@ struct cg_drag_icon { struct wl_listener destroy; }; -struct cg_seat *seat_create(struct cg_server *server); +struct cg_seat *seat_create(struct cg_server *server, struct wlr_backend *backend); void seat_destroy(struct cg_seat *seat); struct cg_view *seat_get_focus(struct cg_seat *seat); void seat_set_focus(struct cg_seat *seat, struct cg_view *view); diff --git a/server.h b/server.h index d05dabf..5caa0c1 100644 --- a/server.h +++ b/server.h @@ -4,7 +4,6 @@ #include "config.h" #include -#include #include #include #include @@ -19,7 +18,6 @@ struct cg_server { struct wl_display *wl_display; - struct wlr_backend *backend; struct wl_list views; struct cg_seat *seat; From 6fa273465182240673e1ca9f429f35141e2f5ab9 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Feb 2020 19:34:54 +0100 Subject: [PATCH 061/233] meson: fix snapshot builds Previously, is git was found but the build was run from a snapshot, `version` wouldn't be set. This commit fixes this by first setting version to the project version and only then, conditionally, setting it to the git version. Fixes #125. --- meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 84eac11..ce93de0 100644 --- a/meson.build +++ b/meson.build @@ -75,6 +75,7 @@ else have_xwayland = false 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']) @@ -86,8 +87,6 @@ if git.found() git_branch.stdout().strip(), ) endif -else - version = '@0@'.format(meson.project_version()) endif conf_data = configuration_data() From bd48cad49265c4abe3b45d34d901808291712396 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Feb 2020 22:10:21 +0100 Subject: [PATCH 062/233] Add clang-format file This adds a first iteration of a clang-format style definition. It formats the current code such that it aligns (mostly..) with the style I prefer, but it is most likely incomplete and there will be corner cases. Fixes #124. --- .clang-format | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..49b64c2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,13 @@ +AlignAfterOpenBracket: Align +AlignTrailingComments: false +AlwaysBreakAfterReturnType: TopLevelDefinitions +BreakBeforeBraces: Linux +ColumnLimit: 120 +ContinuationIndentWidth: 8 +ForEachMacros: [wl_list_for_each, wl_list_for_each_safe, wl_list_for_each_reverse] +IndentWidth: 8 +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: true +TabWidth: 8 +UseTab: Always From 6cbc2026626948e016d9f1a14f0316208019fe3e Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Feb 2020 19:49:47 +0100 Subject: [PATCH 063/233] Apply clang-format --- cage.c | 28 +++++------- idle_inhibit_v1.c | 2 +- output.c | 38 +++++++--------- output.h | 12 ++--- render.c | 21 ++++----- seat.c | 112 +++++++++++++++++----------------------------- view.c | 6 +-- view.h | 15 +++---- xdg_shell.c | 5 ++- xwayland.c | 5 ++- 10 files changed, 99 insertions(+), 145 deletions(-) diff --git a/cage.c b/cage.c index 691024e..74fa6a7 100644 --- a/cage.c +++ b/cage.c @@ -33,8 +33,8 @@ #include #endif #include -#include #include +#include #include #if CAGE_HAS_XWAYLAND #include @@ -153,8 +153,8 @@ drop_permissions(void) } if (setuid(0) != -1) { - wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to " - "restore it after setuid), refusing to start"); + wlr_log(WLR_ERROR, + "Unable to drop root (we shouldn't be able to restore it after setuid), refusing to start"); return false; } @@ -180,7 +180,8 @@ handle_signal(int signal, void *data) static void usage(FILE *file, const char *cage) { - fprintf(file, "Usage: %s [OPTIONS] [--] APPLICATION\n" + fprintf(file, + "Usage: %s [OPTIONS] [--] APPLICATION\n" "\n" " -d\t Don't draw client side decorations, when possible\n" " -r\t Rotate the output 90 degrees clockwise, specify up to three times\n" @@ -383,10 +384,9 @@ main(int argc, char *argv[]) ret = 1; goto end; } - wlr_server_decoration_manager_set_default_mode(server_decoration_manager, - server.xdg_decoration ? - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER : - WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); + wlr_server_decoration_manager_set_default_mode( + server_decoration_manager, server.xdg_decoration ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER + : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); export_dmabuf_manager = wlr_export_dmabuf_manager_v1_create(server.wl_display); if (!export_dmabuf_manager) { @@ -434,8 +434,7 @@ main(int argc, char *argv[]) } if (setenv("DISPLAY", xwayland->display_name, true) < 0) { - wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland.", - "Clients may not be able to connect"); + wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland. Clients may not be able to connect"); } else { wlr_log(WLR_DEBUG, "XWayland is running on display %s", xwayland->display_name); } @@ -443,12 +442,10 @@ main(int argc, char *argv[]) if (wlr_xcursor_manager_load(xcursor_manager, 1)) { wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); } - struct wlr_xcursor *xcursor = - wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); if (xcursor) { struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor(xwayland, image->buffer, - image->width * 4, image->width, image->height, + wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, image->width, image->height, image->hotspot_x, image->hotspot_y); } #endif @@ -467,8 +464,7 @@ main(int argc, char *argv[]) } if (setenv("WAYLAND_DISPLAY", socket, true) < 0) { - wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.", - "Clients may not be able to connect"); + wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY. Clients may not be able to connect"); } else { wlr_log(WLR_DEBUG, "Cage " CAGE_VERSION " is running on Wayland display %s", socket); } diff --git a/idle_inhibit_v1.c b/idle_inhibit_v1.c index 1d0e167..5aba865 100644 --- a/idle_inhibit_v1.c +++ b/idle_inhibit_v1.c @@ -1,6 +1,6 @@ /* * Cage: A Wayland kiosk. - * + * * Copyright (C) 2018-2019 Jente Hidskes * * See the LICENSE file accompanying this file. diff --git a/output.c b/output.c index 15773e2..1ce90b3 100644 --- a/output.c +++ b/output.c @@ -10,13 +10,13 @@ #define _POSIX_C_SOURCE 200112L #include "config.h" -#include #include #include #include #include #include +#include #if WLR_HAS_X11_BACKEND #include #endif @@ -91,9 +91,8 @@ output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, vo } 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) +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, @@ -107,8 +106,8 @@ output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *su } static void -output_view_for_each_surface(struct cg_output *output, struct cg_view *view, - cg_surface_iterator_func_t iterator, void *user_data) +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, @@ -123,8 +122,8 @@ output_view_for_each_surface(struct cg_output *output, struct cg_view *view, } void -output_view_for_each_popup(struct cg_output *output, struct cg_view *view, - cg_surface_iterator_func_t iterator, void *user_data) +output_view_for_each_popup(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, @@ -148,8 +147,8 @@ output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *dra 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); + output_surface_for_each_surface(output, drag_icon->wlr_drag_icon->surface, ox, oy, iterator, + user_data); } } } @@ -183,8 +182,7 @@ send_frame_done(struct cg_output *output, struct send_frame_done_data *data) } static void -count_surface_iterator(struct cg_output *output, struct wlr_surface *surface, - struct wlr_box *_box, void *data) +count_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *_box, void *data) { size_t *n = data; n++; @@ -229,7 +227,8 @@ scan_out_primary_view(struct cg_output *output) return false; } - if ((float) surface->current.scale != wlr_output->scale || surface->current.transform != wlr_output->transform) { + if ((float) surface->current.scale != wlr_output->scale || + surface->current.transform != wlr_output->transform) { return false; } @@ -260,8 +259,7 @@ damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, s /* 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); + 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); @@ -270,8 +268,7 @@ damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, s } void -output_damage_surface(struct cg_output *output, struct wlr_surface *surface, - double lx, double ly, bool whole) +output_damage_surface(struct cg_output *output, struct wlr_surface *surface, double lx, double ly, bool whole) { double ox = lx, oy = ly; wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy); @@ -319,10 +316,10 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) output_render(output, &damage); - damage_finish: +damage_finish: pixman_region32_fini(&damage); - frame_done: +frame_done: clock_gettime(CLOCK_MONOTONIC, &frame_data.when); send_frame_done(output, &frame_data); } @@ -439,8 +436,7 @@ handle_new_output(struct wl_listener *listener, void *data) } if (wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { - wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", - wlr_output->name, + wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, wlr_output->scale); } diff --git a/output.h b/output.h index 9e6a0dd..687b45c 100644 --- a/output.h +++ b/output.h @@ -22,14 +22,16 @@ struct cg_output { 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); +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 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(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, void *user_data); -void output_view_for_each_popup(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_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); diff --git a/render.c b/render.c index 2fd309a..c4b375e 100644 --- a/render.c +++ b/render.c @@ -49,9 +49,8 @@ struct render_data { }; 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]) +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); @@ -70,13 +69,12 @@ render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage, wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); } - damage_finish: +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) +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; @@ -118,20 +116,17 @@ render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_reg 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); + output_surface_for_each_surface(output, view->wlr_surface, ox, oy, render_surface_iterator, &data); } static void -render_popup_iterator(struct cg_output *output, struct wlr_surface *surface, - struct wlr_box *box, void *data) +render_popup_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *data) { /* Render this popup's surface. */ render_surface_iterator(output, surface, box, data); /* Render this popup's child toplevels. */ - output_surface_for_each_surface(output, surface, box->x, box->y, - render_surface_iterator, data); + output_surface_for_each_surface(output, surface, box->x, box->y, render_surface_iterator, data); } static void @@ -189,7 +184,7 @@ output_render(struct cg_output *output, pixman_region32_t *damage) render_drag_icons(output, damage, &server->seat->drag_icons); - renderer_end: +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); diff --git a/seat.c b/seat.c index f08cfae..9fc8f0b 100644 --- a/seat.c +++ b/seat.c @@ -8,8 +8,8 @@ #include "config.h" -#include #include +#include #include #include #include @@ -40,8 +40,7 @@ static void drag_icon_update_position(struct cg_drag_icon *drag_icon); * 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) +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; @@ -64,8 +63,7 @@ view_at(struct cg_view *view, double lx, double ly, * 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) +desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { struct cg_view *view; @@ -79,17 +77,15 @@ desktop_view_at(struct cg_server *server, double lx, double ly, } static void -press_cursor_button(struct cg_seat *seat, struct wlr_input_device *device, - uint32_t time, uint32_t button, uint32_t state, - double lx, double ly) +press_cursor_button(struct cg_seat *seat, struct wlr_input_device *device, uint32_t time, uint32_t button, + uint32_t state, double lx, double ly) { struct cg_server *server = seat->server; if (state == WLR_BUTTON_PRESSED) { double sx, sy; struct wlr_surface *surface; - struct cg_view *view = desktop_view_at(server, lx, ly, - &surface, &sx, &sy); + struct cg_view *view = desktop_view_at(server, lx, ly, &surface, &sx, &sy); struct cg_view *current = seat_get_focus(seat); if (view == current) { return; @@ -104,7 +100,8 @@ press_cursor_button(struct cg_seat *seat, struct wlr_input_device *device, } static void -update_capabilities(struct cg_seat *seat) { +update_capabilities(struct cg_seat *seat) +{ uint32_t caps = 0; if (!wl_list_empty(&seat->keyboards)) { @@ -122,14 +119,13 @@ update_capabilities(struct cg_seat *seat) { if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) { wlr_cursor_set_image(seat->cursor, NULL, 0, 0, 0, 0, 0, 0); } else { - wlr_xcursor_manager_set_cursor_image(seat->xcursor_manager, - DEFAULT_XCURSOR, - seat->cursor); + wlr_xcursor_manager_set_cursor_image(seat->xcursor_manager, DEFAULT_XCURSOR, seat->cursor); } } static void -handle_touch_destroy(struct wl_listener *listener, void *data) { +handle_touch_destroy(struct wl_listener *listener, void *data) +{ struct cg_touch *touch = wl_container_of(listener, touch, destroy); struct cg_seat *seat = touch->seat; @@ -217,8 +213,7 @@ handle_keyboard_modifiers(struct wl_listener *listener, void *data) struct cg_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); - wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat, - &keyboard->device->keyboard->modifiers); + wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat, &keyboard->device->keyboard->modifiers); wlr_idle_notify_activity(keyboard->seat->server->idle, keyboard->seat->seat); } @@ -266,8 +261,7 @@ handle_keyboard_key(struct wl_listener *listener, void *data) if (!handled) { /* Otherwise, we pass it along to the client. */ wlr_seat_set_keyboard(seat->seat, keyboard->device); - wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, - event->keycode, event->state); + wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); } wlr_idle_notify_activity(seat->server->idle, seat->seat); @@ -304,14 +298,13 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) return; } - struct xkb_rule_names rules = { 0 }; + 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_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!keymap) { wlr_log(WLR_ERROR, "Unable to configure keyboard: keymap does not exist"); free(keyboard); @@ -399,8 +392,7 @@ handle_request_set_cursor(struct wl_listener *listener, void *data) /* This can be sent by any client, so we check to make sure * this one actually has pointer focus first. */ if (focused_client == event->seat_client->client) { - wlr_cursor_set_surface(seat->cursor, event->surface, - event->hotspot_x, event->hotspot_y); + wlr_cursor_set_surface(seat->cursor, event->surface, event->hotspot_x, event->hotspot_y); } } @@ -411,27 +403,22 @@ handle_touch_down(struct wl_listener *listener, void *data) struct wlr_event_touch_down *event = data; double lx, ly; - wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, - event->x, event->y, &lx, &ly); + wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); double sx, sy; struct wlr_surface *surface; - struct cg_view *view = desktop_view_at(seat->server, lx, ly, - &surface, &sx, &sy); + struct cg_view *view = desktop_view_at(seat->server, lx, ly, &surface, &sx, &sy); uint32_t serial = 0; if (view) { - serial = wlr_seat_touch_notify_down(seat->seat, surface, - event->time_msec, event->touch_id, - sx, sy); + serial = wlr_seat_touch_notify_down(seat->seat, surface, event->time_msec, event->touch_id, sx, sy); } if (serial && wlr_seat_touch_num_points(seat->seat) == 1) { seat->touch_id = event->touch_id; seat->touch_lx = lx; seat->touch_ly = ly; - press_cursor_button(seat, event->device, event->time_msec, - BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); + press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); } wlr_idle_notify_activity(seat->server->idle, seat->seat); @@ -448,8 +435,7 @@ handle_touch_up(struct wl_listener *listener, void *data) } if (wlr_seat_touch_num_points(seat->seat) == 1) { - press_cursor_button(seat, event->device, event->time_msec, - BTN_LEFT, WLR_BUTTON_RELEASED, + press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED, seat->touch_lx, seat->touch_ly); } @@ -468,22 +454,17 @@ handle_touch_motion(struct wl_listener *listener, void *data) } double lx, ly; - wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, - event->x, event->y, &lx, &ly); + wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); double sx, sy; struct wlr_surface *surface; - struct cg_view *view = desktop_view_at(seat->server, lx, ly, - &surface, &sx, &sy); + struct cg_view *view = desktop_view_at(seat->server, lx, ly, &surface, &sx, &sy); if (view) { - wlr_seat_touch_point_focus(seat->seat, surface, - event->time_msec, event->touch_id, sx, sy); - wlr_seat_touch_notify_motion(seat->seat, event->time_msec, - event->touch_id, sx, sy); + wlr_seat_touch_point_focus(seat->seat, surface, event->time_msec, event->touch_id, sx, sy); + wlr_seat_touch_notify_motion(seat->seat, event->time_msec, event->touch_id, sx, sy); } else { - wlr_seat_touch_point_clear_focus(seat->seat, event->time_msec, - event->touch_id); + wlr_seat_touch_point_clear_focus(seat->seat, event->time_msec, event->touch_id); } if (event->touch_id == seat->touch_id) { @@ -509,8 +490,7 @@ handle_cursor_axis(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, cursor_axis); struct wlr_event_pointer_axis *event = data; - wlr_seat_pointer_notify_axis(seat->seat, - event->time_msec, event->orientation, event->delta, + wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, event->source); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -521,11 +501,9 @@ handle_cursor_button(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, cursor_button); struct wlr_event_pointer_button *event = data; - wlr_seat_pointer_notify_button(seat->seat, event->time_msec, - event->button, event->state); - press_cursor_button(seat, event->device, event->time_msec, - event->button, event->state, - seat->cursor->x, seat->cursor->y); + wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state); + press_cursor_button(seat, event->device, event->time_msec, event->button, event->state, seat->cursor->x, + seat->cursor->y); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -536,9 +514,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) struct wlr_seat *wlr_seat = seat->seat; struct wlr_surface *surface = NULL; - struct cg_view *view = desktop_view_at(seat->server, - seat->cursor->x, seat->cursor->y, - &surface, &sx, &sy); + struct cg_view *view = desktop_view_at(seat->server, seat->cursor->x, seat->cursor->y, &surface, &sx, &sy); if (!view) { wlr_seat_pointer_clear_focus(wlr_seat); @@ -586,8 +562,7 @@ 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); + output_damage_surface(output, drag_icon->wlr_drag_icon->surface, drag_icon->lx, drag_icon->ly, true); } } @@ -636,23 +611,20 @@ handle_request_start_drag(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, request_start_drag); struct wlr_seat_request_start_drag_event *event = data; - if (wlr_seat_validate_pointer_grab_serial(seat->seat, - event->origin, event->serial)) { + if (wlr_seat_validate_pointer_grab_serial(seat->seat, event->origin, event->serial)) { wlr_seat_start_pointer_drag(seat->seat, event->drag, event->serial); return; } struct wlr_touch_point *point; - if (wlr_seat_validate_touch_grab_serial(seat->seat, - event->origin, event->serial, &point)) { - wlr_seat_start_touch_drag(seat->seat, - event->drag, event->serial, point); + if (wlr_seat_validate_touch_grab_serial(seat->seat, event->origin, event->serial, &point)) { + wlr_seat_start_touch_drag(seat->seat, event->drag, event->serial, point); return; } // TODO: tablet grabs - wlr_log(WLR_DEBUG, "Ignoring start_drag request: " - "could not validate pointer/touch serial %" PRIu32, event->serial); + wlr_log(WLR_DEBUG, "Ignoring start_drag request: could not validate pointer/touch serial %" PRIu32, + event->serial); wlr_data_source_destroy(event->drag->source); } @@ -792,8 +764,7 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) wl_list_init(&seat->drag_icons); seat->request_start_drag.notify = handle_request_start_drag; - wl_signal_add(&seat->seat->events.request_start_drag, - &seat->request_start_drag); + wl_signal_add(&seat->seat->events.request_start_drag, &seat->request_start_drag); seat->start_drag.notify = handle_start_drag; wl_signal_add(&seat->seat->events.start_drag, &seat->start_drag); @@ -863,13 +834,10 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(wlr_seat); if (keyboard) { - wlr_seat_keyboard_notify_enter(wlr_seat, view->wlr_surface, - keyboard->keycodes, - keyboard->num_keycodes, + wlr_seat_keyboard_notify_enter(wlr_seat, view->wlr_surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); } else { - wlr_seat_keyboard_notify_enter(wlr_seat, view->wlr_surface, - NULL, 0, NULL); + wlr_seat_keyboard_notify_enter(wlr_seat, view->wlr_surface, NULL, 0, NULL); } process_cursor_motion(seat, -1); diff --git a/view.c b/view.c index 5f9bed0..b227121 100644 --- a/view.c +++ b/view.c @@ -131,7 +131,8 @@ view_is_primary(struct cg_view *view) } bool -view_is_transient_for(struct cg_view *child, struct cg_view *parent) { +view_is_transient_for(struct cg_view *child, struct cg_view *parent) +{ return child->impl->is_transient_for(child, parent); } @@ -286,8 +287,7 @@ 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) +view_init(struct cg_view *view, struct cg_server *server, enum cg_view_type type, const struct cg_view_impl *impl) { view->server = server; view->type = type; diff --git a/view.h b/view.h index 1da861c..1b0e90f 100644 --- a/view.h +++ b/view.h @@ -44,12 +44,9 @@ 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)(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); + void (*for_each_surface)(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data); + void (*for_each_popup)(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 { @@ -82,12 +79,10 @@ void view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t itera 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); +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); +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); diff --git a/xdg_shell.c b/xdg_shell.c index 4c6d0ee..26fe860 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -97,14 +97,15 @@ popup_unconstrain(struct cg_xdg_popup *popup) struct wlr_box *popup_box = &popup->wlr_popup->geometry; struct wlr_output_layout *output_layout = server->output_layout; - struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, view->lx + popup_box->x, view->ly + popup_box->y); + struct wlr_output *wlr_output = + wlr_output_layout_output_at(output_layout, view->lx + popup_box->x, view->ly + popup_box->y); struct wlr_box *output_box = wlr_output_layout_get_box(output_layout, wlr_output); struct wlr_box output_toplevel_box = { .x = output_box->x - view->lx, .y = output_box->y - view->ly, .width = output_box->width, - .height = output_box->height + .height = output_box->height, }; wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box); diff --git a/xwayland.c b/xwayland.c index cfc33f9..1aca1cc 100644 --- a/xwayland.c +++ b/xwayland.c @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include "server.h" #include "view.h" @@ -84,7 +84,8 @@ static void maximize(struct cg_view *view, int output_width, int output_height) { struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); - wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, view->lx, view->ly, output_width, output_height); + wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, view->lx, view->ly, output_width, + output_height); wlr_xwayland_surface_set_maximized(xwayland_view->xwayland_surface, true); } From 6d0714bfa3a781cea216d0b15c07ab3906922ff2 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Feb 2020 21:11:27 +0100 Subject: [PATCH 064/233] Begrudgingly format wl_list_* macros with a space before parameter list I can't seem to configure clang-format to remove this space... --- output.c | 14 +++++++------- render.c | 2 +- seat.c | 18 +++++++++--------- view.c | 10 +++++----- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/output.c b/output.c index 1ce90b3..d78389d 100644 --- a/output.c +++ b/output.c @@ -142,7 +142,7 @@ output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *dra cg_surface_iterator_func_t iterator, void *user_data) { struct cg_drag_icon *drag_icon; - wl_list_for_each(drag_icon, drag_icons, link) { + 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; @@ -157,7 +157,7 @@ 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) { + wl_list_for_each_reverse (view, &output->server->views, link) { output_view_for_each_surface(output, view, iterator, user_data); } @@ -195,7 +195,7 @@ scan_out_primary_view(struct cg_output *output) 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) { + wl_list_for_each (drag_icon, &server->seat->drag_icons, link) { if (drag_icon->wlr_drag_icon->mapped) { return false; } @@ -334,7 +334,7 @@ handle_output_transform(struct wl_listener *listener, void *data) } struct cg_view *view; - wl_list_for_each(view, &output->server->views, link) { + wl_list_for_each (view, &output->server->views, link) { view_position(view); } } @@ -349,7 +349,7 @@ handle_output_mode(struct wl_listener *listener, void *data) } struct cg_view *view; - wl_list_for_each(view, &output->server->views, link) { + wl_list_for_each (view, &output->server->views, link) { view_position(view); } } @@ -369,7 +369,7 @@ output_destroy(struct cg_output *output) wlr_output_layout_remove(server->output_layout, output->wlr_output); struct cg_view *view; - wl_list_for_each(view, &output->server->views, link) { + wl_list_for_each (view, &output->server->views, link) { view_position(view); } @@ -431,7 +431,7 @@ handle_new_output(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(server->output_layout, wlr_output); struct cg_view *view; - wl_list_for_each(view, &output->server->views, link) { + wl_list_for_each (view, &output->server->views, link) { view_position(view); } diff --git a/render.c b/render.c index c4b375e..1e3b614 100644 --- a/render.c +++ b/render.c @@ -173,7 +173,7 @@ output_render(struct cg_output *output, pixman_region32_t *damage) // 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) { + wl_list_for_each_reverse (view, &server->views, link) { render_view_toplevels(view, output, damage); } diff --git a/seat.c b/seat.c index 9fc8f0b..9016e38 100644 --- a/seat.c +++ b/seat.c @@ -67,7 +67,7 @@ desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surfa { struct cg_view *view; - wl_list_for_each(view, &server->views, link) { + wl_list_for_each (view, &server->views, link) { if (view_at(view, lx, ly, surface, sx, sy)) { return view; } @@ -156,7 +156,7 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) if (device->output_name != NULL) { struct cg_output *output; - wl_list_for_each(output, &seat->server->outputs, link) { + wl_list_for_each (output, &seat->server->outputs, link) { if (strcmp(device->output_name, output->wlr_output->name) == 0) { wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); break; @@ -198,7 +198,7 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) if (device->output_name != NULL) { struct cg_output *output; - wl_list_for_each(output, &seat->server->outputs, link) { + wl_list_for_each (output, &seat->server->outputs, link) { if (strcmp(device->output_name, output->wlr_output->name) == 0) { wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); break; @@ -528,7 +528,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) } struct cg_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &seat->drag_icons, link) { + wl_list_for_each (drag_icon, &seat->drag_icons, link) { drag_icon_update_position(drag_icon); } @@ -561,7 +561,7 @@ 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) { + 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); } } @@ -660,15 +660,15 @@ handle_destroy(struct wl_listener *listener, void *data) wl_list_remove(&seat->destroy.link); struct cg_keyboard *keyboard, *keyboard_tmp; - wl_list_for_each_safe(keyboard, keyboard_tmp, &seat->keyboards, link) { + wl_list_for_each_safe (keyboard, keyboard_tmp, &seat->keyboards, link) { handle_keyboard_destroy(&keyboard->destroy, NULL); } struct cg_pointer *pointer, *pointer_tmp; - wl_list_for_each_safe(pointer, pointer_tmp, &seat->pointers, link) { + wl_list_for_each_safe (pointer, pointer_tmp, &seat->pointers, link) { handle_pointer_destroy(&pointer->destroy, NULL); } struct cg_touch *touch, *touch_tmp; - wl_list_for_each_safe(touch, touch_tmp, &seat->touch, link) { + wl_list_for_each_safe (touch, touch_tmp, &seat->touch, link) { handle_touch_destroy(&touch->destroy, NULL); } wl_list_remove(&seat->new_input.link); @@ -827,7 +827,7 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) view_activate(view, true); char *title = view_get_title(view); struct cg_output *output; - wl_list_for_each(output, &server->outputs, link) { + wl_list_for_each (output, &server->outputs, link) { output_set_window_title(output, title); } free(title); diff --git a/view.c b/view.c index b227121..3dc7b34 100644 --- a/view.c +++ b/view.c @@ -140,7 +140,7 @@ void view_damage_part(struct cg_view *view) { struct cg_output *output; - wl_list_for_each(output, &view->server->outputs, link) { + wl_list_for_each (output, &view->server->outputs, link) { output_damage_surface(output, view->wlr_surface, view->lx, view->ly, false); } } @@ -149,7 +149,7 @@ void view_damage_whole(struct cg_view *view) { struct cg_output *output; - wl_list_for_each(output, &view->server->outputs, link) { + wl_list_for_each (output, &view->server->outputs, link) { output_damage_surface(output, view->wlr_surface, view->lx, view->ly, true); } } @@ -222,7 +222,7 @@ view_unmap(struct cg_view *view) wl_list_remove(&view->new_subsurface.link); struct cg_view_child *child, *tmp; - wl_list_for_each_safe(child, tmp, &view->children, link) { + wl_list_for_each_safe (child, tmp, &view->children, link) { child->destroy(child); } @@ -235,7 +235,7 @@ 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, parent_link) { + wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces, parent_link) { subsurface_create(view, subsurface); } @@ -300,7 +300,7 @@ 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) { + wl_list_for_each (view, &server->views, link) { if (view->wlr_surface == surface) { return view; } From 1e3417cd6580295a2d4b6c7e6cfe0757c56a210c Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Feb 2020 21:56:33 +0100 Subject: [PATCH 065/233] CI: add clang-format task --- .builds/archlinux.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index a8d1d8e..d5d6803 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -27,3 +27,9 @@ tasks: cd cage CC=clang meson build --werror -Dxwayland=true CC=clang ninja -C build scan-build + - clang-format: | + cd cage + meson build --werror -Dxwayland=true + ninja -C build clang-format + rm -rf build + git diff --exit-code From b2bcf06eee9301644bf40b53f07dd24c255a7e0f Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 17 Feb 2020 21:57:15 +0100 Subject: [PATCH 066/233] CI: add tasks that build without XWayland --- .builds/alpine.yml | 6 ++++++ .builds/archlinux.yml | 7 +++++++ .builds/freebsd.yml | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 9737be6..53f3c74 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -25,3 +25,9 @@ tasks: 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 index d5d6803..2a54809 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -23,10 +23,17 @@ tasks: 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 diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 0c62d4c..83f9b30 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -26,3 +26,9 @@ tasks: 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 From e96fccfa54511ed5ebfd095764b2c29c069ed82a Mon Sep 17 00:00:00 2001 From: project-repo Date: Fri, 21 Feb 2020 21:19:12 +0100 Subject: [PATCH 067/233] Implement support for wlr_keyboard_group (#123) * Implement support for wlr_keyboard_group * Cast pointers to void type when passing to wlr_log * Fix bracket style * Improve style * Remove unnecessary function * Prefer defined variable for brevity * Remove unnecessary pointer printing * Ameliorate style * Remove duplicate functionality * Set group repeat info * Ameliorate style * Fix bug introduced through renaming * Ameliorate style in seat.h * Remove cg_keyboard in favour of cg_keyboard_group * Remove unused signalling * Apply clang-format * Fix ordering of commands * Remove unnecessary field in cg_keyboard_group --- seat.c | 119 +++++++++++++++++++++++++++++++++++++-------------------- seat.h | 11 +++--- 2 files changed, 82 insertions(+), 48 deletions(-) diff --git a/seat.c b/seat.c index 9016e38..b7d85c9 100644 --- a/seat.c +++ b/seat.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,7 @@ update_capabilities(struct cg_seat *seat) { uint32_t caps = 0; - if (!wl_list_empty(&seat->keyboards)) { + if (!wl_list_empty(&seat->keyboard_groups)) { caps |= WL_SEAT_CAPABILITY_KEYBOARD; } if (!wl_list_empty(&seat->pointers)) { @@ -208,14 +209,12 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) } static void -handle_keyboard_modifiers(struct wl_listener *listener, void *data) +handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) { - struct cg_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); + wlr_seat_set_keyboard(seat->seat, device); + wlr_seat_keyboard_notify_modifiers(seat->seat, &device->keyboard->modifiers); - wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); - wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat, &keyboard->device->keyboard->modifiers); - - wlr_idle_notify_activity(keyboard->seat->server->idle, keyboard->seat->seat); + wlr_idle_notify_activity(seat->server->idle, seat->seat); } static bool @@ -235,20 +234,18 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) } static void -handle_keyboard_key(struct wl_listener *listener, void *data) +handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *data) { - struct cg_keyboard *keyboard = wl_container_of(listener, keyboard, key); - struct cg_seat *seat = keyboard->seat; struct wlr_event_keyboard_key *event = data; /* Translate from libinput keycode to an xkbcommon keycode. */ xkb_keycode_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, keycode, &syms); + int nsyms = xkb_state_key_get_syms(device->keyboard->xkb_state, keycode, &syms); bool handled = false; - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { /* If Alt is held down and this button was pressed, we * attempt to process it as a compositor @@ -260,7 +257,7 @@ handle_keyboard_key(struct wl_listener *listener, void *data) if (!handled) { /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat->seat, keyboard->device); + wlr_seat_set_keyboard(seat->seat, device); wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); } @@ -268,33 +265,78 @@ handle_keyboard_key(struct wl_listener *listener, void *data) } static void -handle_keyboard_destroy(struct wl_listener *listener, void *data) +handle_keyboard_group_key(struct wl_listener *listener, void *data) { - struct cg_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); - struct cg_seat *seat = keyboard->seat; + struct cg_keyboard_group *cg_group = wl_container_of(listener, cg_group, key); + handle_key_event(cg_group->wlr_group->input_device, cg_group->seat, data); +} - wl_list_remove(&keyboard->destroy.link); - wl_list_remove(&keyboard->modifiers.link); - wl_list_remove(&keyboard->key.link); - wl_list_remove(&keyboard->link); - free(keyboard); +static void +handle_keyboard_group_modifiers(struct wl_listener *listener, void *data) +{ + struct cg_keyboard_group *group = wl_container_of(listener, group, modifiers); + handle_modifier_event(group->wlr_group->input_device, group->seat); +} - update_capabilities(seat); +static void +cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) +{ + struct wlr_keyboard *wlr_keyboard = device->keyboard; + + struct cg_keyboard_group *group; + wl_list_for_each (group, &seat->keyboard_groups, link) { + struct wlr_keyboard_group *wlr_group = group->wlr_group; + if (wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard)) { + wlr_log(WLR_DEBUG, "Added new keyboard to existing group"); + return; + } + } + + /* 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)); + if (cg_group == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate keyboard group."); + return; + } + cg_group->seat = seat; + cg_group->wlr_group = wlr_keyboard_group_create(); + if (cg_group->wlr_group == NULL) { + wlr_log(WLR_ERROR, "Failed to create wlr keyboard group."); + goto cleanup; + } + + cg_group->wlr_group->data = cg_group; + wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, device->keyboard->keymap); + + wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, wlr_keyboard->repeat_info.rate, + wlr_keyboard->repeat_info.delay); + + 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); + + wl_signal_add(&cg_group->wlr_group->keyboard.events.key, &cg_group->key); + cg_group->key.notify = handle_keyboard_group_key; + wl_signal_add(&cg_group->wlr_group->keyboard.events.modifiers, &cg_group->modifiers); + cg_group->modifiers.notify = handle_keyboard_group_modifiers; + + return; + +cleanup: + if (cg_group && cg_group->wlr_group) { + wlr_keyboard_group_destroy(cg_group->wlr_group); + } + free(cg_group); } static void handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) { - struct cg_keyboard *keyboard = calloc(1, sizeof(struct cg_keyboard)); - if (!keyboard) { - wlr_log(WLR_ERROR, "Cannot allocate keyboard"); - return; - } - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { wlr_log(WLR_ERROR, "Unable to create XBK context"); - free(keyboard); return; } @@ -307,26 +349,17 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!keymap) { wlr_log(WLR_ERROR, "Unable to configure keyboard: keymap does not exist"); - free(keyboard); xkb_context_unref(context); return; } - keyboard->seat = seat; - keyboard->device = device; wlr_keyboard_set_keymap(device->keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); - wl_list_insert(&seat->keyboards, &keyboard->link); - keyboard->destroy.notify = handle_keyboard_destroy; - wl_signal_add(&device->events.destroy, &keyboard->destroy); - keyboard->key.notify = handle_keyboard_key; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); - keyboard->modifiers.notify = handle_keyboard_modifiers; - wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); + cg_keyboard_group_add(device, seat); wlr_seat_set_keyboard(seat->seat, device); } @@ -659,9 +692,10 @@ handle_destroy(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, destroy); wl_list_remove(&seat->destroy.link); - struct cg_keyboard *keyboard, *keyboard_tmp; - wl_list_for_each_safe (keyboard, keyboard_tmp, &seat->keyboards, link) { - handle_keyboard_destroy(&keyboard->destroy, NULL); + struct cg_keyboard_group *group, *group_tmp; + wl_list_for_each_safe (group, group_tmp, &seat->keyboard_groups, link) { + wlr_keyboard_group_destroy(group->wlr_group); + free(group); } struct cg_pointer *pointer, *pointer_tmp; wl_list_for_each_safe (pointer, pointer_tmp, &seat->pointers, link) { @@ -756,6 +790,7 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) wl_signal_add(&seat->seat->events.request_set_primary_selection, &seat->request_set_primary_selection); wl_list_init(&seat->keyboards); + wl_list_init(&seat->keyboard_groups); wl_list_init(&seat->pointers); wl_list_init(&seat->touch); diff --git a/seat.h b/seat.h index de3ddc8..188543d 100644 --- a/seat.h +++ b/seat.h @@ -20,6 +20,7 @@ struct cg_seat { struct wl_listener destroy; struct wl_list keyboards; + struct wl_list keyboard_groups; struct wl_list pointers; struct wl_list touch; struct wl_listener new_input; @@ -48,14 +49,12 @@ struct cg_seat { struct wl_listener request_set_primary_selection; }; -struct cg_keyboard { - struct wl_list link; // seat::keyboards +struct cg_keyboard_group { + struct wlr_keyboard_group *wlr_group; struct cg_seat *seat; - struct wlr_input_device *device; - - struct wl_listener modifiers; struct wl_listener key; - struct wl_listener destroy; + struct wl_listener modifiers; + struct wl_list link; // cg_seat::keyboard_groups }; struct cg_pointer { From 27391f174a1fe385899074f13453667b98af8621 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 22 Feb 2020 00:23:03 +0100 Subject: [PATCH 068/233] Cage: check for sigchld_source being NULL before removing it If something goes wrong during startup (i.e., the wlroots backend cannot be created), we jump to the end. This then unconditionally removes the sigchld_source, but that hasn't been set at this point yet. --- cage.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 74fa6a7..a1ba450 100644 --- a/cage.c +++ b/cage.c @@ -495,7 +495,9 @@ end: wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); - wl_event_source_remove(sigchld_source); + if (sigchld_source) { + wl_event_source_remove(sigchld_source); + } seat_destroy(server.seat); /* This function is not null-safe, but we only ever get here with a proper wl_display. */ From 9886efa112fd8e2fba3350c9874cf7bec498a3d3 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 23 Feb 2020 16:00:57 +0100 Subject: [PATCH 069/233] seat: log around input device mapping (#128) This should make it easier to troubleshoot why, for example, a touch input device isn't mapped to a touch output device. See #126. --- seat.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/seat.c b/seat.c index b7d85c9..34a7553 100644 --- a/seat.c +++ b/seat.c @@ -124,6 +124,27 @@ update_capabilities(struct cg_seat *seat) } } +static void +map_input_device_to_output(struct cg_seat *seat, struct wlr_input_device *device) +{ + if (!device->output_name) { + wlr_log(WLR_INFO, "Input device %s cannot be mapped to an output device\n", device->name); + return; + } + + struct cg_output *output; + wl_list_for_each (output, &seat->server->outputs, link) { + if (strcmp(device->output_name, output->wlr_output->name) == 0) { + wlr_log(WLR_INFO, "Mapping input device %s to output device %s\n", device->name, + output->wlr_output->name); + wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); + return; + } + } + + wlr_log(WLR_INFO, "Couldn't map input device %s to an output\n", device->name); +} + static void handle_touch_destroy(struct wl_listener *listener, void *data) { @@ -155,15 +176,7 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) touch->destroy.notify = handle_touch_destroy; wl_signal_add(&touch->device->events.destroy, &touch->destroy); - if (device->output_name != NULL) { - struct cg_output *output; - wl_list_for_each (output, &seat->server->outputs, link) { - if (strcmp(device->output_name, output->wlr_output->name) == 0) { - wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); - break; - } - } - } + map_input_device_to_output(seat, device); } static void @@ -197,15 +210,7 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) pointer->destroy.notify = handle_pointer_destroy; wl_signal_add(&device->events.destroy, &pointer->destroy); - if (device->output_name != NULL) { - struct cg_output *output; - wl_list_for_each (output, &seat->server->outputs, link) { - if (strcmp(device->output_name, output->wlr_output->name) == 0) { - wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); - break; - } - } - } + map_input_device_to_output(seat, device); } static void From fc5564645e3d29fc1da38db5dcc22a6e08dd4168 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 27 Feb 2020 20:39:15 +0100 Subject: [PATCH 070/233] seat: remove signals earlier in seat destroy handler (#130) This fixes a bunch of invalid writes found with valgrind. --- seat.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/seat.c b/seat.c index 34a7553..56c7d14 100644 --- a/seat.c +++ b/seat.c @@ -696,6 +696,17 @@ handle_destroy(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, destroy); wl_list_remove(&seat->destroy.link); + wl_list_remove(&seat->cursor_motion.link); + wl_list_remove(&seat->cursor_motion_absolute.link); + wl_list_remove(&seat->cursor_button.link); + wl_list_remove(&seat->cursor_axis.link); + wl_list_remove(&seat->cursor_frame.link); + wl_list_remove(&seat->touch_down.link); + wl_list_remove(&seat->touch_up.link); + wl_list_remove(&seat->touch_motion.link); + wl_list_remove(&seat->request_set_cursor.link); + wl_list_remove(&seat->request_set_selection.link); + wl_list_remove(&seat->request_set_primary_selection.link); struct cg_keyboard_group *group, *group_tmp; wl_list_for_each_safe (group, group_tmp, &seat->keyboard_groups, link) { @@ -716,17 +727,6 @@ handle_destroy(struct wl_listener *listener, void *data) if (seat->cursor) { wlr_cursor_destroy(seat->cursor); } - wl_list_remove(&seat->cursor_motion.link); - wl_list_remove(&seat->cursor_motion_absolute.link); - wl_list_remove(&seat->cursor_button.link); - wl_list_remove(&seat->cursor_axis.link); - wl_list_remove(&seat->cursor_frame.link); - wl_list_remove(&seat->touch_down.link); - wl_list_remove(&seat->touch_up.link); - wl_list_remove(&seat->touch_motion.link); - wl_list_remove(&seat->request_set_cursor.link); - wl_list_remove(&seat->request_set_selection.link); - wl_list_remove(&seat->request_set_primary_selection.link); free(seat); } From 5d7ff9e64dc71cdcfd66097571b1c995e1556e47 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Mon, 16 Mar 2020 15:32:24 -0400 Subject: [PATCH 071/233] =?UTF-8?q?Don=E2=80=99t=20terminate=20display=20w?= =?UTF-8?q?hen=20no=20view=20is=20found=20(#132)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Don’t terminate display when no view is found Some apps like RetroArch will quit and fork itself to switch modes (like from the menu to a loaded core). This means that for a very short period of time we have no view available for Wayland. Right now, Cage doesn’t actually exit when it does this terminate, so you get this kind of zombie child process that is running but not showing anything on the screen because there is no compositor. The solution I have here is to just keep Cage’s Wayland server running to avoid this issue. I’m open to other idea, but this seems sane to me. Perhaps an alternative is to check if the process is still alive when this happens, if not then we can do the quitting behavior. In addition, we could make this an option if some users don’t want this behavior. * Remove "ever_been_mapped" from cg_wayland_view --- view.c | 12 ------------ xwayland.c | 1 - xwayland.h | 15 --------------- 3 files changed, 28 deletions(-) diff --git a/view.c b/view.c index 3dc7b34..0b8d377 100644 --- a/view.c +++ b/view.c @@ -259,14 +259,6 @@ void view_destroy(struct cg_view *view) { struct cg_server *server = view->server; - bool ever_been_mapped = true; - -#if CAGE_HAS_XWAYLAND - if (view->type == CAGE_XWAYLAND_VIEW) { - struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); - ever_been_mapped = xwayland_view->ever_been_mapped; - } -#endif if (view->wlr_surface != NULL) { view_unmap(view); @@ -279,10 +271,6 @@ view_destroy(struct cg_view *view) if (!empty) { struct cg_view *prev = wl_container_of(server->views.next, prev, link); seat_set_focus(server->seat, prev); - } else if (ever_been_mapped) { - /* The list is empty and the last view has been - mapped, so we can safely exit. */ - wl_display_terminate(server->wl_display); } } diff --git a/xwayland.c b/xwayland.c index 1aca1cc..53c9768 100644 --- a/xwayland.c +++ b/xwayland.c @@ -151,7 +151,6 @@ handle_xwayland_surface_map(struct wl_listener *listener, void *data) xwayland_view->commit.notify = handle_xwayland_surface_commit; wl_signal_add(&xwayland_view->xwayland_surface->surface->events.commit, &xwayland_view->commit); - xwayland_view->ever_been_mapped = true; view_map(view, xwayland_view->xwayland_surface->surface); view_damage_whole(view); diff --git a/xwayland.h b/xwayland.h index 4cfd4b0..d257f57 100644 --- a/xwayland.h +++ b/xwayland.h @@ -9,21 +9,6 @@ struct cg_xwayland_view { struct cg_view view; struct wlr_xwayland_surface *xwayland_surface; - - /* Some applications that aren't yet Wayland-native or - otherwise "special" (e.g. Firefox Nightly and Google - Chrome/Chromium) spawn an XWayland surface upon startup - that is almost immediately closed again. This makes Cage - think there are no views left, which results in it - exiting. However, after this initial (unmapped) surface, - the "real" application surface is opened. This leads to - these applications' startup sequences being interrupted by - Cage exiting. Hence, to work around this issue, Cage checks - whether an XWayland surface has ever been mapped and exits - only if 1) the XWayland surface has ever been mapped and 2) - this was the last surface Cage manages. */ - bool ever_been_mapped; - struct wl_listener destroy; struct wl_listener unmap; struct wl_listener map; From 6eb693c05b5b34d4ed5ad8234a9f79a14ac8e07d Mon Sep 17 00:00:00 2001 From: travankor <38744110+travankor@users.noreply.github.com> Date: Fri, 17 Apr 2020 21:58:26 +0200 Subject: [PATCH 072/233] Cage: drop gid before uid (#142) If setuid is called first then the target user may not have the ability to setgid. See https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges --- cage.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cage.c b/cage.c index a1ba450..e4eb90f 100644 --- a/cage.c +++ b/cage.c @@ -146,13 +146,14 @@ static bool drop_permissions(void) { if (getuid() != geteuid() || getgid() != getegid()) { - if (setuid(getuid()) != 0 || setgid(getgid()) != 0) { + // Set the gid and uid in the correct order. + if (setgid(getgid()) != 0 || setuid(getuid()) != 0) { wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); return false; } } - if (setuid(0) != -1) { + if (setgid(0) != -1 || setuid(0) != -1) { wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to restore it after setuid), refusing to start"); return false; From 4e96d913fbeabe524579213a90135a8241a73c47 Mon Sep 17 00:00:00 2001 From: travankor <38744110+travankor@users.noreply.github.com> Date: Sun, 31 May 2020 15:14:18 +0200 Subject: [PATCH 073/233] Add man page. (#141) * Add man page. * CI: add scdoc --- .builds/alpine.yml | 1 + .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + README.md | 7 +++-- cage.1.scd | 64 +++++++++++++++++++++++++++++++++++++++++++ meson.build | 26 ++++++++++++++++++ meson_options.txt | 1 + 7 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 cage.1.scd diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 53f3c74..07780b6 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -6,6 +6,7 @@ packages: - libinput-dev - libxkbcommon-dev - pixman-dev + - scdoc - wayland-dev - wayland-protocols - xorg-server-xwayland diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 2a54809..cc68c3c 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -4,6 +4,7 @@ packages: - meson - libinput - libxkbcommon + - scdoc - wayland - wayland-protocols - xorg-server-xwayland diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 83f9b30..10f132a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -7,6 +7,7 @@ packages: - graphics/mesa-libs - graphics/wayland - graphics/wayland-protocols + - textproc/scdoc - x11/libinput - x11/libxkbcommon - x11/pixman diff --git a/README.md b/README.md index 6f8a7de..e1b6f56 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,10 @@ and published on [GitHub](https://github.com/Hjdskes/cage/releases). ## Building and running Cage You can build Cage with the [meson](https://mesonbuild.com/) build system. It -requires wayland, wlroots and xkbcommon to be installed. Note that Cage is -developed against the latest tag of wlroots, in order to not constantly chase -breaking changes as soon as they occur. +requires wayland, wlroots, and xkbcommon to be installed. Optionally, install +scdoc for manual pages. Note that Cage is developed against the latest tag of +wlroots, in order to not constantly chase breaking changes as soon as they +occur. Simply execute the following steps to build Cage: diff --git a/cage.1.scd b/cage.1.scd new file mode 100644 index 0000000..2ca43bc --- /dev/null +++ b/cage.1.scd @@ -0,0 +1,64 @@ +cage(1) + +# NAME + +cage - a Wayland kiosk compsitor + +# SYNOPSIS + +*cage* [-dhrv] [--] _application_ [application argument ...] + +# DESCRIPTION + +Cage runs a single, maximized application. Cage can run multiple applications, +but only a single one is visible at any point in time. User interaction and +activities outside the scope of the running application are prevented. + +# OPTIONS + +*-d* + Don't draw client side decorations when possible. + +*-h* + Show the help message. + +*-r* + Rotate the output 90 degrees clockwise. This can be specifed up to three + times, each resulting in an additional 90 degrees clockwise rotation. + +*-v* + Show the version number and exit. + +# ENVIRONMENT + +_DISPLAY_ + If compiled with Xwayland support, this will be set to the name of the + X display used for Xwayland. Otherwise, probe the X11 backend. + +_WAYLAND_DISPLAY_ + Specifies the name of the Wayland display that Cage is running on. + +_XCURSOR_PATH_ + Directory where cursors are located. + +_XCURSOR_SIZE_ + Specifies the configured cursor size. + +_XCURSOR_THEME_ + Specifies the configured cursor theme. + +_XKB_DEFAULT_RULES_, _XKB_DEFAULT_MODEL_, _XKB_DEFAULT_LAYOUT_, +_XKB_DEFAULT_VARIANT_, _XKB_DEFAULT_OPTIONS_ + Configures the xkb keyboard settings. See *xkeyboard-config*(7). + +# SEE ALSO + +*xkeyboard-config(7)* + +# BUGS + +Report bugs at https://github.com/Hjdskes/cage + +# AUTHORS + +Jente Hidskes diff --git a/meson.build b/meson.build index ce93de0..90bc400 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,32 @@ conf_data = configuration_data() conf_data.set10('CAGE_HAS_XWAYLAND', have_xwayland) 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) + sh = find_program('sh', native: true) + mandir = get_option('mandir') + man_files = [ + 'cage.1.scd' + ] + foreach filename : man_files + topic = filename.split('.')[-3].split('/')[-1] + section = filename.split('.')[-2] + output = '@0@.@1@'.format(topic, section) + + custom_target( + output, + input: filename, + output: output, + command: [ + sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) + ], + install: true, + install_dir: '@0@/man@1@'.format(mandir, section) + ) + endforeach +endif + cage_sources = [ 'cage.c', 'idle_inhibit_v1.c', diff --git a/meson_options.txt b/meson_options.txt index 87763ff..a28e2cf 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,2 @@ +option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('xwayland', type: 'boolean', value: 'false', description: 'Enable support for X11 applications') From f4b63cd6b8d8df7cc9a28fabb930ff77cb530115 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 31 May 2020 15:31:16 +0200 Subject: [PATCH 074/233] output: add enable and disable functions These will allow different patterns of multimonitor behaviour. In a followup commit, we will introduce a behaviour where only the last connected output is in use. --- output.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/output.c b/output.c index d78389d..97f02d6 100644 --- a/output.c +++ b/output.c @@ -239,6 +239,37 @@ scan_out_primary_view(struct cg_output *output) return wlr_output_commit(wlr_output); } +static void +output_enable(struct cg_output *output) +{ + struct wlr_output *wlr_output = output->wlr_output; + + /* Outputs get enabled by the backend before firing the new_output event, + * so we can't do a check for already enabled outputs here unless we + * duplicate the enabled property in cg_output. */ + wlr_log(WLR_DEBUG, "Enabling output %s", wlr_output->name); + + wlr_output_layout_add_auto(output->server->output_layout, wlr_output); + wlr_output_enable(wlr_output, true); + wlr_output_commit(wlr_output); +} + +static void +output_disable(struct cg_output *output) +{ + struct wlr_output *wlr_output = output->wlr_output; + + if (!wlr_output->enabled) { + wlr_log(WLR_DEBUG, "Not disabling already disabled output %s", wlr_output->name); + return; + } + + 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); + wlr_output_commit(wlr_output); +} + static void damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data) { @@ -270,6 +301,11 @@ damage_surface_iterator(struct cg_output *output, struct wlr_surface *surface, s 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); @@ -427,23 +463,20 @@ handle_new_output(struct wl_listener *listener, void *data) if (preferred_mode) { wlr_output_set_mode(wlr_output, preferred_mode); } - wlr_output_set_transform(wlr_output, server->output_transform); - wlr_output_layout_add_auto(server->output_layout, wlr_output); + wlr_output_set_transform(wlr_output, output->server->output_transform); - struct cg_view *view; - wl_list_for_each (view, &output->server->views, link) { - view_position(view); - } if (wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, wlr_output->scale); } - wlr_output_enable(wlr_output, true); - wlr_output_commit(wlr_output); + output_enable(output); - wlr_output_damage_add_whole(output->damage); + struct cg_view *view; + wl_list_for_each (view, &output->server->views, link) { + view_position(view); + } } void @@ -451,6 +484,11 @@ output_set_window_title(struct cg_output *output, const char *title) { struct wlr_output *wlr_output = output->wlr_output; + if (!wlr_output->enabled) { + wlr_log(WLR_DEBUG, "Not setting window title for disabled output %s", wlr_output->name); + return; + } + if (wlr_output_is_wl(wlr_output)) { wlr_wl_output_set_title(wlr_output, title); #if WLR_HAS_X11_BACKEND From 64299054db9e6cfb9848ba03b4573510d90734c6 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 31 May 2020 15:45:47 +0200 Subject: [PATCH 075/233] output: add output_mode enum This enum provides two means of behaviour for multi-output setups: extend the display across all outputs, or only use the last one. The former is the current (and default) behaviour; the latter will be added in the next commit. --- cage.c | 2 ++ server.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/cage.c b/cage.c index e4eb90f..541c1c2 100644 --- a/cage.c +++ b/cage.c @@ -270,6 +270,8 @@ main(int argc, char *argv[]) return 1; } + server.output_mode = CAGE_MULTI_OUTPUT_MODE_EXTEND; + #ifdef DEBUG wlr_log_init(WLR_DEBUG, NULL); #else diff --git a/server.h b/server.h index 5caa0c1..401dd55 100644 --- a/server.h +++ b/server.h @@ -16,6 +16,11 @@ #include "seat.h" #include "view.h" +enum cg_multi_output_mode { + CAGE_MULTI_OUTPUT_MODE_EXTEND, + CAGE_MULTI_OUTPUT_MODE_LAST, +}; + struct cg_server { struct wl_display *wl_display; struct wl_list views; @@ -26,6 +31,7 @@ struct cg_server { struct wl_listener new_idle_inhibitor_v1; struct wl_list inhibitors; + enum cg_multi_output_mode output_mode; struct wlr_output_layout *output_layout; struct wl_list outputs; struct wl_listener new_output; From 72f6c0bae39ef4ed5ad913f9ed2d4a323c078dcc Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 31 May 2020 16:04:01 +0200 Subject: [PATCH 076/233] output: implement CAGE_MULTI_OUTPUT_MODE_LAST In this mode, only the last connected output will be used. If that one is unplugged, the previously last connected output will be enabled. This for example allows one to switch between two outputs, e.g. on a handheld device such as a mobile phone. --- output.c | 21 ++++++++++++++++----- server.h | 4 +++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/output.c b/output.c index 97f02d6..d6e34aa 100644 --- a/output.c +++ b/output.c @@ -404,15 +404,20 @@ output_destroy(struct cg_output *output) wlr_output_layout_remove(server->output_layout, output->wlr_output); - struct cg_view *view; - wl_list_for_each (view, &output->server->views, link) { - view_position(view); - } - free(output); if (wl_list_empty(&server->outputs)) { wl_display_terminate(server->wl_display); + } else if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST) { + struct cg_output *prev = wl_container_of(server->outputs.next, prev, link); + if (prev) { + output_enable(prev); + + struct cg_view *view; + wl_list_for_each (view, &server->views, link) { + view_position(view); + } + } } } @@ -465,6 +470,12 @@ handle_new_output(struct wl_listener *listener, void *data) } wlr_output_set_transform(wlr_output, output->server->output_transform); + if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST) { + struct cg_output *next = wl_container_of(output->link.next, next, link); + if (next) { + output_disable(next); + } + } if (wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, diff --git a/server.h b/server.h index 401dd55..1469802 100644 --- a/server.h +++ b/server.h @@ -33,7 +33,9 @@ struct cg_server { enum cg_multi_output_mode output_mode; struct wlr_output_layout *output_layout; - struct wl_list outputs; + /* Includes disabled outputs; depending on the output_mode + * some outputs may be disabled. */ + struct wl_list outputs; // cg_output::link struct wl_listener new_output; struct wl_listener xdg_toplevel_decoration; From bd961db6f5384f223c44604e19e60c773ba2e06b Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 31 May 2020 16:20:59 +0200 Subject: [PATCH 077/233] cage: allow setting output mode --- cage.1.scd | 7 ++++++- cage.c | 29 ++++++++++++++++++----------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/cage.1.scd b/cage.1.scd index 2ca43bc..51714a3 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -6,7 +6,7 @@ cage - a Wayland kiosk compsitor # SYNOPSIS -*cage* [-dhrv] [--] _application_ [application argument ...] +*cage* [-dhmrv] [--] _application_ [application argument ...] # DESCRIPTION @@ -22,6 +22,11 @@ activities outside the scope of the running application are prevented. *-h* Show the help message. +*-m* + Set the multi-monitor behaviour. Supported modes are: + *last* Cage uses only the last connected monitor. + *extend* Cage extends the display across all connected monitors. + *-r* Rotate the output 90 degrees clockwise. This can be specifed up to three times, each resulting in an additional 90 degrees clockwise rotation. diff --git a/cage.c b/cage.c index 541c1c2..6853587 100644 --- a/cage.c +++ b/cage.c @@ -185,11 +185,13 @@ usage(FILE *file, const char *cage) "Usage: %s [OPTIONS] [--] APPLICATION\n" "\n" " -d\t Don't draw client side decorations, when possible\n" - " -r\t Rotate the output 90 degrees clockwise, specify up to three times\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" + " -r\t Rotate the output 90 degrees clockwise, specify up to three times\n" " -v\t Show the version number and exit\n" "\n" " Use -- when you want to pass arguments to APPLICATION\n", @@ -201,20 +203,14 @@ parse_args(struct cg_server *server, int argc, char *argv[]) { int c; #ifdef DEBUG - while ((c = getopt(argc, argv, "drDhv")) != -1) { + while ((c = getopt(argc, argv, "dDhm:rv")) != -1) { #else - while ((c = getopt(argc, argv, "drhv")) != -1) { + while ((c = getopt(argc, argv, "dhm:rv")) != -1) { #endif switch (c) { case 'd': server->xdg_decoration = true; break; - case 'r': - server->output_transform++; - if (server->output_transform > WL_OUTPUT_TRANSFORM_270) { - server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; - } - break; #ifdef DEBUG case 'D': server->debug_damage_tracking = true; @@ -223,6 +219,19 @@ parse_args(struct cg_server *server, int argc, char *argv[]) case 'h': usage(stdout, argv[0]); return false; + case 'm': + if (strcmp(optarg, "last") == 0) { + server->output_mode = CAGE_MULTI_OUTPUT_MODE_LAST; + } else if (strcmp(optarg, "extend") == 0) { + server->output_mode = CAGE_MULTI_OUTPUT_MODE_EXTEND; + } + break; + case 'r': + server->output_transform++; + if (server->output_transform > WL_OUTPUT_TRANSFORM_270) { + server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; + } + break; case 'v': fprintf(stdout, "Cage version " CAGE_VERSION "\n"); exit(0); @@ -270,8 +279,6 @@ main(int argc, char *argv[]) return 1; } - server.output_mode = CAGE_MULTI_OUTPUT_MODE_EXTEND; - #ifdef DEBUG wlr_log_init(WLR_DEBUG, NULL); #else From 79992f39f3f451cac8140bc1053f57e2355c4f3c Mon Sep 17 00:00:00 2001 From: Jan Tatje Date: Wed, 15 Jul 2020 16:50:38 +0200 Subject: [PATCH 078/233] Add option to allow changing VT Code that does the VT switch taken from sway. --- cage.c | 21 ++++++++++++--------- seat.c | 18 ++++++++++++++---- server.h | 2 ++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/cage.c b/cage.c index 6853587..5281436 100644 --- a/cage.c +++ b/cage.c @@ -192,6 +192,7 @@ usage(FILE *file, const char *cage) " -m extend Extend the display across all connected outputs (default)\n" " -m last Use only the last connected output\n" " -r\t Rotate the output 90 degrees clockwise, specify up to three times\n" + " -s\t Allow VT switching\n" " -v\t Show the version number and exit\n" "\n" " Use -- when you want to pass arguments to APPLICATION\n", @@ -203,9 +204,9 @@ parse_args(struct cg_server *server, int argc, char *argv[]) { int c; #ifdef DEBUG - while ((c = getopt(argc, argv, "dDhm:rv")) != -1) { + while ((c = getopt(argc, argv, "dDhm:rsv")) != -1) { #else - while ((c = getopt(argc, argv, "dhm:rv")) != -1) { + while ((c = getopt(argc, argv, "dhm:rsv")) != -1) { #endif switch (c) { case 'd': @@ -232,6 +233,9 @@ parse_args(struct cg_server *server, int argc, char *argv[]) server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; } break; + case 's': + server->allow_vt_switch = true; + break; case 'v': fprintf(stdout, "Cage version " CAGE_VERSION "\n"); exit(0); @@ -257,7 +261,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_backend *backend = NULL; struct wlr_renderer *renderer = NULL; struct wlr_compositor *compositor = NULL; struct wlr_data_device_manager *data_device_manager = NULL; @@ -301,8 +304,8 @@ main(int argc, char *argv[]) sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); - backend = wlr_backend_autocreate(server.wl_display, NULL); - if (!backend) { + server.backend = wlr_backend_autocreate(server.wl_display, NULL); + if (!server.backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); ret = 1; goto end; @@ -313,7 +316,7 @@ main(int argc, char *argv[]) goto end; } - renderer = wlr_backend_get_renderer(backend); + renderer = wlr_backend_get_renderer(server.backend); wlr_renderer_init_wl_display(renderer, server.wl_display); wl_list_init(&server.views); @@ -344,9 +347,9 @@ main(int argc, char *argv[]) * available on the backend. We use this only to detect the * first output and ignore subsequent outputs. */ server.new_output.notify = handle_new_output; - wl_signal_add(&backend->events.new_output, &server.new_output); + wl_signal_add(&server.backend->events.new_output, &server.new_output); - server.seat = seat_create(&server, backend); + server.seat = seat_create(&server, server.backend); if (!server.seat) { wlr_log(WLR_ERROR, "Unable to create the seat"); ret = 1; @@ -467,7 +470,7 @@ main(int argc, char *argv[]) goto end; } - if (!wlr_backend_start(backend)) { + if (!wlr_backend_start(server.backend)) { wlr_log(WLR_ERROR, "Unable to start the wlroots backend"); ret = 1; goto end; diff --git a/seat.c b/seat.c index 56c7d14..48c126f 100644 --- a/seat.c +++ b/seat.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -225,13 +226,22 @@ handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) static bool handle_keybinding(struct cg_server *server, xkb_keysym_t sym) { - switch (sym) { #ifdef DEBUG - case XKB_KEY_Escape: + if (sym == XKB_KEY_Escape) { wl_display_terminate(server->wl_display); - break; + } else #endif - default: + if (server->allow_vt_switch && sym >= XKB_KEY_XF86Switch_VT_1 + && sym <= XKB_KEY_XF86Switch_VT_12) { + if (wlr_backend_is_multi(server->backend)) { + struct wlr_session *session = + wlr_backend_get_session(server->backend); + if (session) { + unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1; + wlr_session_change_vt(session, vt); + } + } + } else { return false; } wlr_idle_notify_activity(server->idle, server->seat->seat); diff --git a/server.h b/server.h index 1469802..817637b 100644 --- a/server.h +++ b/server.h @@ -24,6 +24,7 @@ enum cg_multi_output_mode { struct cg_server { struct wl_display *wl_display; struct wl_list views; + struct wlr_backend *backend; struct cg_seat *seat; struct wlr_idle *idle; @@ -45,6 +46,7 @@ struct cg_server { #endif bool xdg_decoration; + bool allow_vt_switch; enum wl_output_transform output_transform; #ifdef DEBUG bool debug_damage_tracking; From a6b1cf1d698361b3b201fbc149abee7296040c9d Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 9 May 2020 11:39:00 +0000 Subject: [PATCH 079/233] output: unbreak with wlroots 0.11.0 Port changes changes from https://github.com/swaywm/sway/commit/9d0aa0cb8396 https://github.com/swaywm/sway/commit/40e87fa98afd --- output.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/output.c b/output.c index d6e34aa..96f915c 100644 --- a/output.c +++ b/output.c @@ -232,10 +232,7 @@ scan_out_primary_view(struct cg_output *output) return false; } - if (!wlr_output_attach_buffer(wlr_output, surface->buffer)) { - return false; - } - + wlr_output_attach_buffer(wlr_output, &surface->buffer->base); return wlr_output_commit(wlr_output); } From 0d694db6fecb5aca65292f16f0c89719c4321900 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 16 Jul 2020 15:21:17 +0200 Subject: [PATCH 080/233] Invert wlr_xcursor_manager_load return value --- cage.c | 2 +- output.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cage.c b/cage.c index 5281436..b8e76d6 100644 --- a/cage.c +++ b/cage.c @@ -452,7 +452,7 @@ main(int argc, char *argv[]) wlr_log(WLR_DEBUG, "XWayland is running on display %s", xwayland->display_name); } - if (wlr_xcursor_manager_load(xcursor_manager, 1)) { + if (!wlr_xcursor_manager_load(xcursor_manager, 1)) { wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); } struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); diff --git a/output.c b/output.c index 96f915c..e162af9 100644 --- a/output.c +++ b/output.c @@ -474,7 +474,7 @@ handle_new_output(struct wl_listener *listener, void *data) } } - if (wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { + if (!wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, wlr_output->scale); } From 99aba6b89bd28e5c2e2847c73e3b8bbc7042073f Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Wed, 15 Jul 2020 23:30:48 +0000 Subject: [PATCH 081/233] meson: require wlroots 0.11.0 after 6a12da196068 ../output.c:235:57: error: no member named 'base' in 'struct wlr_buffer' wlr_output_attach_buffer(wlr_output, &surface->buffer->base); ~~~~~~~~~~~~~~~ ^ --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 90bc400..ee6d4c7 100644 --- a/meson.build +++ b/meson.build @@ -34,7 +34,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.9.1') +wlroots = dependency('wlroots', version: '>= 0.11.0') wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') pixman = dependency('pixman-1') From efb11217696d5b3561678d6d2fcc0f4008d40196 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 9 May 2020 11:46:10 +0000 Subject: [PATCH 082/233] CI: bump wlroots version to 0.11.0 --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 07780b6..3ccff6e 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -18,7 +18,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.10.0 + git checkout 0.11.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index cc68c3c..99627cf 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -16,7 +16,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.10.0 + git checkout 0.11.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 10f132a..73bd94b 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -19,7 +19,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.10.0 + git checkout 0.11.0 meson --prefix=/usr/local build -Dexamples=false ninja -C build sudo ninja -C build install From 1037adbab700eac50a645d82de4f7184e1ff2fa2 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 16 Jul 2020 15:41:31 +0200 Subject: [PATCH 083/233] man: document -s and fix some typos --- cage.1.scd | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cage.1.scd b/cage.1.scd index 51714a3..a67cddf 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -2,11 +2,11 @@ cage(1) # NAME -cage - a Wayland kiosk compsitor +cage - a Wayland kiosk compositor # SYNOPSIS -*cage* [-dhmrv] [--] _application_ [application argument ...] +*cage* [-dhmrsv] [--] _application_ [application argument ...] # DESCRIPTION @@ -23,14 +23,17 @@ activities outside the scope of the running application are prevented. Show the help message. *-m* - Set the multi-monitor behaviour. Supported modes are: + Set the multi-monitor behavior. Supported modes are: *last* Cage uses only the last connected monitor. *extend* Cage extends the display across all connected monitors. *-r* - Rotate the output 90 degrees clockwise. This can be specifed up to three + Rotate the output 90 degrees clockwise. This can be specified up to three times, each resulting in an additional 90 degrees clockwise rotation. +*-s* + Allow VT switching + *-v* Show the version number and exit. From 7b861bf17562b078b73e378ec56a44401e506a6a Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 16 Jul 2020 15:35:45 +0200 Subject: [PATCH 084/233] Release Cage 0.1.2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ee6d4c7..e7e12b8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cage', 'c', - version: '0.1.1', + version: '0.1.2', license: 'MIT', default_options: [ 'c_std=c11', From d09739373288adef901cdd58c983c0d02302932c Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 16 Jul 2020 16:25:19 +0200 Subject: [PATCH 085/233] man: indent with tabs --- cage.1.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.1.scd b/cage.1.scd index a67cddf..4ca1bea 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -32,7 +32,7 @@ activities outside the scope of the running application are prevented. times, each resulting in an additional 90 degrees clockwise rotation. *-s* - Allow VT switching + Allow VT switching *-v* Show the version number and exit. From 7d37322906f0e4d6fc42a13ec407fc8482cceba5 Mon Sep 17 00:00:00 2001 From: Michael Weiss Date: Fri, 17 Jul 2020 13:44:46 +0200 Subject: [PATCH 086/233] seat.c: Make clangformat happy and simplify the control flow This restores the original behaviour from 2cf40f7, is easier to read, and satisfies clangformat. This also doesn't call wlr_idle_notify_activity anymore, which was probably unintended. --- seat.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/seat.c b/seat.c index 48c126f..651ed32 100644 --- a/seat.c +++ b/seat.c @@ -229,13 +229,12 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) #ifdef DEBUG if (sym == XKB_KEY_Escape) { wl_display_terminate(server->wl_display); - } else + return true; + } #endif - if (server->allow_vt_switch && sym >= XKB_KEY_XF86Switch_VT_1 - && sym <= XKB_KEY_XF86Switch_VT_12) { + if (server->allow_vt_switch && sym >= XKB_KEY_XF86Switch_VT_1 && sym <= XKB_KEY_XF86Switch_VT_12) { if (wlr_backend_is_multi(server->backend)) { - struct wlr_session *session = - wlr_backend_get_session(server->backend); + struct wlr_session *session = wlr_backend_get_session(server->backend); if (session) { unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1; wlr_session_change_vt(session, vt); From 0d85c1652e676806a5c065bdc88e83f0b33a0a5e Mon Sep 17 00:00:00 2001 From: Michael Weiss Date: Fri, 17 Jul 2020 13:15:32 +0200 Subject: [PATCH 087/233] meson.build: Unify the indentation (replace all tabs) --- meson.build | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index e7e12b8..788a500 100644 --- a/meson.build +++ b/meson.build @@ -132,8 +132,8 @@ cage_sources = [ cage_headers = [ configure_file(input: 'config.h.in', - output: 'config.h', - configuration: conf_data), + output: 'config.h', + configuration: conf_data), 'idle_inhibit_v1.h', 'output.h', 'render.h', @@ -164,10 +164,10 @@ executable( ) summary = [ - '', - 'Cage @0@'.format(version), - '', - ' xwayland: @0@'.format(have_xwayland), - '' + '', + 'Cage @0@'.format(version), + '', + ' xwayland: @0@'.format(have_xwayland), + '' ] message('\n'.join(summary)) From 4a01da76f1b1fc4166d8e060482ba6eb06e63458 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 15 Nov 2020 05:36:13 +0000 Subject: [PATCH 088/233] seat: chase swaywm/wlroots@7693f61d8138 seat.c:263:56: error: use of undeclared identifier 'WLR_KEY_PRESSED' if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { ^ Based on https://github.com/swaywm/sway/commit/bb342ac5e6de --- seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seat.c b/seat.c index 651ed32..dea384c 100644 --- a/seat.c +++ b/seat.c @@ -260,7 +260,7 @@ handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *da bool handled = false; uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); - if ((modifiers & WLR_MODIFIER_ALT) && event->state == WLR_KEY_PRESSED) { + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { /* If Alt is held down and this button was pressed, we * attempt to process it as a compositor * keybinding. */ From e6762725ed8754e7e5a998dbbe707ee0b117e9cb Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 15 Nov 2020 05:41:47 +0000 Subject: [PATCH 089/233] seat: chase swaywm/wlroots@e06c9e43afd8 seat.c:453:58: error: incomplete definition of type 'struct wlr_event_touch_down' wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); ~~~~~^ seat.c:450:9: note: forward declaration of 'struct wlr_event_touch_down' struct wlr_event_touch_down *event = data; ^ Based on https://github.com/swaywm/sway/commit/a56098a24e43 --- seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/seat.c b/seat.c index dea384c..08f25a3 100644 --- a/seat.c +++ b/seat.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #if CAGE_HAS_XWAYLAND From 90da4ee4dcdef6a3cf09be9debbf8e2033bf4739 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Tue, 5 Jan 2021 09:02:58 +0000 Subject: [PATCH 090/233] cage: chase swaywm/wlroots@4b03bdc3ab0c cage.c:307:61: error: too many arguments to function call, expected single argument 'display', have 2 arguments server.backend = wlr_backend_autocreate(server.wl_display, NULL); ~~~~~~~~~~~~~~~~~~~~~~ ^~~~ /usr/include/sys/_null.h:34:14: note: expanded from macro 'NULL' #define NULL ((void *)0) ^~~~~~~~~~~ /usr/local/include/wlr/backend.h:36:21: note: 'wlr_backend_autocreate' declared here struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); ^ Based on https://github.com/swaywm/sway/commit/53f5197c26f1 --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index b8e76d6..5392535 100644 --- a/cage.c +++ b/cage.c @@ -304,7 +304,7 @@ main(int argc, char *argv[]) sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); - server.backend = wlr_backend_autocreate(server.wl_display, NULL); + server.backend = wlr_backend_autocreate(server.wl_display); if (!server.backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); ret = 1; From 82bad3f0fc1d9fb416877b96339b7daf104fe4ec Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Thu, 14 Jan 2021 00:54:00 +0000 Subject: [PATCH 091/233] xdg_shell: chase swaywm/wlroots@07111828c5a2 xdg_shell.c:230:2: warning: implicit declaration of function 'wlr_xdg_surface_for_each_popup' is invalid in C99 [-Wimplicit-function-declaration] wlr_xdg_surface_for_each_popup(xdg_shell_view->xdg_surface, iterator, data); ^ ld: error: undefined symbol: wlr_xdg_surface_for_each_popup >>> referenced by xdg_shell.c:230 (../xdg_shell.c:230) >>> cage.p/xdg_shell.c.o:(for_each_popup) Based on https://github.com/swaywm/sway/commit/5438cc158a1b --- output.c | 6 +++--- output.h | 4 ++-- render.c | 12 +----------- view.c | 6 +++--- view.h | 4 ++-- xdg_shell.c | 6 +++--- xwayland.c | 2 +- 7 files changed, 15 insertions(+), 25 deletions(-) diff --git a/output.c b/output.c index e162af9..4c4d77a 100644 --- a/output.c +++ b/output.c @@ -122,8 +122,8 @@ output_view_for_each_surface(struct cg_output *output, struct cg_view *view, cg_ } void -output_view_for_each_popup(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, - void *user_data) +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, @@ -134,7 +134,7 @@ output_view_for_each_popup(struct cg_output *output, struct cg_view *view, cg_su }; wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - view_for_each_popup(view, output_for_each_surface_iterator, &data); + view_for_each_popup_surface(view, output_for_each_surface_iterator, &data); } void diff --git a/output.h b/output.h index 687b45c..a573df9 100644 --- a/output.h +++ b/output.h @@ -28,8 +28,8 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_ 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(struct cg_output *output, struct cg_view *view, 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); diff --git a/render.c b/render.c index 1e3b614..166a088 100644 --- a/render.c +++ b/render.c @@ -119,23 +119,13 @@ render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_reg output_surface_for_each_surface(output, view->wlr_surface, ox, oy, render_surface_iterator, &data); } -static void -render_popup_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *data) -{ - /* Render this popup's surface. */ - render_surface_iterator(output, surface, box, data); - - /* Render this popup's child toplevels. */ - output_surface_for_each_surface(output, surface, box->x, box->y, 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(output, view, render_popup_iterator, &data); + output_view_for_each_popup_surface(output, view, render_surface_iterator, &data); } void diff --git a/view.c b/view.c index 0b8d377..b9ba9c2 100644 --- a/view.c +++ b/view.c @@ -206,12 +206,12 @@ view_for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator } void -view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) +view_for_each_popup_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) { - if (!view->impl->for_each_popup) { + if (!view->impl->for_each_popup_surface) { return; } - view->impl->for_each_popup(view, iterator, data); + view->impl->for_each_popup_surface(view, iterator, data); } void diff --git a/view.h b/view.h index 1b0e90f..cd16e42 100644 --- a/view.h +++ b/view.h @@ -45,7 +45,7 @@ struct cg_view_impl { 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)(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); }; @@ -75,7 +75,7 @@ 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(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); diff --git a/xdg_shell.c b/xdg_shell.c index 26fe860..2e42347 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -224,10 +224,10 @@ for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, voi } static void -for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) +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(xdg_shell_view->xdg_surface, iterator, data); + wlr_xdg_surface_for_each_popup_surface(xdg_shell_view->xdg_surface, iterator, data); } static struct wlr_surface * @@ -305,7 +305,7 @@ static const struct cg_view_impl xdg_shell_view_impl = { .maximize = maximize, .destroy = destroy, .for_each_surface = for_each_surface, - .for_each_popup = for_each_popup, + .for_each_popup_surface = for_each_popup_surface, .wlr_surface_at = wlr_surface_at, }; diff --git a/xwayland.c b/xwayland.c index 53c9768..2aae0f9 100644 --- a/xwayland.c +++ b/xwayland.c @@ -181,7 +181,7 @@ static const struct cg_view_impl xwayland_view_impl = { .destroy = destroy, .for_each_surface = for_each_surface, /* XWayland doesn't have a separate popup iterator. */ - .for_each_popup = NULL, + .for_each_popup_surface = NULL, .wlr_surface_at = wlr_surface_at, }; From a5aa497ff180d61405c8941ea12fcda046ee958e Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 16 Jan 2021 22:20:37 +0000 Subject: [PATCH 092/233] output: chase swaywm/wlroots@cc56b4f07373 output.c:456:36: error: no member named 'transform' in 'struct wlr_output::(anonymous at /usr/local/include/wlr/types/wlr_output.h:154:2)' wl_signal_add(&wlr_output->events.transform, &output->transform); ~~~~~~~~~~~~~~~~~~ ^ Based on https://github.com/swaywm/sway/commit/2c76923282b1 --- output.c | 19 +++++++++++-------- output.h | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/output.c b/output.c index 4c4d77a..d8da3b9 100644 --- a/output.c +++ b/output.c @@ -358,17 +358,20 @@ frame_done: } static void -handle_output_transform(struct wl_listener *listener, void *data) +handle_output_commit(struct wl_listener *listener, void *data) { - struct cg_output *output = wl_container_of(listener, output, transform); + struct cg_output *output = wl_container_of(listener, output, commit); + struct wlr_output_event_commit *event = data; if (!output->wlr_output->enabled) { return; } - struct cg_view *view; - wl_list_for_each (view, &output->server->views, link) { - view_position(view); + if (event->committed & WLR_OUTPUT_STATE_TRANSFORM) { + struct cg_view *view; + wl_list_for_each (view, &output->server->views, link) { + view_position(view); + } } } @@ -393,8 +396,8 @@ output_destroy(struct cg_output *output) struct cg_server *server = output->server; wl_list_remove(&output->destroy.link); + wl_list_remove(&output->commit.link); wl_list_remove(&output->mode.link); - wl_list_remove(&output->transform.link); wl_list_remove(&output->damage_frame.link); wl_list_remove(&output->damage_destroy.link); wl_list_remove(&output->link); @@ -450,10 +453,10 @@ handle_new_output(struct wl_listener *listener, void *data) output->damage = wlr_output_damage_create(wlr_output); wl_list_insert(&server->outputs, &output->link); + output->commit.notify = handle_output_commit; + wl_signal_add(&wlr_output->events.commit, &output->commit); output->mode.notify = handle_output_mode; wl_signal_add(&wlr_output->events.mode, &output->mode); - output->transform.notify = handle_output_transform; - wl_signal_add(&wlr_output->events.transform, &output->transform); output->destroy.notify = handle_output_destroy; wl_signal_add(&wlr_output->events.destroy, &output->destroy); output->damage_frame.notify = handle_output_damage_frame; diff --git a/output.h b/output.h index a573df9..b3fd3b4 100644 --- a/output.h +++ b/output.h @@ -13,8 +13,8 @@ struct cg_output { struct wlr_output *wlr_output; struct wlr_output_damage *damage; + struct wl_listener commit; struct wl_listener mode; - struct wl_listener transform; struct wl_listener destroy; struct wl_listener damage_frame; struct wl_listener damage_destroy; From eb18383e8e01bd3bd41a3309689f832d53d4c797 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Tue, 5 Jan 2021 09:19:47 +0000 Subject: [PATCH 093/233] meson: require wlroots 0.13.0 after 0db62672a4c1 cage.c:307:59: error: too few arguments to function call, expected 2, have 1 server.backend = wlr_backend_autocreate(server.wl_display); ~~~~~~~~~~~~~~~~~~~~~~ ^ subprojects/wlroots/include/wlr/backend.h:43:21: note: 'wlr_backend_autocreate' declared here struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, ^ --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 788a500..3756433 100644 --- a/meson.build +++ b/meson.build @@ -34,7 +34,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.11.0') +wlroots = dependency('wlroots', version: '>= 0.13.0') wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') pixman = dependency('pixman-1') From cb937856490a1e652bc97b5b54c2182c457ef0c6 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 15 Mar 2021 10:50:59 +0000 Subject: [PATCH 094/233] CI: chase swaywm/wlroots@3504bb587daa + swaywm/wlroots@e8ad05913fb9 meson.build:70:4: ERROR: Problem encountered: Cannot build Cage with XWayland support: wlroots has been built without it --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 3ccff6e..ac2294f 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -9,7 +9,7 @@ packages: - scdoc - wayland-dev - wayland-protocols - - xorg-server-xwayland + - xwayland sources: - https://github.com/swaywm/wlroots - https://github.com/Hjdskes/cage diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 99627cf..347c0ae 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -7,7 +7,7 @@ packages: - scdoc - wayland - wayland-protocols - - xorg-server-xwayland + - xorg-xwayland sources: - https://github.com/swaywm/wlroots - https://github.com/Hjdskes/cage diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 73bd94b..516ea0c 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -11,6 +11,7 @@ packages: - x11/libinput - x11/libxkbcommon - x11/pixman + - x11-servers/xwayland sources: - https://github.com/swaywm/wlroots - https://github.com/Hjdskes/cage From 40fc92f7e774b292427644a11ce5ee209cbaa471 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Thu, 8 Apr 2021 13:43:12 +0000 Subject: [PATCH 095/233] CI: chase swaywm/wlroots@de5347d0f2a8 Run-time dependency xcb-icccm found: NO (tried pkgconfig and cmake) Message: Required for Xwayland support. --- .builds/alpine.yml | 1 + .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index ac2294f..58af149 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -9,6 +9,7 @@ packages: - scdoc - wayland-dev - wayland-protocols + - xcb-util-wm-dev - xwayland sources: - https://github.com/swaywm/wlroots diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 347c0ae..a79b3fe 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -7,6 +7,7 @@ packages: - scdoc - wayland - wayland-protocols + - xcb-util-wm - xorg-xwayland sources: - https://github.com/swaywm/wlroots diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 516ea0c..3a6aefb 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -11,6 +11,7 @@ packages: - x11/libinput - x11/libxkbcommon - x11/pixman + - x11/xcb-util-wm - x11-servers/xwayland sources: - https://github.com/swaywm/wlroots From b07647fb780f270a0b68f62f78a1d28633803bd6 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Tue, 5 Jan 2021 09:41:35 +0000 Subject: [PATCH 096/233] CI: explicitly depend on Mesa on Arch Linux meson.build:102:0: ERROR: Dependency "egl" not found, tried pkgconfig --- .builds/archlinux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index a79b3fe..5ffa9e4 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -4,6 +4,7 @@ packages: - meson - libinput - libxkbcommon + - mesa - scdoc - wayland - wayland-protocols From 0891f4b81424932cd3642462fa00b7888e3d4781 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Tue, 5 Jan 2021 09:09:14 +0000 Subject: [PATCH 097/233] CI: bump wlroots version to 0.13.0 --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 58af149..044966e 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -19,7 +19,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.11.0 + git checkout 0.13.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 5ffa9e4..0a64c48 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -18,7 +18,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.11.0 + git checkout 0.13.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 3a6aefb..af4ee34 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -21,7 +21,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.11.0 + git checkout 0.13.0 meson --prefix=/usr/local build -Dexamples=false ninja -C build sudo ninja -C build install From aa91af32a5a2bf0aaa83b1768e868808447c9936 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 16 Apr 2021 14:01:38 +0200 Subject: [PATCH 098/233] Update version to 0.1.3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3756433..a268f1a 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cage', 'c', - version: '0.1.2', + version: '0.1.3', license: 'MIT', default_options: [ 'c_std=c11', From efaf76e9ab2032ed6eedee7260c0857fac34b5b1 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 16 Apr 2021 14:34:57 +0200 Subject: [PATCH 099/233] Include release scripts --- contrib/increment-version | 25 +++++++++++++++++++++++++ contrib/release | 21 +++++++++++++++++++++ contrib/sign-release | 12 ++++++++++++ contrib/tag-release | 26 ++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100755 contrib/increment-version create mode 100755 contrib/release create mode 100755 contrib/sign-release create mode 100755 contrib/tag-release diff --git a/contrib/increment-version b/contrib/increment-version new file mode 100755 index 0000000..11a3354 --- /dev/null +++ b/contrib/increment-version @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +if [ "$#" -ne 1 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +new_version="$1" + +if [ "$new_version" != "${new_version#v}" ]; then + echo "Error: The new version shouldn't be prefixed with a \"v\"." >&2 + exit 1 +fi + +set -x + +sed -i meson.build -e "s/^ version: '.*'/ version: '$new_version'/" + +echo -n "Minimum wlroots version? " +read -r wlr_version_min + +sed -i meson.build -e "s/'wlroots', version: '.*'/'wlroots', version: '>= $wlr_version_min'/" + +git add meson.build +git commit -m "Update version to $new_version" \ No newline at end of file diff --git a/contrib/release b/contrib/release new file mode 100755 index 0000000..514d370 --- /dev/null +++ b/contrib/release @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +if [ "$#" -ne 1 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +new_version="$1" + +if [ "$new_version" != "${new_version#v}" ]; then + echo "Error: The new version shouldn't be prefixed with a \"v\"." >&2 + exit 1 +fi + +set -x + +./increment_version "$new_version" +./tag-release "$new_version" +./sign-release + +git push --tags \ No newline at end of file diff --git a/contrib/sign-release b/contrib/sign-release new file mode 100755 index 0000000..b11fd02 --- /dev/null +++ b/contrib/sign-release @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -x + +project="$(basename "$(pwd)")" +last=$(git describe --tags --abbrev=0) + +prefix="$project-${last#v}" +archive="$prefix.tar.gz" + +git archive --prefix="$prefix/" -o "$archive" "$last" +gpg --output "$archive".sig --detach-sig "$archive" diff --git a/contrib/tag-release b/contrib/tag-release new file mode 100755 index 0000000..4452964 --- /dev/null +++ b/contrib/tag-release @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -x + +if [ "$#" -ne 1 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +last=$(git describe --tags --abbrev=0) +echo "Last release was $last" + +next="v$1" + +shortlog="$(git shortlog --no-merges "$last"..)" + +printf "Shortlog: \n\n%s\n\nRelease $next? [y/N] " "$shortlog" +read -r answer + +if [ "$answer" != "y" ]; then + exit 0 +fi + +project="$(basename "$(pwd)")" + +(echo "$project $next"; echo ""; echo "$shortlog") | git tag "$next" -ase -F - From 851268bedce2995f297f4a32fa46f6daf9b23243 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Thu, 3 Jun 2021 17:53:11 +0000 Subject: [PATCH 100/233] view: chase swaywm/wlroots@9e58301df7f0 view.c:238:52: error: no member named 'subsurfaces' in 'struct wlr_surface' wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces, parent_link) { ~~~~~~~~~~~~~~~~~ ^ /usr/include/wayland-util.h:443:30: note: expanded from macro 'wl_list_for_each' for (pos = wl_container_of((head)->next, pos, member); \ ^~~~ /usr/include/wayland-util.h:409:32: note: expanded from macro 'wl_container_of' (__typeof__(sample))((char *)(ptr) - \ ^~~ Based on https://github.com/swaywm/sway/commit/3162766eef14 --- view.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/view.c b/view.c index b9ba9c2..3f3b0ed 100644 --- a/view.c +++ b/view.c @@ -235,7 +235,10 @@ 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, parent_link) { + 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); } From 636185bf9c2a1b1a4305698bb4dac17ebc4efe82 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Wed, 23 Jun 2021 16:44:03 +0000 Subject: [PATCH 101/233] meson: require wlroots 0.14.0 after 9a4523d47efe view.c:238:52: error: no member named 'subsurfaces_below' in 'struct wlr_surface' wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces_below, parent_link) { ~~~~~~~~~~~~~~~~~ ^ /usr/include/wayland-util.h:443:30: note: expanded from macro 'wl_list_for_each' for (pos = wl_container_of((head)->next, pos, member); \ ^~~~ /usr/include/wayland-util.h:409:32: note: expanded from macro 'wl_container_of' (__typeof__(sample))((char *)(ptr) - \ ^~~ --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a268f1a..5b0f9a6 100644 --- a/meson.build +++ b/meson.build @@ -34,7 +34,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.13.0') +wlroots = dependency('wlroots', version: '>= 0.14.0') wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') pixman = dependency('pixman-1') From 08e58c2b45c221dc3d72f7285272ca49db829f5e Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Wed, 23 Jun 2021 16:45:11 +0000 Subject: [PATCH 102/233] CI: bump wlroots version to 0.14.0 --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 044966e..ef32a95 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -19,7 +19,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.13.0 + git checkout 0.14.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 0a64c48..99cdd24 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -18,7 +18,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.13.0 + git checkout 0.14.0 meson --prefix=/usr build -Dexamples=false ninja -C build sudo ninja -C build install diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index af4ee34..92a2119 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -21,7 +21,7 @@ tasks: # version, instead of master, to avoid any breaking changes in wlroots. - wlroots: | cd wlroots - git checkout 0.13.0 + git checkout 0.14.0 meson --prefix=/usr/local build -Dexamples=false ninja -C build sudo ninja -C build install From 646b3e80b45a011676eb4190652b8c506d56e7a4 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 26 Jun 2021 09:39:40 +0200 Subject: [PATCH 103/233] Update version to 0.1.4 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5b0f9a6..3a84794 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cage', 'c', - version: '0.1.3', + version: '0.1.4', license: 'MIT', default_options: [ 'c_std=c11', From cdb1cdf3b4ecfdf98f10e5edd14ea71c4d2504e7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 9 Aug 2021 20:31:41 +0200 Subject: [PATCH 104/233] Don't manually parse XKB_* env vars libxkbcommon will do it for us if we provide a NULL struct xkb_rule_names. --- seat.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/seat.c b/seat.c index 08f25a3..ab6efbb 100644 --- a/seat.c +++ b/seat.c @@ -355,13 +355,7 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) 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); From 5424a35aba643840e958303b16e0ba69807bb9ef Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 9 Aug 2021 20:33:38 +0200 Subject: [PATCH 105/233] Damage drag icon when destroyed This fixes the drag icon not disappearing when releasing the pointer button. Reproduction steps: - Open gedit - Drag some text around - Release the pointer button --- seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/seat.c b/seat.c index ab6efbb..e8f0d92 100644 --- a/seat.c +++ b/seat.c @@ -642,6 +642,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) { struct cg_drag_icon *drag_icon = wl_container_of(listener, drag_icon, destroy); + drag_icon_damage(drag_icon); wl_list_remove(&drag_icon->link); wl_list_remove(&drag_icon->destroy.link); free(drag_icon); From 1a3ab3eb3ad0f4a1addb8f9a9427d8b369b19511 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 9 Aug 2021 20:29:18 +0200 Subject: [PATCH 106/233] build: allow using subproject for wlroots This is handy when testing cage with a newer wlroots copy, or when developing cage and wlroots patches in parallel. --- meson.build | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 3a84794..6b5bce6 100644 --- a/meson.build +++ b/meson.build @@ -34,7 +34,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.14.0') +wlroots = dependency('wlroots', version: '>= 0.14.0', fallback: ['wlroots', 'wlroots']) wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') pixman = dependency('pixman-1') @@ -65,12 +65,11 @@ server_protos = declare_dependency( ) if get_option('xwayland') - wlroots_has_xwayland = cc.get_define('WLR_HAS_XWAYLAND', prefix: '#include ', dependencies: wlroots) == '1' + wlroots_has_xwayland = wlroots.get_variable(pkgconfig: 'have_xwayland', internal: 'have_xwayland') == 'true' if not wlroots_has_xwayland error('Cannot build Cage with XWayland support: wlroots has been built without it') - else - have_xwayland = true endif + have_xwayland = true else have_xwayland = false endif From b21f9c6322ddd651e16615c57f5f0f6b8d5ba7b1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 11 Aug 2021 11:58:16 +0200 Subject: [PATCH 107/233] Fix count_surface_iterator This increments the pointer value, not the actual count. References: https://github.com/Hjdskes/cage/issues/176 --- output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output.c b/output.c index d8da3b9..0f4f6b2 100644 --- a/output.c +++ b/output.c @@ -185,7 +185,7 @@ static void count_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *_box, void *data) { size_t *n = data; - n++; + (*n)++; } static bool From 60492959a7c3521c24173b3d3c8cb069938d77a5 Mon Sep 17 00:00:00 2001 From: Lorenz Brun Date: Thu, 8 Jul 2021 21:19:42 +0200 Subject: [PATCH 108/233] Set xdg_toplevel geometry for fullscreen clients --- xdg_shell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xdg_shell.c b/xdg_shell.c index 2e42347..5bac6de 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -242,6 +242,8 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * { struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_fullscreen); struct wlr_xdg_toplevel_set_fullscreen_event *event = data; + struct wlr_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); } From 0ba1c40aa62927058f150f70fad8b6d87bd3ccde Mon Sep 17 00:00:00 2001 From: Palanix Date: Sat, 21 Aug 2021 02:22:12 +0200 Subject: [PATCH 109/233] fix drag --- seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seat.c b/seat.c index e8f0d92..ac950aa 100644 --- a/seat.c +++ b/seat.c @@ -564,7 +564,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) 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) { + if (!focus_changed && time > 0 || wlr_seat->drag) { wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy); } } From d1367b1c461de95e3698a8f994b9b89bf2505d40 Mon Sep 17 00:00:00 2001 From: Palanix Date: Mon, 6 Sep 2021 16:00:12 +0200 Subject: [PATCH 110/233] removed focus_changed logic --- seat.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/seat.c b/seat.c index ac950aa..806b957 100644 --- a/seat.c +++ b/seat.c @@ -563,10 +563,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->drag) { - 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; From 8385b62a9b31028fa356cc4130baebc8b6f4adec Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Thu, 9 Apr 2020 18:10:40 +0200 Subject: [PATCH 111/233] Move to GitHub actions --- .builds/alpine.yml | 35 ------------------ .builds/archlinux.yml | 45 ---------------------- .builds/freebsd.yml | 37 ------------------- .clang-format-ignore | 1 + .github/workflows/main.yml | 76 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 117 deletions(-) delete mode 100644 .builds/alpine.yml delete mode 100644 .builds/archlinux.yml delete mode 100644 .builds/freebsd.yml create mode 100644 .clang-format-ignore create mode 100644 .github/workflows/main.yml 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..4711f70 --- /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.14.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.14.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.14.0 + - name: Run scan-build + run: | + meson build-scan-build -Dxwayland=true + ninja -C build-scan-build scan-build \ No newline at end of file From 388d60d6b88733330fb83dd440051ee805cc7ec7 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sat, 18 Dec 2021 12:55:08 +0100 Subject: [PATCH 112/233] Tune compiler options --- meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 6b5bce6..80e72dc 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', ], From 395189fb051ed722c7b10b6cb11caa8f6904079c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 11 Aug 2021 11:31:14 +0200 Subject: [PATCH 113/233] Upgrade to wlroots 0.15 - Update wlr_box includes to util/box.h: the wlroots header has been moved upstream. - Subsurface fields have been moved - Create renderer and allocator, stop using wlr_backend_get_renderer - Initalize output rendering --- .github/workflows/main.yml | 8 ++++---- cage.c | 21 +++++++++++++++++---- meson.build | 2 +- output.c | 5 +++++ render.c | 26 ++++++++------------------ server.h | 2 ++ util.c | 2 -- util.h | 2 +- view.c | 5 ++--- view.h | 2 +- xdg_shell.c | 1 - xwayland.c | 1 - 12 files changed, 41 insertions(+), 36 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4711f70..5e95347 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,7 +31,7 @@ jobs: 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.14.0 + 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 }}) @@ -50,7 +50,7 @@ jobs: 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.14.0 + 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 @@ -69,8 +69,8 @@ jobs: 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.14.0 + 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 \ No newline at end of file + ninja -C build-scan-build scan-build diff --git a/cage.c b/cage.c index 5392535..f9db7a9 100644 --- a/cage.c +++ b/cage.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -261,7 +262,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; @@ -316,8 +316,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 +342,7 @@ main(int argc, char *argv[]) goto end; } - compositor = wlr_compositor_create(server.wl_display, renderer); + compositor = wlr_compositor_create(server.wl_display, server.renderer); if (!compositor) { wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); ret = 1; diff --git a/meson.build b/meson.build index 80e72dc..7c57967 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.14.0', fallback: ['wlroots', 'wlroots']) +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') diff --git a/output.c b/output.c index 0f4f6b2..60266e1 100644 --- a/output.c +++ b/output.c @@ -442,6 +442,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"); diff --git a/render.c b/render.c index 166a088..ffa960f 100644 --- a/render.c +++ b/render.c @@ -10,11 +10,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -27,8 +27,6 @@ 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, @@ -41,7 +39,7 @@ scissor_output(struct wlr_output *output, pixman_box32_t *rect) 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); + wlr_renderer_scissor(output->renderer, &box); } struct render_data { @@ -52,8 +50,6 @@ 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); @@ -66,7 +62,7 @@ render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage, 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); + wlr_render_texture_with_matrix(wlr_output->renderer, texture, matrix, 1.0f); } damage_finish: @@ -134,13 +130,7 @@ 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); + wlr_renderer_begin(server->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"); @@ -149,7 +139,7 @@ output_render(struct cg_output *output, pixman_region32_t *damage) #ifdef DEBUG if (server->debug_damage_tracking) { - wlr_renderer_clear(renderer, (float[]){1.0f, 0.0f, 0.0f, 1.0f}); + wlr_renderer_clear(server->renderer, (float[]){1.0f, 0.0f, 0.0f, 1.0f}); } #endif @@ -158,7 +148,7 @@ output_render(struct cg_output *output, pixman_region32_t *damage) 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); + wlr_renderer_clear(server->renderer, color); } // TODO: render only top view, possibly use focused view for this, see #35. @@ -178,8 +168,8 @@ 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); + wlr_renderer_scissor(server->renderer, NULL); + wlr_renderer_end(server->renderer); int output_width, output_height; wlr_output_transformed_resolution(wlr_output, &output_width, &output_height); diff --git a/server.h b/server.h index 817637b..74970c5 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; diff --git a/util.c b/util.c index 95de499..714c7e3 100644 --- a/util.c +++ b/util.c @@ -6,8 +6,6 @@ * See the LICENSE file accompanying this file. */ -#include - #include "util.h" int diff --git a/util.h b/util.h index db6bc7d..b6281f3 100644 --- a/util.h +++ b/util.h @@ -1,7 +1,7 @@ #ifndef CG_UTIL_H #define CG_UTIL_H -#include +#include /** Apply scale to a width or height. */ int scale_length(int length, int offset, float scale); diff --git a/view.c b/view.c index 3f3b0ed..33b59b4 100644 --- a/view.c +++ b/view.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -235,10 +234,10 @@ 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) { + wl_list_for_each (subsurface, &view->wlr_surface->current.subsurfaces_below, current.link) { subsurface_create(view, subsurface); } - wl_list_for_each (subsurface, &view->wlr_surface->subsurfaces_above, parent_link) { + wl_list_for_each (subsurface, &view->wlr_surface->current.subsurfaces_above, current.link) { subsurface_create(view, subsurface); } diff --git a/view.h b/view.h index cd16e42..87477d0 100644 --- a/view.h +++ b/view.h @@ -5,9 +5,9 @@ #include #include -#include #include #include +#include #if CAGE_HAS_XWAYLAND #include #endif diff --git a/xdg_shell.c b/xdg_shell.c index 5bac6de..72ae43a 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/xwayland.c b/xwayland.c index 2aae0f9..ebd8e54 100644 --- a/xwayland.c +++ b/xwayland.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include From f5444833401d992bcaa6610be202b5b5d2d252dd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 9 Aug 2021 20:06:57 +0200 Subject: [PATCH 114/233] Use the wlroots scene-graph API References: https://github.com/swaywm/wlroots/pull/1966 --- cage.c | 8 +++++ output.c | 67 +++++++------------------------------- output.h | 4 --- render.c | 94 +++-------------------------------------------------- seat.c | 9 +++++ seat.h | 1 + server.h | 1 + view.c | 14 ++++++++ view.h | 1 + xdg_shell.c | 10 ++++++ xdg_shell.h | 1 + 11 files changed, 61 insertions(+), 149 deletions(-) diff --git a/cage.c b/cage.c index f9db7a9..a90639f 100644 --- a/cage.c +++ b/cage.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #if CAGE_HAS_XWAYLAND @@ -342,6 +343,13 @@ main(int argc, char *argv[]) goto end; } + server.scene = wlr_scene_create(); + if (!server.scene) { + wlr_log(WLR_ERROR, "Unable to create scene"); + ret = 1; + goto end; + } + compositor = wlr_compositor_create(server.wl_display, server.renderer); if (!compositor) { wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); diff --git a/output.c b/output.c index 60266e1..402a678 100644 --- a/output.c +++ b/output.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -105,63 +106,19 @@ output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *su 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); - } + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .output = output, + .ox = 0, + .oy = 0, + }; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - output_drag_icons_for_each_surface(output, &output->server->seat->drag_icons, iterator, user_data); + wlr_scene_node_for_each_surface(&output->server->scene->node, output_for_each_surface_iterator, &data); } struct send_frame_done_data { @@ -182,7 +139,7 @@ send_frame_done(struct cg_output *output, struct send_frame_done_data *data) } static void -count_surface_iterator(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *_box, void *data) +count_surface_iterator(struct wlr_surface *surface, int sx, int sy, void *data) { size_t *n = data; (*n)++; @@ -207,7 +164,7 @@ scan_out_primary_view(struct cg_output *output) } size_t n_surfaces = 0; - output_view_for_each_surface(output, view, count_surface_iterator, &n_surfaces); + wlr_scene_node_for_each_surface(&view->scene_surface->node, count_surface_iterator, &n_surfaces); if (n_surfaces > 1) { return false; } diff --git a/output.h b/output.h index b3fd3b4..8c5799f 100644 --- a/output.h +++ b/output.h @@ -28,10 +28,6 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_ 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); diff --git a/render.c b/render.c index ffa960f..9eb4d30 100644 --- a/render.c +++ b/render.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -46,84 +47,6 @@ 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]) -{ - 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(wlr_output->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) { @@ -151,18 +74,9 @@ output_render(struct cg_output *output, pixman_region32_t *damage) wlr_renderer_clear(server->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); + double lx = 0, ly = 0; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &lx, &ly); + wlr_scene_render_output(server->scene, wlr_output, lx, ly, damage); renderer_end: /* Draw software cursor in case hardware cursors aren't diff --git a/seat.c b/seat.c index 806b957..0ac976c 100644 --- a/seat.c +++ b/seat.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -632,6 +633,8 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) } drag_icon_damage(drag_icon); + + wlr_scene_node_set_position(&drag_icon->scene_surface->node, drag_icon->lx, drag_icon->ly); } static void @@ -642,6 +645,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) drag_icon_damage(drag_icon); wl_list_remove(&drag_icon->link); wl_list_remove(&drag_icon->destroy.link); + wlr_scene_node_destroy(&drag_icon->scene_surface->node); free(drag_icon); } @@ -684,6 +688,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_surface = wlr_scene_surface_create(&seat->server->scene->node, wlr_drag_icon->surface); + if (!drag_icon->scene_surface) { + free(drag_icon); + return; + } drag_icon->destroy.notify = handle_drag_icon_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &drag_icon->destroy); diff --git a/seat.h b/seat.h index 188543d..75f1cc6 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_surface *scene_surface; /* The drag icon has a position in layout coordinates. */ double lx, ly; diff --git a/server.h b/server.h index 74970c5..0712708 100644 --- a/server.h +++ b/server.h @@ -36,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 diff --git a/view.c b/view.c index 33b59b4..5f9169c 100644 --- a/view.c +++ b/view.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "output.h" @@ -173,6 +174,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_surface->node, view->lx, view->ly); + view->impl->maximize(view, layout_box->width, layout_box->height); } @@ -184,6 +188,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_surface->node, view->lx, view->ly); } void @@ -225,6 +231,8 @@ view_unmap(struct cg_view *view) child->destroy(child); } + wlr_scene_node_destroy(&view->scene_surface->node); + view->wlr_surface = NULL; } @@ -233,6 +241,12 @@ view_map(struct cg_view *view, struct wlr_surface *surface) { view->wlr_surface = surface; + view->scene_surface = wlr_scene_surface_create(&view->server->scene->node, surface); + if (!view->scene_surface) { + wl_resource_post_no_memory(surface->resource); + return; + } + struct wlr_subsurface *subsurface; wl_list_for_each (subsurface, &view->wlr_surface->current.subsurfaces_below, current.link) { subsurface_create(view, subsurface); diff --git a/view.h b/view.h index 87477d0..b748b03 100644 --- a/view.h +++ b/view.h @@ -26,6 +26,7 @@ struct cg_view { struct wl_list link; // server::views struct wl_list children; // cg_view_child::link struct wlr_surface *wlr_surface; + struct wlr_scene_surface *scene_surface; /* The view has a position in layout coordinates. */ int lx, ly; diff --git a/xdg_shell.c b/xdg_shell.c index 72ae43a..502d84a 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,14 @@ static void handle_xdg_popup_map(struct wl_listener *listener, void *data) { struct cg_xdg_popup *popup = wl_container_of(listener, popup, map); + struct wlr_scene_node *parent_node = &popup->view_child.view->scene_surface->node; + popup->scene_surface = wlr_scene_surface_create(parent_node, popup->view_child.wlr_surface); + if (!popup->scene_surface) { + return; + } + double sx, sy; + wlr_xdg_popup_get_position(popup->wlr_popup, &sx, &sy); + wlr_scene_node_set_position(&popup->scene_surface->node, sx, sy); view_damage_whole(popup->view_child.view); } @@ -67,6 +76,7 @@ static void handle_xdg_popup_unmap(struct wl_listener *listener, void *data) { struct cg_xdg_popup *popup = wl_container_of(listener, popup, unmap); + wlr_scene_node_destroy(&popup->scene_surface->node); view_damage_whole(popup->view_child.view); } diff --git a/xdg_shell.h b/xdg_shell.h index 45d87db..5ee0bba 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -22,6 +22,7 @@ struct cg_xdg_shell_view { struct cg_xdg_popup { struct cg_view_child view_child; struct wlr_xdg_popup *wlr_popup; + struct wlr_scene_surface *scene_surface; struct wl_listener destroy; struct wl_listener map; From 6d60c6c4640d432a10f3464b9ef492a59256b59f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 Aug 2021 11:37:19 +0200 Subject: [PATCH 115/233] Drop view_for_each_surface and view_for_each_popup_surface With the scene-graph, these are no longer used. --- view.c | 15 --------------- view.h | 4 ---- xdg_shell.c | 16 ---------------- xwayland.c | 9 --------- 4 files changed, 44 deletions(-) diff --git a/view.c b/view.c index 5f9169c..70af974 100644 --- a/view.c +++ b/view.c @@ -204,21 +204,6 @@ 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) { diff --git a/view.h b/view.h index b748b03..a0be53d 100644 --- a/view.h +++ b/view.h @@ -45,8 +45,6 @@ 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); }; @@ -75,8 +73,6 @@ 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); diff --git a/xdg_shell.c b/xdg_shell.c index 502d84a..efb9d8b 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -225,20 +225,6 @@ 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) { @@ -315,8 +301,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, }; diff --git a/xwayland.c b/xwayland.c index ebd8e54..ccfca5f 100644 --- a/xwayland.c +++ b/xwayland.c @@ -95,12 +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) { @@ -178,9 +172,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, }; From fb3dc5823795ac4a1001e46626e833a3d3ad5330 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 10 Aug 2021 11:40:54 +0200 Subject: [PATCH 116/233] Replace view_wlr_surface_at with scene-graph --- seat.c | 52 +++++++++++++++++++++------------------------------- view.c | 7 +------ view.h | 2 -- xdg_shell.c | 8 -------- xwayland.c | 7 ------- 5 files changed, 22 insertions(+), 54 deletions(-) diff --git a/seat.c b/seat.c index 0ac976c..3366351 100644 --- a/seat.c +++ b/seat.c @@ -8,6 +8,7 @@ #include "config.h" +#include #include #include #include @@ -42,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; - - wl_list_for_each (view, &server->views, link) { - if (view_at(view, lx, ly, surface, sx, sy)) { - return 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; } - return NULL; + *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 node->data; } static void diff --git a/view.c b/view.c index 70af974..faf4fe7 100644 --- a/view.c +++ b/view.c @@ -231,6 +231,7 @@ view_map(struct cg_view *view, struct wlr_surface *surface) wl_resource_post_no_memory(surface->resource); return; } + view->scene_surface->node.data = view; struct wlr_subsurface *subsurface; wl_list_for_each (subsurface, &view->wlr_surface->current.subsurfaces_below, current.link) { @@ -296,9 +297,3 @@ view_from_wlr_surface(struct cg_server *server, struct wlr_surface *surface) } return NULL; } - -struct wlr_surface * -view_wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y) -{ - return view->impl->wlr_surface_at(view, sx, sy, sub_x, sub_y); -} diff --git a/view.h b/view.h index a0be53d..3c0da5b 100644 --- a/view.h +++ b/view.h @@ -45,7 +45,6 @@ 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); - struct wlr_surface *(*wlr_surface_at)(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y); }; struct cg_view_child { @@ -79,7 +78,6 @@ 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); diff --git a/xdg_shell.c b/xdg_shell.c index efb9d8b..bba2986 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -225,13 +225,6 @@ destroy(struct cg_view *view) free(xdg_shell_view); } -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) { @@ -301,7 +294,6 @@ static const struct cg_view_impl xdg_shell_view_impl = { .activate = activate, .maximize = maximize, .destroy = destroy, - .wlr_surface_at = wlr_surface_at, }; void diff --git a/xwayland.c b/xwayland.c index ccfca5f..47e1a2b 100644 --- a/xwayland.c +++ b/xwayland.c @@ -95,12 +95,6 @@ destroy(struct cg_view *view) free(xwayland_view); } -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) { @@ -172,7 +166,6 @@ static const struct cg_view_impl xwayland_view_impl = { .activate = activate, .maximize = maximize, .destroy = destroy, - .wlr_surface_at = wlr_surface_at, }; void From 128fa90ea10588767808bfab1271a46d22e76d5b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 28 Aug 2021 11:08:11 +0200 Subject: [PATCH 117/233] Use scene-graph helpers for sub-surfaces Delegate sub-surface handling to wlr_scene_surface_tree_create. References: https://github.com/swaywm/wlroots/pull/3128 --- output.c | 4 ++- seat.c | 8 +++--- seat.h | 2 +- view.c | 83 ++++------------------------------------------------- view.h | 12 +------- xdg_shell.c | 2 +- 6 files changed, 16 insertions(+), 95 deletions(-) diff --git a/output.c b/output.c index 402a678..42e3c9b 100644 --- a/output.c +++ b/output.c @@ -164,7 +164,7 @@ scan_out_primary_view(struct cg_output *output) } size_t n_surfaces = 0; - wlr_scene_node_for_each_surface(&view->scene_surface->node, count_surface_iterator, &n_surfaces); + wlr_scene_node_for_each_surface(view->scene_node, count_surface_iterator, &n_surfaces); if (n_surfaces > 1) { return false; } @@ -312,6 +312,8 @@ damage_finish: frame_done: clock_gettime(CLOCK_MONOTONIC, &frame_data.when); send_frame_done(output, &frame_data); + + wlr_output_damage_add_whole(output->damage); } static void diff --git a/seat.c b/seat.c index 3366351..2736a6b 100644 --- a/seat.c +++ b/seat.c @@ -624,7 +624,7 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) drag_icon_damage(drag_icon); - wlr_scene_node_set_position(&drag_icon->scene_surface->node, drag_icon->lx, drag_icon->ly); + wlr_scene_node_set_position(drag_icon->scene_node, drag_icon->lx, drag_icon->ly); } static void @@ -635,7 +635,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) drag_icon_damage(drag_icon); wl_list_remove(&drag_icon->link); wl_list_remove(&drag_icon->destroy.link); - wlr_scene_node_destroy(&drag_icon->scene_surface->node); + wlr_scene_node_destroy(drag_icon->scene_node); free(drag_icon); } @@ -678,8 +678,8 @@ handle_start_drag(struct wl_listener *listener, void *data) } drag_icon->seat = seat; drag_icon->wlr_drag_icon = wlr_drag_icon; - drag_icon->scene_surface = wlr_scene_surface_create(&seat->server->scene->node, wlr_drag_icon->surface); - if (!drag_icon->scene_surface) { + 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; } diff --git a/seat.h b/seat.h index 75f1cc6..5fb2db3 100644 --- a/seat.h +++ b/seat.h @@ -77,7 +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_surface *scene_surface; + struct wlr_scene_node *scene_node; /* The drag icon has a position in layout coordinates. */ double lx, ly; diff --git a/view.c b/view.c index faf4fe7..8e47445 100644 --- a/view.c +++ b/view.c @@ -31,16 +31,6 @@ view_child_handle_commit(struct wl_listener *listener, void *data) 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) { @@ -52,7 +42,6 @@ view_child_finish(struct cg_view_child *child) wl_list_remove(&child->link); wl_list_remove(&child->commit.link); - wl_list_remove(&child->new_subsurface.link); } void @@ -63,57 +52,10 @@ view_child_init(struct cg_view_child *child, struct cg_view *view, struct wlr_su 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) { @@ -175,7 +117,7 @@ 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_surface->node, view->lx, view->ly); + wlr_scene_node_set_position(view->scene_node, view->lx, view->ly); view->impl->maximize(view, layout_box->width, layout_box->height); } @@ -189,7 +131,7 @@ 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_surface->node, view->lx, view->ly); + wlr_scene_node_set_position(view->scene_node, view->lx, view->ly); } void @@ -209,14 +151,12 @@ 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_surface->node); + wlr_scene_node_destroy(view->scene_node); view->wlr_surface = NULL; } @@ -226,23 +166,12 @@ view_map(struct cg_view *view, struct wlr_surface *surface) { view->wlr_surface = surface; - view->scene_surface = wlr_scene_surface_create(&view->server->scene->node, surface); - if (!view->scene_surface) { + 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_surface->node.data = view; - - struct wlr_subsurface *subsurface; - wl_list_for_each (subsurface, &view->wlr_surface->current.subsurfaces_below, current.link) { - subsurface_create(view, subsurface); - } - wl_list_for_each (subsurface, &view->wlr_surface->current.subsurfaces_above, current.link) { - subsurface_create(view, subsurface); - } - - view->new_subsurface.notify = handle_new_subsurface; - wl_signal_add(&view->wlr_surface->events.new_subsurface, &view->new_subsurface); + view->scene_node->data = view; #if CAGE_HAS_XWAYLAND /* We shouldn't position override-redirect windows. They set diff --git a/view.h b/view.h index 3c0da5b..49468c1 100644 --- a/view.h +++ b/view.h @@ -26,15 +26,13 @@ struct cg_view { struct wl_list link; // server::views struct wl_list children; // cg_view_child::link struct wlr_surface *wlr_surface; - struct wlr_scene_surface *scene_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 { @@ -53,18 +51,10 @@ struct cg_view_child { 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); diff --git a/xdg_shell.c b/xdg_shell.c index bba2986..3fb47db 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -61,7 +61,7 @@ static void handle_xdg_popup_map(struct wl_listener *listener, void *data) { struct cg_xdg_popup *popup = wl_container_of(listener, popup, map); - struct wlr_scene_node *parent_node = &popup->view_child.view->scene_surface->node; + struct wlr_scene_node *parent_node = popup->view_child.view->scene_node; popup->scene_surface = wlr_scene_surface_create(parent_node, popup->view_child.wlr_surface); if (!popup->scene_surface) { return; From d46e8a82dd15b809b3d208c22d5dda61116688b0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 17 Aug 2021 17:09:31 +0200 Subject: [PATCH 118/233] Use scene-graph for damage tracking References: https://github.com/swaywm/wlroots/pull/3117 --- cage.c | 12 ------ meson.build | 1 - output.c | 90 +++++-------------------------------------- output.h | 8 +--- render.c | 109 ---------------------------------------------------- seat.c | 14 ------- server.h | 3 -- view.c | 31 --------------- view.h | 4 -- xdg_shell.c | 19 --------- xdg_shell.h | 1 - xwayland.c | 17 -------- xwayland.h | 1 - 13 files changed, 11 insertions(+), 299 deletions(-) delete mode 100644 render.c diff --git a/cage.c b/cage.c index a90639f..ccf3b11 100644 --- a/cage.c +++ b/cage.c @@ -187,9 +187,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" @@ -205,20 +202,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; diff --git a/meson.build b/meson.build index 7c57967..550cd6c 100644 --- a/meson.build +++ b/meson.build @@ -123,7 +123,6 @@ cage_sources = [ 'cage.c', 'idle_inhibit_v1.c', 'output.c', - 'render.c', 'seat.c', 'util.c', 'view.c', diff --git a/output.c b/output.c index 42e3c9b..5ab1ea3 100644 --- a/output.c +++ b/output.c @@ -225,50 +225,9 @@ 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); - } -} - -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); -} - -static void -handle_output_damage_frame(struct wl_listener *listener, void *data) -{ - struct cg_output *output = wl_container_of(listener, output, damage_frame); + struct cg_output *output = wl_container_of(listener, output, frame); struct send_frame_done_data frame_data = {0}; if (!output->wlr_output->enabled) { @@ -287,33 +246,12 @@ handle_output_damage_frame(struct wl_listener *listener, void *data) } last_scanned_out = scanned_out; - if (scanned_out) { - goto frame_done; + if (!scanned_out) { + wlr_scene_output_commit(output->scene_output); } - 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); - - wlr_output_damage_add_whole(output->damage); } static void @@ -357,8 +295,7 @@ output_destroy(struct cg_output *output) 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); @@ -380,18 +317,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); } @@ -414,7 +343,8 @@ handle_new_output(struct wl_listener *listener, void *data) output->wlr_output = wlr_output; output->server = server; - output->damage = wlr_output_damage_create(wlr_output); + output->scene_output = wlr_scene_output_create(server->scene, wlr_output); + wl_list_insert(&server->outputs, &output->link); output->commit.notify = handle_output_commit; @@ -423,10 +353,8 @@ 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); + output->frame.notify = handle_output_frame; + wl_signal_add(&wlr_output->events.frame, &output->frame); struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); if (preferred_mode) { diff --git a/output.h b/output.h index 8c5799f..41a4a55 100644 --- a/output.h +++ b/output.h @@ -11,13 +11,12 @@ 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 }; @@ -26,9 +25,6 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_ 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_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 9eb4d30..0000000 --- a/render.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Cage: A Wayland kiosk. - * - * Copyright (C) 2018-2020 Jente Hidskes - * Copyright (C) 2019 The Sway authors - * - * See the LICENSE file accompanying this file. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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_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(output->renderer, &box); -} - -struct render_data { - pixman_region32_t *damage; -}; - -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; - - wlr_renderer_begin(server->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(server->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(server->renderer, color); - } - - double lx = 0, ly = 0; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &lx, &ly); - wlr_scene_render_output(server->scene, wlr_output, lx, ly, damage); - -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(server->renderer, NULL); - wlr_renderer_end(server->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/seat.c b/seat.c index 2736a6b..2bf1614 100644 --- a/seat.c +++ b/seat.c @@ -587,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) { @@ -603,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; @@ -622,8 +611,6 @@ 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); } @@ -632,7 +619,6 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) { struct cg_drag_icon *drag_icon = wl_container_of(listener, drag_icon, destroy); - drag_icon_damage(drag_icon); wl_list_remove(&drag_icon->link); wl_list_remove(&drag_icon->destroy.link); wlr_scene_node_destroy(drag_icon->scene_node); diff --git a/server.h b/server.h index 0712708..bb7f3c1 100644 --- a/server.h +++ b/server.h @@ -51,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/view.c b/view.c index 8e47445..26c3b7b 100644 --- a/view.c +++ b/view.c @@ -24,13 +24,6 @@ #include "xwayland.h" #endif -static void -view_child_handle_commit(struct wl_listener *listener, void *data) -{ - struct cg_view_child *child = wl_container_of(listener, child, commit); - view_damage_part(child->view); -} - void view_child_finish(struct cg_view_child *child) { @@ -38,10 +31,7 @@ view_child_finish(struct cg_view_child *child) return; } - view_damage_whole(child->view); - wl_list_remove(&child->link); - wl_list_remove(&child->commit.link); } void @@ -50,9 +40,6 @@ view_child_init(struct cg_view_child *child, struct cg_view *view, struct wlr_su child->view = view; child->wlr_surface = wlr_surface; - child->commit.notify = view_child_handle_commit; - wl_signal_add(&wlr_surface->events.commit, &child->commit); - wl_list_insert(&view->children, &child->link); } @@ -78,24 +65,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) { diff --git a/view.h b/view.h index 49468c1..67f2280 100644 --- a/view.h +++ b/view.h @@ -50,16 +50,12 @@ struct cg_view_child { struct wlr_surface *wlr_surface; struct wl_list link; - struct wl_listener commit; - void (*destroy)(struct cg_view_child *child); }; 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_unmap(struct cg_view *view); diff --git a/xdg_shell.c b/xdg_shell.c index 3fb47db..271b05e 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -69,7 +69,6 @@ handle_xdg_popup_map(struct wl_listener *listener, void *data) double sx, sy; wlr_xdg_popup_get_position(popup->wlr_popup, &sx, &sy); wlr_scene_node_set_position(&popup->scene_surface->node, sx, sy); - view_damage_whole(popup->view_child.view); } static void @@ -77,7 +76,6 @@ handle_xdg_popup_unmap(struct wl_listener *listener, void *data) { struct cg_xdg_popup *popup = wl_container_of(listener, popup, unmap); wlr_scene_node_destroy(&popup->scene_surface->node); - view_damage_whole(popup->view_child.view); } static void @@ -235,24 +233,12 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * 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); -} - static void 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); } @@ -262,12 +248,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 diff --git a/xdg_shell.h b/xdg_shell.h index 5ee0bba..a5539b9 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -14,7 +14,6 @@ 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; }; diff --git a/xwayland.c b/xwayland.c index 47e1a2b..ef37a49 100644 --- a/xwayland.c +++ b/xwayland.c @@ -103,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); } @@ -135,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 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; }; From 0736d72e88eefb2199f1030f0925bac64fe6f36d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Sep 2021 12:18:23 +0200 Subject: [PATCH 119/233] Use wlr_scene_attach_output_layout This provides wlr_output_layout integration. References: https://github.com/swaywm/wlroots/pull/3160 --- cage.c | 2 ++ output.c | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cage.c b/cage.c index ccf3b11..1717bcb 100644 --- a/cage.c +++ b/cage.c @@ -338,6 +338,8 @@ main(int argc, char *argv[]) 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"); diff --git a/output.c b/output.c index 5ab1ea3..1c39dd7 100644 --- a/output.c +++ b/output.c @@ -11,6 +11,7 @@ #include "config.h" +#include #include #include #include @@ -206,6 +207,15 @@ 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); + + struct wlr_scene_output *scene_output; + wl_list_for_each (scene_output, &output->server->scene->outputs, link) { + if (scene_output->output == wlr_output) { + output->scene_output = scene_output; + break; + } + } + assert(output->scene_output != NULL); } static void @@ -218,6 +228,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); @@ -343,7 +355,6 @@ handle_new_output(struct wl_listener *listener, void *data) output->wlr_output = wlr_output; output->server = server; - output->scene_output = wlr_scene_output_create(server->scene, wlr_output); wl_list_insert(&server->outputs, &output->link); From 48b31afb5a971baecccbc7447d8b81cfb0d5fab4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Sep 2021 12:09:34 +0200 Subject: [PATCH 120/233] Drop unused output_surface_for_each_surface --- output.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/output.c b/output.c index 1c39dd7..edc412b 100644 --- a/output.c +++ b/output.c @@ -92,21 +92,6 @@ output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, vo 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_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data) { From e6f89ed6f1543d8c835c7ff15376f52cfec15dfa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Sep 2021 12:41:45 +0200 Subject: [PATCH 121/233] Remove output_for_each_surface It's used only by send_frame_done. Instead of keeping a generic iterator, let's inline it in the only user. --- output.c | 64 +++++++++++++++++--------------------------------------- output.h | 3 --- 2 files changed, 19 insertions(+), 48 deletions(-) diff --git a/output.c b/output.c index edc412b..db71d75 100644 --- a/output.c +++ b/output.c @@ -43,18 +43,6 @@ #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) { @@ -68,10 +56,16 @@ intersects_with_output(struct cg_output *output, struct wlr_output_layout *outpu return wlr_box_intersection(&intersection, &output_box, surface_box); } +struct send_frame_done_data { + struct cg_output *output; + double ox, oy; /* Output-local coordinates. */ + struct timespec when; +}; + static void -output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, void *user_data) +send_frame_done_iterator(struct wlr_surface *surface, int sx, int sy, void *user_data) { - struct surface_iterator_data *data = user_data; + const struct send_frame_done_data *data = user_data; struct cg_output *output = data->output; if (!wlr_surface_has_buffer(surface)) { @@ -89,39 +83,19 @@ output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, vo return; } - data->user_iterator(data->output, surface, &surface_box, data->user_data); -} - -static void -output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data) -{ - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .ox = 0, - .oy = 0, - }; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - - wlr_scene_node_for_each_surface(&output->server->scene->node, output_for_each_surface_iterator, &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) +send_frame_done(struct cg_output *output, const struct timespec *when) { - output_for_each_surface(output, send_frame_done_iterator, data); + struct send_frame_done_data data = { + .output = output, + .when = *when, + }; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); + + wlr_scene_node_for_each_surface(&output->server->scene->node, send_frame_done_iterator, &data); } static void @@ -225,7 +199,6 @@ static void handle_output_frame(struct wl_listener *listener, void *data) { struct cg_output *output = wl_container_of(listener, output, frame); - struct send_frame_done_data frame_data = {0}; if (!output->wlr_output->enabled) { return; @@ -247,8 +220,9 @@ handle_output_frame(struct wl_listener *listener, void *data) wlr_scene_output_commit(output->scene_output); } - clock_gettime(CLOCK_MONOTONIC, &frame_data.when); - send_frame_done(output, &frame_data); + struct timespec now = {0}; + clock_gettime(CLOCK_MONOTONIC, &now); + send_frame_done(output, &now); } static void diff --git a/output.h b/output.h index 41a4a55..ced06f6 100644 --- a/output.h +++ b/output.h @@ -21,9 +21,6 @@ struct cg_output { 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_set_window_title(struct cg_output *output, const char *title); From 5a1933f6606c496f68cd4d9477552cadb629b9af Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 20 Oct 2021 16:11:46 +0200 Subject: [PATCH 122/233] Delegate direct scan-out to wlr_scene Depends on [1]. [1]: https://github.com/swaywm/wlroots/pull/3279 --- output.c | 71 +------------------------------------------------------- 1 file changed, 1 insertion(+), 70 deletions(-) diff --git a/output.c b/output.c index db71d75..12968b0 100644 --- a/output.c +++ b/output.c @@ -98,61 +98,6 @@ send_frame_done(struct cg_output *output, const struct timespec *when) wlr_scene_node_for_each_surface(&output->server->scene->node, send_frame_done_iterator, &data); } -static void -count_surface_iterator(struct wlr_surface *surface, int sx, int sy, 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; - wlr_scene_node_for_each_surface(view->scene_node, 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) { @@ -204,21 +149,7 @@ handle_output_frame(struct wl_listener *listener, void *data) 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) { - wlr_scene_output_commit(output->scene_output); - } + wlr_scene_output_commit(output->scene_output); struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC, &now); From af610192f48e5c3f8e7a254a0acede7bffa79985 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 26 Oct 2021 21:55:11 +0200 Subject: [PATCH 123/233] Use wlr_scene_output_for_each_surface --- output.c | 51 ++++----------------------------------------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/output.c b/output.c index 12968b0..81539af 100644 --- a/output.c +++ b/output.c @@ -43,59 +43,16 @@ #include "xwayland.h" #endif -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); -} - -struct send_frame_done_data { - struct cg_output *output; - double ox, oy; /* Output-local coordinates. */ - struct timespec when; -}; - static void -send_frame_done_iterator(struct wlr_surface *surface, int sx, int sy, void *user_data) +send_frame_done_iterator(struct wlr_surface *surface, int lx, int ly, void *user_data) { - const struct send_frame_done_data *data = user_data; - struct cg_output *output = data->output; + const struct timespec *t = user_data; 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; - } - - wlr_surface_send_frame_done(surface, &data->when); -} - -static void -send_frame_done(struct cg_output *output, const struct timespec *when) -{ - struct send_frame_done_data data = { - .output = output, - .when = *when, - }; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); - - wlr_scene_node_for_each_surface(&output->server->scene->node, send_frame_done_iterator, &data); + wlr_surface_send_frame_done(surface, t); } static void @@ -153,7 +110,7 @@ handle_output_frame(struct wl_listener *listener, void *data) struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC, &now); - send_frame_done(output, &now); + wlr_scene_output_for_each_surface(output->scene_output, send_frame_done_iterator, &now); } static void From 79950cd691e7755c081fccb537b773a0b3c9b717 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 27 Oct 2021 16:19:06 +0200 Subject: [PATCH 124/233] Use wlr_scene_xdg_surface_create for popups See https://github.com/swaywm/wlroots/pull/3298 --- xdg_shell.c | 187 ++++++++++++++++++++++------------------------------ xdg_shell.h | 12 ---- 2 files changed, 78 insertions(+), 121 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index 271b05e..a51ed70 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -6,6 +6,7 @@ * See the LICENSE file accompanying this file. */ +#include #include #include #include @@ -41,67 +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) +static struct cg_view * +popup_get_view(struct wlr_xdg_popup *popup) { - if (!child) { - return; + while (true) { + if (popup->parent == NULL || !wlr_surface_is_xdg_surface(popup->parent)) { + return NULL; + } + + 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; + } } - - 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) +popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) { - struct cg_xdg_popup *popup = wl_container_of(listener, popup, map); - struct wlr_scene_node *parent_node = popup->view_child.view->scene_node; - popup->scene_surface = wlr_scene_surface_create(parent_node, popup->view_child.wlr_surface); - if (!popup->scene_surface) { - return; - } - double sx, sy; - wlr_xdg_popup_get_position(popup->wlr_popup, &sx, &sy); - wlr_scene_node_set_position(&popup->scene_surface->node, sx, sy); -} - -static void -handle_xdg_popup_unmap(struct wl_listener *listener, void *data) -{ - struct cg_xdg_popup *popup = wl_container_of(listener, popup, unmap); - wlr_scene_node_destroy(&popup->scene_surface->node); -} - -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); - -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); -} - -static void -popup_unconstrain(struct cg_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 = @@ -115,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 * @@ -261,7 +196,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); @@ -283,29 +217,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; + } + + 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; + } + + 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 } - - 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_shell_view->new_popup.notify = handle_new_xdg_popup; - wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_view->new_popup); } void diff --git a/xdg_shell.h b/xdg_shell.h index a5539b9..9a101c6 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -15,18 +15,6 @@ struct cg_xdg_shell_view { struct wl_listener unmap; struct wl_listener map; 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 wlr_scene_surface *scene_surface; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener new_popup; }; struct cg_xdg_decoration { From 7a7325c0ee26729affe1e15c1759996152cc941f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 27 Oct 2021 16:20:29 +0200 Subject: [PATCH 125/233] Drop cg_view_child This is now unused. --- view.c | 26 -------------------------- view.h | 12 ------------ 2 files changed, 38 deletions(-) diff --git a/view.c b/view.c index 26c3b7b..745f4e5 100644 --- a/view.c +++ b/view.c @@ -24,25 +24,6 @@ #include "xwayland.h" #endif -void -view_child_finish(struct cg_view_child *child) -{ - if (!child) { - return; - } - - wl_list_remove(&child->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; - - wl_list_insert(&view->children, &child->link); -} - char * view_get_title(struct cg_view *view) { @@ -120,11 +101,6 @@ view_unmap(struct cg_view *view) { wl_list_remove(&view->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 = NULL; @@ -180,8 +156,6 @@ 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 * diff --git a/view.h b/view.h index 67f2280..10a4e4a 100644 --- a/view.h +++ b/view.h @@ -24,7 +24,6 @@ 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; @@ -45,14 +44,6 @@ struct cg_view_impl { void (*destroy)(struct cg_view *view); }; -struct cg_view_child { - struct cg_view *view; - struct wlr_surface *wlr_surface; - struct wl_list link; - - void (*destroy)(struct cg_view_child *child); -}; - 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); @@ -65,7 +56,4 @@ void view_init(struct cg_view *view, struct cg_server *server, enum cg_view_type struct cg_view *view_from_wlr_surface(struct cg_server *server, struct wlr_surface *surface); -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); - #endif From 77a3f6bb0c0249561b6b192e54494ba081e85ff5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Dec 2021 16:26:13 +0100 Subject: [PATCH 126/233] Use wlr_scene_output_send_frame_done --- output.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/output.c b/output.c index 81539af..989e5b9 100644 --- a/output.c +++ b/output.c @@ -43,18 +43,6 @@ #include "xwayland.h" #endif -static void -send_frame_done_iterator(struct wlr_surface *surface, int lx, int ly, void *user_data) -{ - const struct timespec *t = user_data; - - if (!wlr_surface_has_buffer(surface)) { - return; - } - - wlr_surface_send_frame_done(surface, t); -} - static void output_enable(struct cg_output *output) { @@ -110,7 +98,7 @@ handle_output_frame(struct wl_listener *listener, void *data) struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_for_each_surface(output->scene_output, send_frame_done_iterator, &now); + wlr_scene_output_send_frame_done(output->scene_output, &now); } static void From 36309d0c07dc0ff2e48248d4a6cfdfb2b74de2b1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 17 Dec 2021 12:02:42 +0100 Subject: [PATCH 127/233] Enable viewporter We get this for free with wlr_scene. --- cage.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cage.c b/cage.c index 1717bcb..3b783ac 100644 --- a/cage.c +++ b/cage.c @@ -31,6 +31,7 @@ #include #include #include +#include #if CAGE_HAS_XWAYLAND #include #endif @@ -259,6 +260,7 @@ 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_xdg_shell *xdg_shell = NULL; #if CAGE_HAS_XWAYLAND struct wlr_xwayland *xwayland = NULL; @@ -412,6 +414,13 @@ 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; + } + 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"); From 7fe306a79ae2f686f62ed8e5e452686170054dfe Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 17 Dec 2021 12:06:01 +0100 Subject: [PATCH 128/233] Enable presentation-time We get this for free with wlr_scene. --- cage.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cage.c b/cage.c index 3b783ac..95f0cc7 100644 --- a/cage.c +++ b/cage.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -261,6 +262,7 @@ main(int argc, char *argv[]) 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; @@ -421,6 +423,14 @@ main(int argc, char *argv[]) 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"); From dfba2d8f9d4b70df081c8bb38bb4f82cf7085753 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 17 Dec 2021 22:05:19 +0100 Subject: [PATCH 129/233] Remove no longer needed dependencies --- meson.build | 5 ----- output.c | 1 - render.h | 8 -------- 3 files changed, 14 deletions(-) delete mode 100644 render.h diff --git a/meson.build b/meson.build index 550cd6c..10c99fb 100644 --- a/meson.build +++ b/meson.build @@ -38,9 +38,7 @@ endif 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') wayland_scanner = find_program('wayland-scanner') @@ -135,7 +133,6 @@ cage_headers = [ configuration: conf_data), 'idle_inhibit_v1.h', 'output.h', - 'render.h', 'seat.h', 'server.h', 'util.h', @@ -156,8 +153,6 @@ executable( wayland_server, wlroots, xkbcommon, - pixman, - math, ], install: true, ) diff --git a/output.c b/output.c index 989e5b9..13eb5eb 100644 --- a/output.c +++ b/output.c @@ -34,7 +34,6 @@ #include #include "output.h" -#include "render.h" #include "seat.h" #include "server.h" #include "util.h" 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 From de03250ca00426d27c5361666e949b532354b7e3 Mon Sep 17 00:00:00 2001 From: lunacb Date: Mon, 20 Dec 2021 23:03:31 -0500 Subject: [PATCH 130/233] fixed typo --- seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seat.c b/seat.c index 2bf1614..f155506 100644 --- a/seat.c +++ b/seat.c @@ -342,7 +342,7 @@ 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; } From 0e87c2c8d8ece2ce93507017c660158ee2fb0b0a Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Wed, 22 Dec 2021 07:53:40 +0200 Subject: [PATCH 131/233] restore direct libm dependency (fixes #222) --- meson.build | 2 ++ util.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/meson.build b/meson.build index 10c99fb..bac2695 100644 --- a/meson.build +++ b/meson.build @@ -39,6 +39,7 @@ wlroots = dependency('wlroots', version: '>= 0.15.0', fallback: ['wlroots wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') xkbcommon = dependency('xkbcommon') +math = dependency('m') wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') wayland_scanner = find_program('wayland-scanner') @@ -153,6 +154,7 @@ executable( wayland_server, wlroots, xkbcommon, + math, ], install: true, ) diff --git a/util.c b/util.c index 714c7e3..22b5176 100644 --- a/util.c +++ b/util.c @@ -6,6 +6,8 @@ * See the LICENSE file accompanying this file. */ +#include + #include "util.h" int From f44ba0cea2746334525544e09fae95960427383e Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Wed, 22 Dec 2021 08:14:39 +0200 Subject: [PATCH 132/233] use find_library() for libm --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index bac2695..781d4de 100644 --- a/meson.build +++ b/meson.build @@ -39,7 +39,7 @@ wlroots = dependency('wlroots', version: '>= 0.15.0', fallback: ['wlroots wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') xkbcommon = dependency('xkbcommon') -math = dependency('m') +math = cc.find_library('m') wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') wayland_scanner = find_program('wayland-scanner') From 3321daef98e07b1ea16f12875cc75f470f1f6325 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Wed, 22 Dec 2021 08:25:43 +0200 Subject: [PATCH 133/233] fall back to a lower output mode if needed (swaywm/sway@4cdc4ac) --- output.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/output.c b/output.c index 13eb5eb..0577c0d 100644 --- a/output.c +++ b/output.c @@ -201,10 +201,26 @@ handle_new_output(struct wl_listener *listener, void *data) output->frame.notify = handle_output_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); - struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); - if (preferred_mode) { - wlr_output_set_mode(wlr_output, preferred_mode); + 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) { From 1ccbacf198a031f38b370d799c78800d7e2bb323 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 24 Feb 2020 20:07:36 +0100 Subject: [PATCH 134/233] output: set pointer to cg_output in wlr_output->data This will be used later in the layer shell implementation. --- output.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/output.c b/output.c index 0577c0d..30d4bcf 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. @@ -138,6 +138,8 @@ 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); @@ -188,6 +190,7 @@ handle_new_output(struct wl_listener *listener, void *data) } output->wlr_output = wlr_output; + wlr_output->data = output; output->server = server; wl_list_insert(&server->outputs, &output->link); From ba9c2453930f0c6eee2c5e5db8a4b81a4583da9a Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 24 Dec 2021 08:58:19 +0100 Subject: [PATCH 135/233] view: implement view_from_wlr_surface in terms of wlr_surface->data pointer --- seat.c | 2 +- view.c | 20 ++++++++++---------- view.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/seat.c b/seat.c index f155506..b0d6ea1 100644 --- a/seat.c +++ b/seat.c @@ -817,7 +817,7 @@ 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); + return view_from_wlr_surface(prev_surface); } void diff --git a/view.c b/view.c index 745f4e5..8c064a9 100644 --- a/view.c +++ b/view.c @@ -1,7 +1,7 @@ /* * Cage: A Wayland kiosk. * - * Copyright (C) 2018-2020 Jente Hidskes + * Copyright (C) 2018-2021 Jente Hidskes * * See the LICENSE file accompanying this file. */ @@ -103,14 +103,13 @@ view_unmap(struct cg_view *view) 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; - view->scene_node = wlr_scene_subsurface_tree_create(&view->server->scene->node, surface); if (!view->scene_node) { wl_resource_post_no_memory(surface->resource); @@ -118,6 +117,9 @@ view_map(struct cg_view *view, struct wlr_surface *surface) } view->scene_node->data = view; + view->wlr_surface = surface; + surface->data = view; + #if CAGE_HAS_XWAYLAND /* We shouldn't position override-redirect windows. They set their own (x,y) coordinates in handle_wayland_surface_map. */ @@ -159,13 +161,11 @@ view_init(struct cg_view *view, struct cg_server *server, enum cg_view_type type } struct cg_view * -view_from_wlr_surface(struct cg_server *server, struct wlr_surface *surface) +view_from_wlr_surface(struct wlr_surface *surface) { - struct cg_view *view; - wl_list_for_each (view, &server->views, link) { - if (view->wlr_surface == surface) { - return view; - } + if (!surface) { + return NULL; } - return NULL; + + return surface->data; } diff --git a/view.h b/view.h index 10a4e4a..677a949 100644 --- a/view.h +++ b/view.h @@ -54,6 +54,6 @@ 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 cg_view *view_from_wlr_surface(struct wlr_surface *surface); #endif From d708a73aca167bff2f19c7e067a968dd7989f1ca Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Dec 2021 15:36:39 +0100 Subject: [PATCH 136/233] view: require non-NULL surface in view_from_wlr_surface --- seat.c | 3 +++ view.c | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/seat.c b/seat.c index b0d6ea1..4dce511 100644 --- a/seat.c +++ b/seat.c @@ -817,6 +817,9 @@ struct cg_view * seat_get_focus(struct cg_seat *seat) { struct wlr_surface *prev_surface = seat->seat->keyboard_state.focused_surface; + if (!prev_surface) { + return NULL; + } return view_from_wlr_surface(prev_surface); } diff --git a/view.c b/view.c index 8c064a9..6551142 100644 --- a/view.c +++ b/view.c @@ -8,6 +8,7 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -163,9 +164,6 @@ view_init(struct cg_view *view, struct cg_server *server, enum cg_view_type type struct cg_view * view_from_wlr_surface(struct wlr_surface *surface) { - if (!surface) { - return NULL; - } - + assert(surface); return surface->data; } From ee5410d3fb9bbb67fa16afe0c39e017a1a3827f2 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Mon, 27 Dec 2021 12:42:30 +0100 Subject: [PATCH 137/233] util: remove unneeded module --- meson.build | 2 -- output.c | 1 - util.c | 36 ------------------------------------ util.h | 11 ----------- 4 files changed, 50 deletions(-) delete mode 100644 util.c delete mode 100644 util.h diff --git a/meson.build b/meson.build index 781d4de..7d36c66 100644 --- a/meson.build +++ b/meson.build @@ -123,7 +123,6 @@ cage_sources = [ 'idle_inhibit_v1.c', 'output.c', 'seat.c', - 'util.c', 'view.c', 'xdg_shell.c', ] @@ -136,7 +135,6 @@ cage_headers = [ 'output.h', 'seat.h', 'server.h', - 'util.h', 'view.h', 'xdg_shell.h', ] diff --git a/output.c b/output.c index 30d4bcf..11d0a56 100644 --- a/output.c +++ b/output.c @@ -36,7 +36,6 @@ #include "output.h" #include "seat.h" #include "server.h" -#include "util.h" #include "view.h" #if CAGE_HAS_XWAYLAND #include "xwayland.h" diff --git a/util.c b/util.c deleted file mode 100644 index 22b5176..0000000 --- a/util.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Cage: A Wayland kiosk. - * - * Copyright (C) 2019 The Sway authors - * - * See the LICENSE file accompanying this file. - */ - -#include - -#include "util.h" - -int -scale_length(int length, int offset, float scale) -{ - /** - * One does not simply multiply the width by the scale. We allow fractional - * scaling, which means the resulting scaled width might be a decimal. - * So we round it. - * - * But even this can produce undesirable results depending on the X or Y - * offset of the box. For example, with a scale of 1.5, a box with - * width=1 should not scale to 2px if its X coordinate is 1, because the - * X coordinate would have scaled to 2px. - */ - return round((offset + length) * scale) - round(offset * scale); -} - -void -scale_box(struct wlr_box *box, float scale) -{ - box->width = scale_length(box->width, box->x, scale); - box->height = scale_length(box->height, box->y, scale); - box->x = round(box->x * scale); - box->y = round(box->y * scale); -} diff --git a/util.h b/util.h deleted file mode 100644 index b6281f3..0000000 --- a/util.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CG_UTIL_H -#define CG_UTIL_H - -#include - -/** Apply scale to a width or height. */ -int scale_length(int length, int offset, float scale); - -void scale_box(struct wlr_box *box, float scale); - -#endif From 38f8566155309f327a5e7ff2037d782d938ac067 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Dec 2021 16:39:46 +0100 Subject: [PATCH 138/233] xdg_shell: check role in is_primary --- xdg_shell.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index a51ed70..0a8eda3 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -112,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 From f71844ab54dbb3192d8c2f0a1db84d50e18536d9 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 26 Dec 2021 16:40:03 +0100 Subject: [PATCH 139/233] xdg_shell: add note why we're setting the size for fullscreen clients --- xdg_shell.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xdg_shell.c b/xdg_shell.c index 0a8eda3..ede71f4 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -166,8 +166,14 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * { 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; + + /** + * 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); } From 46778e6d6c2c327943c16b00e2d600933beec999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= Date: Mon, 21 Mar 2022 23:52:27 -0600 Subject: [PATCH 140/233] output: get scene_output by wlroots function --- output.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/output.c b/output.c index 11d0a56..c33bbe1 100644 --- a/output.c +++ b/output.c @@ -55,13 +55,7 @@ output_enable(struct cg_output *output) wlr_output_enable(wlr_output, true); wlr_output_commit(wlr_output); - struct wlr_scene_output *scene_output; - wl_list_for_each (scene_output, &output->server->scene->outputs, link) { - if (scene_output->output == wlr_output) { - output->scene_output = scene_output; - break; - } - } + output->scene_output = wlr_scene_get_scene_output(output->server->scene, wlr_output); assert(output->scene_output != NULL); } From 1b9d750dc2a21cb5270b5892fb8876f82eaa157b Mon Sep 17 00:00:00 2001 From: "Ethan D. Twardy" Date: Wed, 20 Jul 2022 06:40:10 -0500 Subject: [PATCH 141/233] Fix warnings in `meson build' output for deprecated functions. Previously, the output of `meson build` would warn about the use of some functions that have been deprecated since meson v0.56.0, and the use of the `check` kwarg in the `run_command()` function. Update meson.build to fix these build warnings. --- meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 7d36c66..8ff9287 100644 --- a/meson.build +++ b/meson.build @@ -41,7 +41,7 @@ wayland_server = dependency('wayland-server') 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, @@ -77,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: true) + git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: true) if git_commit.returncode() == 0 and git_branch.returncode() == 0 version = '@0@-@1@ (branch \'@2@\')'.format( meson.project_version(), @@ -94,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 = [ @@ -110,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) From a81ab701d73d0f43c9bb9747e5fdf3c5e226139c Mon Sep 17 00:00:00 2001 From: "Ethan D. Twardy" Date: Wed, 20 Jul 2022 06:57:34 -0500 Subject: [PATCH 142/233] Update meson.build not to fail if git rev-parse fails --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 8ff9287..5a8b28c 100644 --- a/meson.build +++ b/meson.build @@ -77,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'], check: true) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: true) + 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(), From d3d4a129e73b4746ed5f0fab00ae986f7a491c87 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 13 Sep 2021 13:30:59 +0000 Subject: [PATCH 143/233] cage: allow running as root when not using setuid bit --- cage.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cage.c b/cage.c index 95f0cc7..807aefe 100644 --- a/cage.c +++ b/cage.c @@ -149,7 +149,12 @@ cleanup_primary_client(pid_t pid) static bool drop_permissions(void) { + if (getuid() == 0 || getgid() == 0) { + wlr_log(WLR_INFO, "Running as root user, this is dangerous"); + return true; + } if (getuid() != geteuid() || getgid() != getegid()) { + wlr_log(WLR_INFO, "setuid/setgid bit detected, dropping permissions"); // Set the gid and uid in the correct order. if (setgid(getgid()) != 0 || setuid(getuid()) != 0) { wlr_log(WLR_ERROR, "Unable to drop root, refusing to start"); From a57e0067c143c3cf7fa1591b75c67243e43cfc1a Mon Sep 17 00:00:00 2001 From: Phil Jones Date: Thu, 20 Jan 2022 11:13:10 +0000 Subject: [PATCH 144/233] Explicitly create wlr_subcompositor. Following wlroots b6f43ab2, the subcompositor must now be created explicitly, rather than being handled by wlr_compositor_create. --- cage.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cage.c b/cage.c index 807aefe..896334b 100644 --- a/cage.c +++ b/cage.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #if CAGE_HAS_XWAYLAND #include @@ -259,6 +260,7 @@ main(int argc, char *argv[]) struct wl_event_source *sigterm_source = NULL; struct wl_event_source *sigchld_source = NULL; struct wlr_compositor *compositor = NULL; + struct wlr_subcompositor *subcompositor = NULL; struct wlr_data_device_manager *data_device_manager = NULL; struct wlr_server_decoration_manager *server_decoration_manager = NULL; struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; @@ -356,6 +358,13 @@ main(int argc, char *argv[]) goto end; } + subcompositor = wlr_subcompositor_create(server.wl_display); + if (!subcompositor) { + wlr_log(WLR_ERROR, "Unable to create the wlroots subcompositor"); + ret = 1; + goto end; + } + data_device_manager = wlr_data_device_manager_create(server.wl_display); if (!data_device_manager) { wlr_log(WLR_ERROR, "Unable to create the data device manager"); From 47f5daba20e25985103ed3cabc1cc9b397d6018a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 12 Oct 2022 03:37:05 -0400 Subject: [PATCH 145/233] seat: Port 0.16 device changes --- seat.c | 108 ++++++++++++++++++++++++++++----------------------------- seat.h | 4 +-- 2 files changed, 55 insertions(+), 57 deletions(-) diff --git a/seat.c b/seat.c index 4dce511..9aa2d6e 100644 --- a/seat.c +++ b/seat.c @@ -118,16 +118,16 @@ update_capabilities(struct cg_seat *seat) } static void -map_input_device_to_output(struct cg_seat *seat, struct wlr_input_device *device) +map_input_device_to_output(struct cg_seat *seat, struct wlr_input_device *device, const char *output_name) { - if (!device->output_name) { + if (!output_name) { wlr_log(WLR_INFO, "Input device %s cannot be mapped to an output device\n", device->name); return; } struct cg_output *output; wl_list_for_each (output, &seat->server->outputs, link) { - if (strcmp(device->output_name, output->wlr_output->name) == 0) { + if (strcmp(output_name, output->wlr_output->name) == 0) { wlr_log(WLR_INFO, "Mapping input device %s to output device %s\n", device->name, output->wlr_output->name); wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); @@ -145,7 +145,7 @@ handle_touch_destroy(struct wl_listener *listener, void *data) struct cg_seat *seat = touch->seat; wl_list_remove(&touch->link); - wlr_cursor_detach_input_device(seat->cursor, touch->device); + wlr_cursor_detach_input_device(seat->cursor, &touch->touch->base); wl_list_remove(&touch->destroy.link); free(touch); @@ -153,7 +153,7 @@ handle_touch_destroy(struct wl_listener *listener, void *data) } static void -handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) +handle_new_touch(struct cg_seat *seat, struct wlr_touch *wlr_touch) { struct cg_touch *touch = calloc(1, sizeof(struct cg_touch)); if (!touch) { @@ -162,14 +162,14 @@ handle_new_touch(struct cg_seat *seat, struct wlr_input_device *device) } touch->seat = seat; - touch->device = device; - wlr_cursor_attach_input_device(seat->cursor, device); + touch->touch = wlr_touch; + wlr_cursor_attach_input_device(seat->cursor, &wlr_touch->base); wl_list_insert(&seat->touch, &touch->link); touch->destroy.notify = handle_touch_destroy; - wl_signal_add(&touch->device->events.destroy, &touch->destroy); + wl_signal_add(&wlr_touch->base.events.destroy, &touch->destroy); - map_input_device_to_output(seat, device); + map_input_device_to_output(seat, &wlr_touch->base, wlr_touch->output_name); } static void @@ -179,7 +179,7 @@ handle_pointer_destroy(struct wl_listener *listener, void *data) struct cg_seat *seat = pointer->seat; wl_list_remove(&pointer->link); - wlr_cursor_detach_input_device(seat->cursor, pointer->device); + wlr_cursor_detach_input_device(seat->cursor, &pointer->pointer->base); wl_list_remove(&pointer->destroy.link); free(pointer); @@ -187,7 +187,7 @@ handle_pointer_destroy(struct wl_listener *listener, void *data) } static void -handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) +handle_new_pointer(struct cg_seat *seat, struct wlr_pointer *wlr_pointer) { struct cg_pointer *pointer = calloc(1, sizeof(struct cg_pointer)); if (!pointer) { @@ -196,21 +196,21 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_input_device *device) } pointer->seat = seat; - pointer->device = device; - wlr_cursor_attach_input_device(seat->cursor, device); + pointer->pointer = wlr_pointer; + wlr_cursor_attach_input_device(seat->cursor, &wlr_pointer->base); wl_list_insert(&seat->pointers, &pointer->link); pointer->destroy.notify = handle_pointer_destroy; - wl_signal_add(&device->events.destroy, &pointer->destroy); + wl_signal_add(&wlr_pointer->base.events.destroy, &pointer->destroy); - map_input_device_to_output(seat, device); + map_input_device_to_output(seat, &wlr_pointer->base, wlr_pointer->output_name); } static void -handle_modifier_event(struct wlr_input_device *device, struct cg_seat *seat) +handle_modifier_event(struct wlr_keyboard *keyboard, struct cg_seat *seat) { - wlr_seat_set_keyboard(seat->seat, device); - wlr_seat_keyboard_notify_modifiers(seat->seat, &device->keyboard->modifiers); + wlr_seat_set_keyboard(seat->seat, keyboard); + wlr_seat_keyboard_notify_modifiers(seat->seat, &keyboard->modifiers); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -240,18 +240,18 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) } static void -handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *data) +handle_key_event(struct wlr_keyboard *keyboard, struct cg_seat *seat, void *data) { - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; /* Translate from libinput keycode to an xkbcommon keycode. */ xkb_keycode_t keycode = event->keycode + 8; const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(device->keyboard->xkb_state, keycode, &syms); + int nsyms = xkb_state_key_get_syms(keyboard->xkb_state, keycode, &syms); bool handled = false; - uint32_t modifiers = wlr_keyboard_get_modifiers(device->keyboard); + uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard); if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { /* If Alt is held down and this button was pressed, we * attempt to process it as a compositor @@ -263,7 +263,7 @@ handle_key_event(struct wlr_input_device *device, struct cg_seat *seat, void *da if (!handled) { /* Otherwise, we pass it along to the client. */ - wlr_seat_set_keyboard(seat->seat, device); + wlr_seat_set_keyboard(seat->seat, keyboard); wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); } @@ -274,25 +274,23 @@ static void handle_keyboard_group_key(struct wl_listener *listener, void *data) { struct cg_keyboard_group *cg_group = wl_container_of(listener, cg_group, key); - handle_key_event(cg_group->wlr_group->input_device, cg_group->seat, data); + handle_key_event(&cg_group->wlr_group->keyboard, cg_group->seat, data); } static void handle_keyboard_group_modifiers(struct wl_listener *listener, void *data) { struct cg_keyboard_group *group = wl_container_of(listener, group, modifiers); - handle_modifier_event(group->wlr_group->input_device, group->seat); + handle_modifier_event(&group->wlr_group->keyboard, group->seat); } static void -cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) +cg_keyboard_group_add(struct wlr_keyboard *keyboard, struct cg_seat *seat) { - struct wlr_keyboard *wlr_keyboard = device->keyboard; - struct cg_keyboard_group *group; wl_list_for_each (group, &seat->keyboard_groups, link) { struct wlr_keyboard_group *wlr_group = group->wlr_group; - if (wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard)) { + if (wlr_keyboard_group_add_keyboard(wlr_group, keyboard)) { wlr_log(WLR_DEBUG, "Added new keyboard to existing group"); return; } @@ -313,14 +311,14 @@ cg_keyboard_group_add(struct wlr_input_device *device, struct cg_seat *seat) } cg_group->wlr_group->data = cg_group; - wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, device->keyboard->keymap); + wlr_keyboard_set_keymap(&cg_group->wlr_group->keyboard, keyboard->keymap); - wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, wlr_keyboard->repeat_info.rate, - wlr_keyboard->repeat_info.delay); + wlr_keyboard_set_repeat_info(&cg_group->wlr_group->keyboard, keyboard->repeat_info.rate, + keyboard->repeat_info.delay); wlr_log(WLR_DEBUG, "Created keyboard group"); - wlr_keyboard_group_add_keyboard(cg_group->wlr_group, wlr_keyboard); + wlr_keyboard_group_add_keyboard(cg_group->wlr_group, keyboard); wl_list_insert(&seat->keyboard_groups, &cg_group->link); wl_signal_add(&cg_group->wlr_group->keyboard.events.key, &cg_group->key); @@ -338,7 +336,7 @@ cleanup: } static void -handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) +handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard) { struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -353,15 +351,15 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_input_device *device) return; } - wlr_keyboard_set_keymap(device->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); - wlr_keyboard_set_repeat_info(device->keyboard, 25, 600); + wlr_keyboard_set_repeat_info(keyboard, 25, 600); - cg_keyboard_group_add(device, seat); + cg_keyboard_group_add(keyboard, seat); - wlr_seat_set_keyboard(seat->seat, device); + wlr_seat_set_keyboard(seat->seat, keyboard); } static void @@ -372,13 +370,13 @@ handle_new_input(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - handle_new_keyboard(seat, device); + handle_new_keyboard(seat, wlr_keyboard_from_input_device(device)); break; case WLR_INPUT_DEVICE_POINTER: - handle_new_pointer(seat, device); + handle_new_pointer(seat, wlr_pointer_from_input_device(device)); break; case WLR_INPUT_DEVICE_TOUCH: - handle_new_touch(seat, device); + handle_new_touch(seat, wlr_touch_from_input_device(device)); break; case WLR_INPUT_DEVICE_SWITCH: wlr_log(WLR_DEBUG, "Switch input is not implemented"); @@ -433,10 +431,10 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, touch_down); - struct wlr_event_touch_down *event = data; + struct wlr_touch_down_event *event = data; double lx, ly; - wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); + wlr_cursor_absolute_to_layout_coords(seat->cursor, &event->touch->base, event->x, event->y, &lx, &ly); double sx, sy; struct wlr_surface *surface; @@ -451,7 +449,7 @@ handle_touch_down(struct wl_listener *listener, void *data) seat->touch_id = event->touch_id; seat->touch_lx = lx; seat->touch_ly = ly; - press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); + press_cursor_button(seat, &event->touch->base, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); } wlr_idle_notify_activity(seat->server->idle, seat->seat); @@ -461,14 +459,14 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, touch_up); - struct wlr_event_touch_up *event = data; + struct wlr_touch_up_event *event = data; if (!wlr_seat_touch_get_point(seat->seat, event->touch_id)) { return; } if (wlr_seat_touch_num_points(seat->seat) == 1) { - press_cursor_button(seat, event->device, event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED, + press_cursor_button(seat, &event->touch->base, event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED, seat->touch_lx, seat->touch_ly); } @@ -480,14 +478,14 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, touch_motion); - struct wlr_event_touch_motion *event = data; + struct wlr_touch_motion_event *event = data; if (!wlr_seat_touch_get_point(seat->seat, event->touch_id)) { return; } double lx, ly; - wlr_cursor_absolute_to_layout_coords(seat->cursor, event->device, event->x, event->y, &lx, &ly); + wlr_cursor_absolute_to_layout_coords(seat->cursor, &event->touch->base, event->x, event->y, &lx, &ly); double sx, sy; struct wlr_surface *surface; @@ -521,7 +519,7 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, cursor_axis); - struct wlr_event_pointer_axis *event = data; + struct wlr_pointer_axis_event *event = data; wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, event->source); @@ -532,10 +530,10 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, cursor_button); - struct wlr_event_pointer_button *event = data; + struct wlr_pointer_button_event *event = data; wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state); - press_cursor_button(seat, event->device, event->time_msec, event->button, event->state, seat->cursor->x, + press_cursor_button(seat, &event->pointer->base, event->time_msec, event->button, event->state, seat->cursor->x, seat->cursor->y); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -569,9 +567,9 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_absolute); - struct wlr_event_pointer_motion_absolute *event = data; + struct wlr_pointer_motion_absolute_event *event = data; - wlr_cursor_warp_absolute(seat->cursor, event->device, event->x, event->y); + wlr_cursor_warp_absolute(seat->cursor, &event->pointer->base, event->x, event->y); process_cursor_motion(seat, event->time_msec); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -580,9 +578,9 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion); - struct wlr_event_pointer_motion *event = data; + struct wlr_pointer_motion_event *event = data; - wlr_cursor_move(seat->cursor, event->device, event->delta_x, event->delta_y); + wlr_cursor_move(seat->cursor, &event->pointer->base, event->delta_x, event->delta_y); process_cursor_motion(seat, event->time_msec); wlr_idle_notify_activity(seat->server->idle, seat->seat); } diff --git a/seat.h b/seat.h index 5fb2db3..479dbaf 100644 --- a/seat.h +++ b/seat.h @@ -60,7 +60,7 @@ struct cg_keyboard_group { struct cg_pointer { struct wl_list link; // seat::pointers struct cg_seat *seat; - struct wlr_input_device *device; + struct wlr_pointer *pointer; struct wl_listener destroy; }; @@ -68,7 +68,7 @@ struct cg_pointer { struct cg_touch { struct wl_list link; // seat::touch struct cg_seat *seat; - struct wlr_input_device *device; + struct wlr_touch *touch; struct wl_listener destroy; }; From b43c7adcd90739335b45d1e56b93fa017b9553e4 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 12 Oct 2022 04:00:11 -0400 Subject: [PATCH 146/233] xdg_shell: Port 0.16 xdg_toplevel changes --- xdg_shell.c | 36 ++++++++++++++++-------------------- xdg_shell.h | 2 +- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index ede71f4..fcb3745 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -94,7 +94,7 @@ static char * get_title(struct cg_view *view) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); - return xdg_shell_view->xdg_surface->toplevel->title; + return xdg_shell_view->xdg_toplevel->title; } static void @@ -103,7 +103,7 @@ get_geometry(struct cg_view *view, int *width_out, int *height_out) struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); struct wlr_box geom; - wlr_xdg_surface_get_geometry(xdg_shell_view->xdg_surface, &geom); + wlr_xdg_surface_get_geometry(xdg_shell_view->xdg_toplevel->base, &geom); *width_out = geom.width; *height_out = geom.height; } @@ -112,12 +112,9 @@ static bool is_primary(struct cg_view *view) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); - struct wlr_xdg_surface *xdg_surface = xdg_shell_view->xdg_surface; + struct wlr_xdg_toplevel *parent = xdg_shell_view->xdg_toplevel->parent; - struct wlr_xdg_surface *parent = xdg_surface->toplevel->parent; - enum wlr_xdg_surface_role role = xdg_surface->role; - - return parent == NULL && role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; + return parent == NULL; } static bool @@ -127,14 +124,13 @@ is_transient_for(struct cg_view *child, struct cg_view *parent) return false; } struct cg_xdg_shell_view *_child = xdg_shell_view_from_view(child); - struct wlr_xdg_surface *xdg_surface = _child->xdg_surface; + struct wlr_xdg_toplevel *xdg_toplevel = _child->xdg_toplevel; struct cg_xdg_shell_view *_parent = xdg_shell_view_from_view(parent); - struct wlr_xdg_surface *parent_xdg_surface = _parent->xdg_surface; - while (xdg_surface) { - if (xdg_surface->toplevel->parent == parent_xdg_surface) { + while (xdg_toplevel) { + if (xdg_toplevel->parent == _parent->xdg_toplevel) { return true; } - xdg_surface = xdg_surface->toplevel->parent; + xdg_toplevel = xdg_toplevel->parent; } return false; } @@ -143,15 +139,15 @@ static void activate(struct cg_view *view, bool activate) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); - wlr_xdg_toplevel_set_activated(xdg_shell_view->xdg_surface, activate); + wlr_xdg_toplevel_set_activated(xdg_shell_view->xdg_toplevel, activate); } static void maximize(struct cg_view *view, int output_width, int output_height) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); - wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_surface, output_width, output_height); - wlr_xdg_toplevel_set_maximized(xdg_shell_view->xdg_surface, true); + wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_toplevel, output_width, output_height); + wlr_xdg_toplevel_set_maximized(xdg_shell_view->xdg_toplevel, true); } static void @@ -172,9 +168,9 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * * 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_size(xdg_shell_view->xdg_toplevel, layout_box->width, layout_box->height); - wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_surface, event->fullscreen); + wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_toplevel, event->fullscreen); } static void @@ -192,7 +188,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; - view_map(view, xdg_shell_view->xdg_surface->surface); + view_map(view, xdg_shell_view->xdg_toplevel->base->surface); } static void @@ -205,7 +201,7 @@ handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data) wl_list_remove(&xdg_shell_view->unmap.link); wl_list_remove(&xdg_shell_view->destroy.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); - xdg_shell_view->xdg_surface = NULL; + xdg_shell_view->xdg_toplevel = NULL; view_destroy(view); } @@ -235,7 +231,7 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) } view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); - xdg_shell_view->xdg_surface = xdg_surface; + xdg_shell_view->xdg_toplevel = xdg_surface->toplevel; xdg_shell_view->map.notify = handle_xdg_shell_surface_map; wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); diff --git a/xdg_shell.h b/xdg_shell.h index 9a101c6..2fd506a 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -9,7 +9,7 @@ struct cg_xdg_shell_view { struct cg_view view; - struct wlr_xdg_surface *xdg_surface; + struct wlr_xdg_toplevel *xdg_toplevel; struct wl_listener destroy; struct wl_listener unmap; From ea148191535748a48cfea276fdbc91979650b69a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 12 Oct 2022 04:00:33 -0400 Subject: [PATCH 147/233] xdg_shell: Port to 0.16 double buffered geometry --- xdg_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xdg_shell.c b/xdg_shell.c index fcb3745..a5287e6 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -67,7 +67,7 @@ static void popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) { struct cg_server *server = view->server; - struct wlr_box *popup_box = &popup->geometry; + struct wlr_box *popup_box = &popup->current.geometry; struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output *wlr_output = From 5818a32a99ded50af005b25405230c7c5c999d47 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 16 Dec 2022 05:42:52 -0500 Subject: [PATCH 148/233] xdg_shell: Port 0.16 configure changes --- xdg_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index a5287e6..b5f5c9b 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -161,7 +161,6 @@ 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; /** * Certain clients do not like figuring out their own window geometry if they @@ -170,7 +169,8 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * 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_toplevel, layout_box->width, layout_box->height); - wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_toplevel, event->fullscreen); + wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_toplevel, + xdg_shell_view->xdg_toplevel->requested.fullscreen); } static void From 979ff58a24f79d8d1f5deb0a58f74afb5d2a4cfe Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 12 Oct 2022 04:05:33 -0400 Subject: [PATCH 149/233] Port 0.16 wlr_output_layout_get_box changes Fixes memory leaks. --- cage.c | 5 +++-- view.c | 9 +++++---- xdg_shell.c | 16 +++++++++------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/cage.c b/cage.c index 896334b..d24fc17 100644 --- a/cage.c +++ b/cage.c @@ -536,8 +536,9 @@ main(int argc, char *argv[]) } /* Place the cursor in the center of the output layout. */ - struct wlr_box *layout_box = wlr_output_layout_get_box(server.output_layout, NULL); - wlr_cursor_warp(server.seat->cursor, NULL, layout_box->width / 2, layout_box->height / 2); + struct wlr_box layout_box; + wlr_output_layout_get_box(server.output_layout, NULL, &layout_box); + wlr_cursor_warp(server.seat->cursor, NULL, layout_box.width / 2, layout_box.height / 2); wl_display_run(server.wl_display); diff --git a/view.c b/view.c index 6551142..788af3d 100644 --- a/view.c +++ b/view.c @@ -88,12 +88,13 @@ view_center(struct cg_view *view, struct wlr_box *layout_box) void view_position(struct cg_view *view) { - struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); + struct wlr_box layout_box; + wlr_output_layout_get_box(view->server->output_layout, NULL, &layout_box); - if (view_is_primary(view) || view_extends_output_layout(view, layout_box)) { - view_maximize(view, layout_box); + if (view_is_primary(view) || view_extends_output_layout(view, &layout_box)) { + view_maximize(view, &layout_box); } else { - view_center(view, layout_box); + view_center(view, &layout_box); } } diff --git a/xdg_shell.c b/xdg_shell.c index b5f5c9b..b0fa185 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -72,13 +72,14 @@ popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, view->lx + popup_box->x, view->ly + popup_box->y); - struct wlr_box *output_box = wlr_output_layout_get_box(output_layout, wlr_output); + struct wlr_box output_box; + wlr_output_layout_get_box(output_layout, wlr_output, &output_box); struct wlr_box output_toplevel_box = { - .x = output_box->x - view->lx, - .y = output_box->y - view->ly, - .width = output_box->width, - .height = output_box->height, + .x = output_box.x - view->lx, + .y = output_box.y - view->ly, + .width = output_box.width, + .height = output_box.height, }; wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box); @@ -166,8 +167,9 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * * 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_toplevel, layout_box->width, layout_box->height); + struct wlr_box layout_box; + wlr_output_layout_get_box(xdg_shell_view->view.server->output_layout, NULL, &layout_box); + wlr_xdg_toplevel_set_size(xdg_shell_view->xdg_toplevel, layout_box.width, layout_box.height); wlr_xdg_toplevel_set_fullscreen(xdg_shell_view->xdg_toplevel, xdg_shell_view->xdg_toplevel->requested.fullscreen); From 32c44ddb5f3619f558eb8c73fb36ac091be8d0fe Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 14 Dec 2022 13:56:15 -0500 Subject: [PATCH 150/233] Port 0.16 scene changes --- seat.c | 33 ++++++++++++++++++++++----------- seat.h | 2 +- view.c | 12 ++++++------ view.h | 2 +- xdg_shell.c | 14 +++++++------- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/seat.c b/seat.c index 9aa2d6e..cfb4f48 100644 --- a/seat.c +++ b/seat.c @@ -53,20 +53,31 @@ static void drag_icon_update_position(struct cg_drag_icon *drag_icon); static struct cg_view * desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - 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) { + struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy); + if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) { return NULL; } - *surface = wlr_scene_surface_from_node(node)->surface; + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_buffer(scene_buffer); + if (!scene_surface) { + return NULL; + } + + *surface = scene_surface->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); + while (!node->data) { + if (!node->parent) { + node = NULL; + break; + } + node = &node->parent->node; + } + + assert(node != NULL); return node->data; } @@ -609,7 +620,7 @@ drag_icon_update_position(struct cg_drag_icon *drag_icon) break; } - wlr_scene_node_set_position(drag_icon->scene_node, drag_icon->lx, drag_icon->ly); + wlr_scene_node_set_position(&drag_icon->scene_tree->node, drag_icon->lx, drag_icon->ly); } static void @@ -619,7 +630,7 @@ handle_drag_icon_destroy(struct wl_listener *listener, void *data) wl_list_remove(&drag_icon->link); wl_list_remove(&drag_icon->destroy.link); - wlr_scene_node_destroy(drag_icon->scene_node); + wlr_scene_node_destroy(&drag_icon->scene_tree->node); free(drag_icon); } @@ -662,8 +673,8 @@ handle_start_drag(struct wl_listener *listener, void *data) } drag_icon->seat = seat; drag_icon->wlr_drag_icon = wlr_drag_icon; - drag_icon->scene_node = wlr_scene_subsurface_tree_create(&seat->server->scene->node, wlr_drag_icon->surface); - if (!drag_icon->scene_node) { + drag_icon->scene_tree = wlr_scene_subsurface_tree_create(&seat->server->scene->tree, wlr_drag_icon->surface); + if (!drag_icon->scene_tree) { free(drag_icon); return; } diff --git a/seat.h b/seat.h index 479dbaf..7b5dabf 100644 --- a/seat.h +++ b/seat.h @@ -77,7 +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; + struct wlr_scene_tree *scene_tree; /* The drag icon has a position in layout coordinates. */ double lx, ly; diff --git a/view.c b/view.c index 788af3d..dd8a8c1 100644 --- a/view.c +++ b/view.c @@ -68,7 +68,7 @@ view_maximize(struct cg_view *view, struct wlr_box *layout_box) view->lx = layout_box->x; view->ly = layout_box->y; - wlr_scene_node_set_position(view->scene_node, view->lx, view->ly); + wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); view->impl->maximize(view, layout_box->width, layout_box->height); } @@ -82,7 +82,7 @@ view_center(struct cg_view *view, struct wlr_box *layout_box) view->lx = (layout_box->width - width) / 2; view->ly = (layout_box->height - height) / 2; - wlr_scene_node_set_position(view->scene_node, view->lx, view->ly); + wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); } void @@ -103,7 +103,7 @@ view_unmap(struct cg_view *view) { wl_list_remove(&view->link); - wlr_scene_node_destroy(view->scene_node); + wlr_scene_node_destroy(&view->scene_tree->node); view->wlr_surface->data = NULL; view->wlr_surface = NULL; @@ -112,12 +112,12 @@ view_unmap(struct cg_view *view) void view_map(struct cg_view *view, struct wlr_surface *surface) { - view->scene_node = wlr_scene_subsurface_tree_create(&view->server->scene->node, surface); - if (!view->scene_node) { + view->scene_tree = wlr_scene_subsurface_tree_create(&view->server->scene->tree, surface); + if (!view->scene_tree) { wl_resource_post_no_memory(surface->resource); return; } - view->scene_node->data = view; + view->scene_tree->node.data = view; view->wlr_surface = surface; surface->data = view; diff --git a/view.h b/view.h index 677a949..11a7648 100644 --- a/view.h +++ b/view.h @@ -25,7 +25,7 @@ struct cg_view { struct cg_server *server; struct wl_list link; // server::views struct wlr_surface *wlr_surface; - struct wlr_scene_node *scene_node; + struct wlr_scene_tree *scene_tree; /* The view has a position in layout coordinates. */ int lx, ly; diff --git a/xdg_shell.c b/xdg_shell.c index b0fa185..c577dc5 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -253,31 +253,31 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) return; } - struct wlr_scene_node *parent_scene_node = NULL; + struct wlr_scene_tree *parent_scene_tree = NULL; struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent); switch (parent->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; - parent_scene_node = view->scene_node; + parent_scene_tree = view->scene_tree; break; case WLR_XDG_SURFACE_ROLE_POPUP: - parent_scene_node = parent->data; + parent_scene_tree = parent->data; break; case WLR_XDG_SURFACE_ROLE_NONE: break; } - if (parent_scene_node == NULL) { + if (parent_scene_tree == NULL) { return; } - struct wlr_scene_node *popup_scene_node = wlr_scene_xdg_surface_create(parent_scene_node, xdg_surface); - if (popup_scene_node == NULL) { + struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, xdg_surface); + if (popup_scene_tree == NULL) { wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); return; } popup_unconstrain(view, popup); - xdg_surface->data = popup_scene_node; + xdg_surface->data = popup_scene_tree; break; case WLR_XDG_SURFACE_ROLE_NONE: assert(false); // unreachable From 3015e0368b2ab208139d6e5478c94924ccff81ce Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 12 Oct 2022 04:17:38 -0400 Subject: [PATCH 151/233] Give xdg_shell a version --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index d24fc17..d857272 100644 --- a/cage.c +++ b/cage.c @@ -402,7 +402,7 @@ main(int argc, char *argv[]) wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1); wl_list_init(&server.inhibitors); - xdg_shell = wlr_xdg_shell_create(server.wl_display); + xdg_shell = wlr_xdg_shell_create(server.wl_display, 4); if (!xdg_shell) { wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); ret = 1; From 36c9c52d3f67276ee848c87eb034267003cdda73 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 16 Dec 2022 05:44:26 -0500 Subject: [PATCH 152/233] Port 0.16 surface header includes --- output.c | 2 +- seat.c | 1 - view.c | 1 - view.h | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/output.c b/output.c index c33bbe1..6eca0db 100644 --- a/output.c +++ b/output.c @@ -22,13 +22,13 @@ #include #endif #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/seat.c b/seat.c index cfb4f48..3b65c3d 100644 --- a/seat.c +++ b/seat.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/view.c b/view.c index dd8a8c1..b4a3eca 100644 --- a/view.c +++ b/view.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "output.h" #include "seat.h" diff --git a/view.h b/view.h index 11a7648..5ae13dd 100644 --- a/view.h +++ b/view.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #if CAGE_HAS_XWAYLAND From 491d508d752f35f11f6c877ce2e3cbe2d1994c36 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 12 Oct 2022 04:29:29 -0400 Subject: [PATCH 153/233] meson: Bump wlroots version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5a8b28c..fbd7e16 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.15.0', fallback: ['wlroots', 'wlroots']) +wlroots = dependency('wlroots', version: '>= 0.16.0', fallback: ['wlroots', 'wlroots']) wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') xkbcommon = dependency('xkbcommon') From a8e4e3d13116720482e29ffd2b8b0c69288d9b35 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 16 Dec 2022 05:43:10 -0500 Subject: [PATCH 154/233] Enable single-pixel-buffer Why not. --- cage.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cage.c b/cage.c index d857272..a08fafc 100644 --- a/cage.c +++ b/cage.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #if CAGE_HAS_XWAYLAND @@ -266,6 +267,7 @@ main(int argc, char *argv[]) struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL; struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; + struct wlr_single_pixel_buffer_manager_v1 *single_pixel_buffer = NULL; struct wlr_xdg_output_manager_v1 *output_manager = NULL; struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; struct wlr_viewporter *viewporter = NULL; @@ -459,6 +461,13 @@ main(int argc, char *argv[]) goto end; } + single_pixel_buffer = wlr_single_pixel_buffer_manager_v1_create(server.wl_display); + if (!single_pixel_buffer) { + wlr_log(WLR_ERROR, "Unable to create the single pixel buffer manager"); + ret = 1; + goto end; + } + output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout); if (!output_manager) { wlr_log(WLR_ERROR, "Unable to create the output manager"); From 5f4c43db04093edf8452efb3b04c3a3c720c78de Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 16 Dec 2022 05:48:44 -0500 Subject: [PATCH 155/233] CI: bump to wlroots 0.16 --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5e95347..a98291a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies (Alpine) if: "matrix.OS == 'alpine:edge'" - run: apk add build-base xcb-util-wm-dev libseat-dev clang git eudev-dev mesa-dev libdrm-dev libinput-dev libxkbcommon-dev pixman-dev wayland-dev meson wayland-protocols xwayland scdoc-doc + run: apk add build-base xcb-util-wm-dev libseat-dev clang git eudev-dev mesa-dev libdrm-dev libinput-dev libxkbcommon-dev pixman-dev wayland-dev meson wayland-protocols xwayland scdoc-doc hwdata - name: Install dependencies (Arch) if: "matrix.OS == 'archlinux:base-devel'" @@ -31,7 +31,7 @@ jobs: pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 # TODO: use --fatal-meson-warnings when on wlroots 0.15.0 - name: Compile Cage (XWayland=${{ matrix.xwayland }}) @@ -48,9 +48,9 @@ jobs: - name: Install dependencies run: | pacman-key --init - pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc + pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 - name: Check for formatting changes run: | meson build-clang-format -Dxwayland=true @@ -67,9 +67,9 @@ jobs: - name: Install dependencies run: | pacman-key --init - pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc + pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.15.0 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 - name: Run scan-build run: | meson build-scan-build -Dxwayland=true From 46f0ec1b729cf2e4fb9c69bb8660e908d1311ea0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 3 Jan 2023 21:30:57 +0100 Subject: [PATCH 156/233] readme: drop CI badge cage currently uses GitHub CI, not SourceHut. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e1b6f56..752387e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Cage: a Wayland kiosk [![builds.sr.ht status](https://builds.sr.ht/~hjdskes.svg)](https://builds.sr.ht/~hjdskes?) +# Cage: a Wayland kiosk Cage's logo From bd5b20e1fab67d7fb548ecde0aade8455df4509c Mon Sep 17 00:00:00 2001 From: ChemicalXandco <32775248+ChemicalXandco@users.noreply.github.com> Date: Sat, 7 Jan 2023 14:28:40 +0000 Subject: [PATCH 157/233] add wlr_virtual_keyboard_manager_v1 and wlr_virtual_pointer_manager_v1 --- cage.c | 20 ++++++++++++++++ seat.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++-------- seat.h | 1 + server.h | 7 +++--- 4 files changed, 86 insertions(+), 14 deletions(-) diff --git a/cage.c b/cage.c index a08fafc..c5eda4d 100644 --- a/cage.c +++ b/cage.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #if CAGE_HAS_XWAYLAND #include #endif @@ -270,6 +272,8 @@ main(int argc, char *argv[]) struct wlr_single_pixel_buffer_manager_v1 *single_pixel_buffer = NULL; struct wlr_xdg_output_manager_v1 *output_manager = NULL; struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard = NULL; + struct wlr_virtual_pointer_manager_v1 *virtual_pointer = NULL; struct wlr_viewporter *viewporter = NULL; struct wlr_presentation *presentation = NULL; struct wlr_xdg_shell *xdg_shell = NULL; @@ -482,6 +486,22 @@ main(int argc, char *argv[]) goto end; } + virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(server.wl_display); + if (!virtual_keyboard) { + wlr_log(WLR_ERROR, "Unable to create the virtual keyboard manager"); + ret = 1; + goto end; + } + wl_signal_add(&virtual_keyboard->events.new_virtual_keyboard, &server.new_virtual_keyboard); + + virtual_pointer = wlr_virtual_pointer_manager_v1_create(server.wl_display); + if (!virtual_pointer) { + wlr_log(WLR_ERROR, "Unable to create the virtual pointer manager"); + ret = 1; + goto end; + } + wl_signal_add(&virtual_pointer->events.new_virtual_pointer, &server.new_virtual_pointer); + #if CAGE_HAS_XWAYLAND xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { diff --git a/seat.c b/seat.c index 3b65c3d..5d80e33 100644 --- a/seat.c +++ b/seat.c @@ -6,11 +6,14 @@ * See the LICENSE file accompanying this file. */ +#define _POSIX_C_SOURCE 200809L + #include "config.h" #include #include #include +#include #include #include #include @@ -22,6 +25,8 @@ #include #include #include +#include +#include #include #include #if CAGE_HAS_XWAYLAND @@ -216,6 +221,27 @@ handle_new_pointer(struct cg_seat *seat, struct wlr_pointer *wlr_pointer) map_input_device_to_output(seat, &wlr_pointer->base, wlr_pointer->output_name); } +static void +handle_virtual_pointer(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, new_virtual_pointer); + struct cg_seat *seat = server->seat; + struct wlr_virtual_pointer_v1_new_pointer_event *event = data; + struct wlr_virtual_pointer_v1 *pointer = event->new_pointer; + struct wlr_pointer *wlr_pointer = &pointer->pointer; + + /* We'll want to map the device back to an output later, this is a bit + * sub-optimal (we could just keep the suggested_output), but just copy + * its name so we do like other devices + */ + if (event->suggested_output != NULL) { + wlr_pointer->output_name = strdup(event->suggested_output->name); + } + /* TODO: event->suggested_seat should be checked if we handle multiple seats */ + handle_new_pointer(seat, wlr_pointer); + update_capabilities(seat); +} + static void handle_modifier_event(struct wlr_keyboard *keyboard, struct cg_seat *seat) { @@ -295,14 +321,21 @@ handle_keyboard_group_modifiers(struct wl_listener *listener, void *data) } static void -cg_keyboard_group_add(struct wlr_keyboard *keyboard, struct cg_seat *seat) +cg_keyboard_group_add(struct wlr_keyboard *keyboard, struct cg_seat *seat, bool virtual) { - struct cg_keyboard_group *group; - wl_list_for_each (group, &seat->keyboard_groups, link) { - struct wlr_keyboard_group *wlr_group = group->wlr_group; - if (wlr_keyboard_group_add_keyboard(wlr_group, keyboard)) { - wlr_log(WLR_DEBUG, "Added new keyboard to existing group"); - return; + /* We apparently should not group virtual keyboards, + * so create a new group with it + */ + if (!virtual) { + struct cg_keyboard_group *group; + wl_list_for_each (group, &seat->keyboard_groups, link) { + if (group->is_virtual) + continue; + struct wlr_keyboard_group *wlr_group = group->wlr_group; + if (wlr_keyboard_group_add_keyboard(wlr_group, keyboard)) { + wlr_log(WLR_DEBUG, "Added new keyboard to existing group"); + return; + } } } @@ -314,6 +347,7 @@ cg_keyboard_group_add(struct wlr_keyboard *keyboard, struct cg_seat *seat) return; } cg_group->seat = seat; + cg_group->is_virtual = virtual; cg_group->wlr_group = wlr_keyboard_group_create(); if (cg_group->wlr_group == NULL) { wlr_log(WLR_ERROR, "Failed to create wlr keyboard group."); @@ -346,7 +380,7 @@ cleanup: } static void -handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard) +handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard, bool virtual) { struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -367,11 +401,26 @@ handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard) xkb_context_unref(context); wlr_keyboard_set_repeat_info(keyboard, 25, 600); - cg_keyboard_group_add(keyboard, seat); + cg_keyboard_group_add(keyboard, seat, virtual); wlr_seat_set_keyboard(seat->seat, keyboard); } +static void +handle_virtual_keyboard(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, new_virtual_keyboard); + struct cg_seat *seat = server->seat; + struct wlr_virtual_keyboard_v1 *keyboard = data; + struct wlr_keyboard *wlr_keyboard = &keyboard->keyboard; + + /* TODO: If multiple seats are supported, check keyboard->seat + * to select the appropriate one */ + + handle_new_keyboard(seat, wlr_keyboard, true); + update_capabilities(seat); +} + static void handle_new_input(struct wl_listener *listener, void *data) { @@ -380,7 +429,7 @@ handle_new_input(struct wl_listener *listener, void *data) switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: - handle_new_keyboard(seat, wlr_keyboard_from_input_device(device)); + handle_new_keyboard(seat, wlr_keyboard_from_input_device(device), false); break; case WLR_INPUT_DEVICE_POINTER: handle_new_pointer(seat, wlr_pointer_from_input_device(device)); @@ -797,6 +846,9 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) seat->new_input.notify = handle_new_input; wl_signal_add(&backend->events.new_input, &seat->new_input); + server->new_virtual_keyboard.notify = handle_virtual_keyboard; + server->new_virtual_pointer.notify = handle_virtual_pointer; + wl_list_init(&seat->drag_icons); seat->request_start_drag.notify = handle_request_start_drag; wl_signal_add(&seat->seat->events.request_start_drag, &seat->request_start_drag); diff --git a/seat.h b/seat.h index 7b5dabf..52cbee4 100644 --- a/seat.h +++ b/seat.h @@ -55,6 +55,7 @@ struct cg_keyboard_group { struct wl_listener key; struct wl_listener modifiers; struct wl_list link; // cg_seat::keyboard_groups + bool is_virtual; }; struct cg_pointer { diff --git a/server.h b/server.h index bb7f3c1..082a435 100644 --- a/server.h +++ b/server.h @@ -12,10 +12,6 @@ #include #endif -#include "output.h" -#include "seat.h" -#include "view.h" - enum cg_multi_output_mode { CAGE_MULTI_OUTPUT_MODE_EXTEND, CAGE_MULTI_OUTPUT_MODE_LAST, @@ -44,6 +40,9 @@ struct cg_server { struct wl_listener xdg_toplevel_decoration; struct wl_listener new_xdg_shell_surface; + + struct wl_listener new_virtual_keyboard; + struct wl_listener new_virtual_pointer; #if CAGE_HAS_XWAYLAND struct wl_listener new_xwayland_surface; #endif From 27b6971b3690e32ecd56cd0ee503e700e4c783f3 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Fri, 14 Jan 2022 21:22:11 +0100 Subject: [PATCH 158/233] cage: remove support for rotating outputs This is now handled through wlr_output_management --- cage.1.scd | 4 ---- cage.c | 9 +-------- output.c | 2 -- server.h | 1 - 4 files changed, 1 insertion(+), 15 deletions(-) diff --git a/cage.1.scd b/cage.1.scd index 4ca1bea..37d4690 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -27,10 +27,6 @@ activities outside the scope of the running application are prevented. *last* Cage uses only the last connected monitor. *extend* Cage extends the display across all connected monitors. -*-r* - Rotate the output 90 degrees clockwise. This can be specified up to three - times, each resulting in an additional 90 degrees clockwise rotation. - *-s* Allow VT switching diff --git a/cage.c b/cage.c index c5eda4d..a98467f 100644 --- a/cage.c +++ b/cage.c @@ -201,7 +201,6 @@ usage(FILE *file, const char *cage) " -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" - " -r\t Rotate the output 90 degrees clockwise, specify up to three times\n" " -s\t Allow VT switching\n" " -v\t Show the version number and exit\n" "\n" @@ -213,7 +212,7 @@ static bool parse_args(struct cg_server *server, int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "dhm:rsv")) != -1) { + while ((c = getopt(argc, argv, "dhm:sv")) != -1) { switch (c) { case 'd': server->xdg_decoration = true; @@ -228,12 +227,6 @@ parse_args(struct cg_server *server, int argc, char *argv[]) server->output_mode = CAGE_MULTI_OUTPUT_MODE_EXTEND; } break; - case 'r': - server->output_transform++; - if (server->output_transform > WL_OUTPUT_TRANSFORM_270) { - server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL; - } - break; case 's': server->allow_vt_switch = true; break; diff --git a/output.c b/output.c index 6eca0db..cdf1b54 100644 --- a/output.c +++ b/output.c @@ -217,8 +217,6 @@ handle_new_output(struct wl_listener *listener, void *data) } } - wlr_output_set_transform(wlr_output, output->server->output_transform); - if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST) { struct cg_output *next = wl_container_of(output->link.next, next, link); if (next) { diff --git a/server.h b/server.h index 082a435..0e808c1 100644 --- a/server.h +++ b/server.h @@ -49,7 +49,6 @@ struct cg_server { bool xdg_decoration; bool allow_vt_switch; - enum wl_output_transform output_transform; }; #endif From 6f78d9d5b2a958f21a506249432dae06809264e6 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Fri, 21 Jul 2023 15:37:38 +0200 Subject: [PATCH 159/233] cage: add basic wlr-output-management support Co-authored-by: Dima Krasner --- cage.c | 14 +++++ output.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++-------- output.h | 3 ++ server.h | 4 ++ view.c | 9 ++++ view.h | 1 + 6 files changed, 170 insertions(+), 21 deletions(-) diff --git a/cage.c b/cage.c index a98467f..bce4b65 100644 --- a/cage.c +++ b/cage.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -340,6 +341,8 @@ main(int argc, char *argv[]) ret = 1; goto end; } + server.output_layout_change.notify = handle_output_layout_change; + wl_signal_add(&server.output_layout->events.change, &server.output_layout_change); server.scene = wlr_scene_create(); if (!server.scene) { @@ -472,6 +475,17 @@ main(int argc, char *argv[]) goto end; } + server.output_manager_v1 = wlr_output_manager_v1_create(server.wl_display); + if (!server.output_manager_v1) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); + ret = 1; + goto end; + } + server.output_manager_apply.notify = handle_output_manager_apply; + wl_signal_add(&server.output_manager_v1->events.apply, &server.output_manager_apply); + server.output_manager_test.notify = handle_output_manager_test; + wl_signal_add(&server.output_manager_v1->events.test, &server.output_manager_test); + gamma_control_manager = wlr_gamma_control_manager_v1_create(server.wl_display); if (!gamma_control_manager) { wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); diff --git a/output.c b/output.c index cdf1b54..30f8c56 100644 --- a/output.c +++ b/output.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,32 @@ #include "xwayland.h" #endif +#define OUTPUT_CONFIG_UPDATED \ + (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_SCALE | WLR_OUTPUT_STATE_TRANSFORM | \ + WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) + +static void +update_output_manager_config(struct cg_server *server) +{ + struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); + + struct cg_output *output; + wl_list_for_each (output, &server->outputs, link) { + struct wlr_output *wlr_output = output->wlr_output; + struct wlr_output_configuration_head_v1 *config_head = + wlr_output_configuration_head_v1_create(config, wlr_output); + struct wlr_box output_box; + + wlr_output_layout_get_box(server->output_layout, wlr_output, &output_box); + if (!wlr_box_empty(&output_box)) { + config_head->state.x = output_box.x; + config_head->state.y = output_box.y; + } + } + + wlr_output_manager_v1_set_configuration(server->output_manager_v1, config); +} + static void output_enable(struct cg_output *output) { @@ -57,6 +84,8 @@ output_enable(struct cg_output *output) output->scene_output = wlr_scene_get_scene_output(output->server->scene, wlr_output); assert(output->scene_output != NULL); + + update_output_manager_config(output->server); } static void @@ -77,6 +106,44 @@ output_disable(struct cg_output *output) wlr_output_commit(wlr_output); } +static bool +output_apply_config(struct cg_output *output, struct wlr_output_configuration_head_v1 *head, bool test_only) +{ + wlr_output_enable(output->wlr_output, head->state.enabled); + + if (head->state.enabled) { + /* Do not mess with these parameters for output to be disabled */ + wlr_output_set_scale(output->wlr_output, head->state.scale); + wlr_output_set_transform(output->wlr_output, head->state.transform); + + if (head->state.mode) { + wlr_output_set_mode(output->wlr_output, head->state.mode); + } else { + wlr_output_set_custom_mode(output->wlr_output, head->state.custom_mode.width, + head->state.custom_mode.height, head->state.custom_mode.refresh); + } + } + + if (test_only) { + bool ret = wlr_output_test(output->wlr_output); + wlr_output_rollback(output->wlr_output); + return ret; + } + + /* Apply output configuration */ + if (!wlr_output_commit(output->wlr_output)) { + return false; + } + + if (head->state.enabled) { + wlr_output_layout_add(output->server->output_layout, head->state.output, head->state.x, head->state.y); + } else { + wlr_output_layout_remove(output->server->output_layout, output->wlr_output); + } + + return true; +} + static void handle_output_frame(struct wl_listener *listener, void *data) { @@ -99,15 +166,21 @@ handle_output_commit(struct wl_listener *listener, void *data) struct cg_output *output = wl_container_of(listener, output, commit); struct wlr_output_event_commit *event = data; - if (!output->wlr_output->enabled) { - return; + /* Notes: + * - output layout change will also be called if needed to position the views + * - always update output manager configuration even if the output is now disabled */ + + if (event->committed & WLR_OUTPUT_STATE_ENABLED) { + if (output->wlr_output->enabled) { + output->scene_output = wlr_scene_get_scene_output(output->server->scene, output->wlr_output); + assert(output->scene_output != NULL); + } else { + output->scene_output = NULL; + } } - if (event->committed & WLR_OUTPUT_STATE_TRANSFORM) { - struct cg_view *view; - wl_list_for_each (view, &output->server->views, link) { - view_position(view); - } + if (event->committed & OUTPUT_CONFIG_UPDATED) { + update_output_manager_config(output->server); } } @@ -120,10 +193,17 @@ handle_output_mode(struct wl_listener *listener, void *data) return; } - struct cg_view *view; - wl_list_for_each (view, &output->server->views, link) { - view_position(view); - } + view_position_all(output->server); + update_output_manager_config(output->server); +} + +void +handle_output_layout_change(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, output_layout_change); + + view_position_all(server); + update_output_manager_config(server); } static void @@ -149,11 +229,7 @@ output_destroy(struct cg_output *output) struct cg_output *prev = wl_container_of(server->outputs.next, prev, link); if (prev) { output_enable(prev); - - struct cg_view *view; - wl_list_for_each (view, &server->views, link) { - view_position(view); - } + view_position_all(server); } } } @@ -230,11 +306,7 @@ handle_new_output(struct wl_listener *listener, void *data) } output_enable(output); - - struct cg_view *view; - wl_list_for_each (view, &output->server->views, link) { - view_position(view); - } + view_position_all(output->server); } void @@ -255,3 +327,49 @@ output_set_window_title(struct cg_output *output, const char *title) #endif } } + +static bool +output_config_apply(struct cg_server *server, struct wlr_output_configuration_v1 *config, bool test_only) +{ + struct wlr_output_configuration_head_v1 *head; + + wl_list_for_each (head, &config->heads, link) { + struct cg_output *output = head->state.output->data; + + if (!output_apply_config(output, head, test_only)) { + return false; + } + } + + return true; +} + +void +handle_output_manager_apply(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, output_manager_apply); + struct wlr_output_configuration_v1 *config = data; + + if (output_config_apply(server, config, false)) { + wlr_output_configuration_v1_send_succeeded(config); + } else { + wlr_output_configuration_v1_send_failed(config); + } + + wlr_output_configuration_v1_destroy(config); +} + +void +handle_output_manager_test(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, output_manager_test); + struct wlr_output_configuration_v1 *config = data; + + if (output_config_apply(server, config, true)) { + wlr_output_configuration_v1_send_succeeded(config); + } else { + wlr_output_configuration_v1_send_failed(config); + } + + wlr_output_configuration_v1_destroy(config); +} diff --git a/output.h b/output.h index ced06f6..4783fd1 100644 --- a/output.h +++ b/output.h @@ -21,6 +21,9 @@ struct cg_output { struct wl_list link; // cg_server::outputs }; +void handle_output_manager_apply(struct wl_listener *listener, void *data); +void handle_output_manager_test(struct wl_listener *listener, void *data); +void handle_output_layout_change(struct wl_listener *listener, void *data); void handle_new_output(struct wl_listener *listener, void *data); void output_set_window_title(struct cg_output *output, const char *title); diff --git a/server.h b/server.h index 0e808c1..6e2fddf 100644 --- a/server.h +++ b/server.h @@ -37,6 +37,7 @@ struct cg_server { * some outputs may be disabled. */ struct wl_list outputs; // cg_output::link struct wl_listener new_output; + struct wl_listener output_layout_change; struct wl_listener xdg_toplevel_decoration; struct wl_listener new_xdg_shell_surface; @@ -46,6 +47,9 @@ struct cg_server { #if CAGE_HAS_XWAYLAND struct wl_listener new_xwayland_surface; #endif + struct wlr_output_manager_v1 *output_manager_v1; + struct wl_listener output_manager_apply; + struct wl_listener output_manager_test; bool xdg_decoration; bool allow_vt_switch; diff --git a/view.c b/view.c index b4a3eca..8948580 100644 --- a/view.c +++ b/view.c @@ -97,6 +97,15 @@ view_position(struct cg_view *view) } } +void +view_position_all(struct cg_server *server) +{ + struct cg_view *view; + wl_list_for_each (view, &server->views, link) { + view_position(view); + } +} + void view_unmap(struct cg_view *view) { diff --git a/view.h b/view.h index 5ae13dd..9b2ab75 100644 --- a/view.h +++ b/view.h @@ -49,6 +49,7 @@ bool view_is_primary(struct cg_view *view); bool view_is_transient_for(struct cg_view *child, struct cg_view *parent); void view_activate(struct cg_view *view, bool activate); void view_position(struct cg_view *view); +void view_position_all(struct cg_server *server); 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); From b1129ca72e0193672f78d9d033d70cfc8e3dc704 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Thu, 27 Jul 2023 16:58:29 +0200 Subject: [PATCH 160/233] output: fix segfault when using `-m last` option Check output list length before accessing previous or next item to avoid segfault. --- output.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/output.c b/output.c index 30f8c56..465c0ed 100644 --- a/output.c +++ b/output.c @@ -225,12 +225,10 @@ output_destroy(struct cg_output *output) if (wl_list_empty(&server->outputs)) { wl_display_terminate(server->wl_display); - } else if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST) { + } else if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST && !wl_list_empty(&server->outputs)) { struct cg_output *prev = wl_container_of(server->outputs.next, prev, link); - if (prev) { - output_enable(prev); - view_position_all(server); - } + output_enable(prev); + view_position_all(server); } } @@ -293,11 +291,9 @@ handle_new_output(struct wl_listener *listener, void *data) } } - if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST) { + if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST && wl_list_length(&server->outputs) > 1) { struct cg_output *next = wl_container_of(output->link.next, next, link); - if (next) { - output_disable(next); - } + output_disable(next); } if (!wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { From 8dcc901522080c3ca7916fe819db8f9873a471b6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 17 Jul 2023 18:28:54 +0200 Subject: [PATCH 161/233] Log execvp() failures Closes: https://github.com/cage-kiosk/cage/issues/255 --- cage.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cage.c b/cage.c index bce4b65..75f0696 100644 --- a/cage.c +++ b/cage.c @@ -113,6 +113,8 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s /* Close read, we only need write in the primary client process. */ close(fd[0]); execvp(argv[0], argv); + /* execvp() returns only on failure */ + wlr_log_errno(WLR_ERROR, "Failed to spawn client"); _exit(1); } else if (pid == -1) { wlr_log_errno(WLR_ERROR, "Unable to fork"); From 794803adc96b9363f71bb95f7d3063121400a1c3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 28 Jul 2023 16:42:58 +0200 Subject: [PATCH 162/233] build: fix default xwayland option type --- meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index a28e2cf..22055dc 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,2 @@ option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') -option('xwayland', type: 'boolean', value: 'false', description: 'Enable support for X11 applications') +option('xwayland', type: 'boolean', value: false, description: 'Enable support for X11 applications') From 83ffc574be860527814c595756a558c228a3475d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 28 Jul 2023 16:46:37 +0200 Subject: [PATCH 163/233] build: bump version to 0.1.5 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index fbd7e16..fd84262 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cage', 'c', - version: '0.1.4', + version: '0.1.5', license: 'MIT', meson_version: '>=0.58.1', default_options: [ From ea95a8af72955a2bacbd2cff4d3054632e952204 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 29 Jul 2023 01:08:56 +0200 Subject: [PATCH 164/233] readme: update PGP key ID --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 752387e..f16a24f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Wiki](https://github.com/Hjdskes/cage/wiki/). ## Release signatures Releases are signed with -[6EBC43B1](http://keys.gnupg.net/pks/lookup?op=vindex&fingerprint=on&search=0x37C445296EBC43B1) +[E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) and published on [GitHub](https://github.com/Hjdskes/cage/releases). ## Building and running Cage From d519b5b529a63a34b97cf894de48516538795099 Mon Sep 17 00:00:00 2001 From: Jente Hidskes Ankarberg Date: Sat, 29 Jul 2023 10:20:42 +0200 Subject: [PATCH 165/233] Establish chain of trust for signed releases --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f16a24f..d75079b 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ Wiki](https://github.com/Hjdskes/cage/wiki/). ## Release signatures -Releases are signed with +Releases up to version 0.1.4 are signed with [6EBC43B1](http://keys.gnupg.net/pks/lookup?op=vindex&fingerprint=on&search=0x37C445296EBC43B1). Releases from 0.1.5 onwards are signed with [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) -and published on [GitHub](https://github.com/Hjdskes/cage/releases). +All releases are published on [GitHub](https://github.com/Hjdskes/cage/releases). ## Building and running Cage From 9a4310f8b6d40be49ca3065742c7462278b1316e Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 13 Aug 2023 23:35:42 +0200 Subject: [PATCH 166/233] Chase HTTP redirect --- README.md | 14 +++++++------- cage.1.scd | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d75079b..71cee17 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ application. This README is only relevant for development resources and instructions. For a description of Cage and installation instructions for end-users, please see [its project page](https://www.hjdskes.nl/projects/cage) and [the -Wiki](https://github.com/Hjdskes/cage/wiki/). +Wiki](https://github.com/cage-kiosk/cage/wiki/). ## Release signatures Releases up to version 0.1.4 are signed with [6EBC43B1](http://keys.gnupg.net/pks/lookup?op=vindex&fingerprint=on&search=0x37C445296EBC43B1). Releases from 0.1.5 onwards are signed with [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) -All releases are published on [GitHub](https://github.com/Hjdskes/cage/releases). +All releases are published on [GitHub](https://github.com/cage-kiosk/cage/releases). ## Building and running Cage @@ -45,20 +45,20 @@ within an existing X11 or Wayland session, it will open in a virtual output as a window in your existing session. If you run it at a TTY, it'll run with the KMS+DRM backend. In debug mode (default build type with Meson), press Alt+Esc to quit. For more configuration options, see -[Configuration](https://github.com/Hjdskes/cage/wiki/Configuration). +[Configuration](https://github.com/cage-kiosk/cage/wiki/Configuration). Cage is based on the annotated source of tinywl and rootston. ## Bugs For any bug, please [create an -issue](https://github.com/Hjdskes/cage/issues/new) on -[GitHub](https://github.com/Hjdskes/cage). +issue](https://github.com/cage-kiosk/cage/issues/new) on +[GitHub](https://github.com/cage-kiosk/cage). ## License Please see -[LICENSE](https://github.com/Hjdskes/cage/blob/master/LICENSE) on -[GitHub](https://github.com/Hjdskes/cage). +[LICENSE](https://github.com/cage-kiosk/cage/blob/master/LICENSE) on +[GitHub](https://github.com/cage-kiosk/cage). Copyright © 2018-2020 Jente Hidskes diff --git a/cage.1.scd b/cage.1.scd index 37d4690..0894f5d 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -61,7 +61,7 @@ _XKB_DEFAULT_VARIANT_, _XKB_DEFAULT_OPTIONS_ # BUGS -Report bugs at https://github.com/Hjdskes/cage +Report bugs at https://github.com/cage-kiosk/cage # AUTHORS From 121e3ac8b28db191e02645af7d8bab9d289ccd8b Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Fri, 18 Aug 2023 15:25:21 +0200 Subject: [PATCH 167/233] cage: return exit code of primary client Some applications indicate different shutdown conditions by returning specific exit codes. One of these is e.g. Kodi, which returns 64 in case the user chose "Power off" and 66 in case the user chose "Reboot". In order to act on these exit codes, it thus makes sense in some situations to pass them on from the primary client to the caller of Cage. This exit code is only returned if the primary client is the cause of Cage terminating. Co-authored-by: Patrick Steinhardt --- cage.c | 26 +++++++++++++++++--------- server.h | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/cage.c b/cage.c index 75f0696..7a4bd9f 100644 --- a/cage.c +++ b/cage.c @@ -62,7 +62,7 @@ static int sigchld_handler(int fd, uint32_t mask, void *data) { - struct wl_display *display = data; + struct cg_server *server = data; /* Close Cage's read pipe. */ close(fd); @@ -73,7 +73,8 @@ sigchld_handler(int fd, uint32_t mask, void *data) wlr_log(WLR_DEBUG, "Connection closed by server"); } - wl_display_terminate(display); + server->return_app_code = true; + wl_display_terminate(server->wl_display); return 0; } @@ -97,7 +98,7 @@ set_cloexec(int fd) } static bool -spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, struct wl_event_source **sigchld_source) +spawn_primary_client(struct cg_server *server, char *argv[], pid_t *pid_out, struct wl_event_source **sigchld_source) { int fd[2]; if (pipe(fd) != 0) { @@ -131,15 +132,15 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s /* Close write, we only need read in Cage. */ close(fd[1]); - struct wl_event_loop *event_loop = wl_display_get_event_loop(display); + struct wl_event_loop *event_loop = wl_display_get_event_loop(server->wl_display); uint32_t mask = WL_EVENT_HANGUP | WL_EVENT_ERROR; - *sigchld_source = wl_event_loop_add_fd(event_loop, fd[0], mask, sigchld_handler, display); + *sigchld_source = wl_event_loop_add_fd(event_loop, fd[0], mask, sigchld_handler, server); wlr_log(WLR_DEBUG, "Child process created with pid %d", pid); return true; } -static void +static int cleanup_primary_client(pid_t pid) { int status; @@ -148,9 +149,14 @@ cleanup_primary_client(pid_t pid) if (WIFEXITED(status)) { wlr_log(WLR_DEBUG, "Child exited normally with exit status %d", WEXITSTATUS(status)); + return WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { + /* Mimic Bash and other shells for the exit status */ wlr_log(WLR_DEBUG, "Child was terminated by a signal (%d)", WTERMSIG(status)); + return 128 + WTERMSIG(status); } + + return 0; } static bool @@ -278,7 +284,7 @@ main(int argc, char *argv[]) struct wlr_xcursor_manager *xcursor_manager = NULL; #endif pid_t pid = 0; - int ret = 0; + int ret = 0, app_ret = 0; if (!parse_args(&server, argc, argv)) { return 1; @@ -568,7 +574,7 @@ main(int argc, char *argv[]) wlr_xwayland_set_seat(xwayland, server.seat->seat); #endif - if (!spawn_primary_client(server.wl_display, argv + optind, &pid, &sigchld_source)) { + if (!spawn_primary_client(&server, argv + optind, &pid, &sigchld_source)) { ret = 1; goto end; } @@ -587,7 +593,9 @@ main(int argc, char *argv[]) wl_display_destroy_clients(server.wl_display); end: - cleanup_primary_client(pid); + app_ret = cleanup_primary_client(pid); + if (!ret && server.return_app_code) + ret = app_ret; wl_event_source_remove(sigint_source); wl_event_source_remove(sigterm_source); diff --git a/server.h b/server.h index 6e2fddf..643ac0d 100644 --- a/server.h +++ b/server.h @@ -53,6 +53,7 @@ struct cg_server { bool xdg_decoration; bool allow_vt_switch; + bool return_app_code; }; #endif From 7ec7e3df2bfc2069219285ccca676327480fa471 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Wed, 23 Aug 2023 18:40:15 +0200 Subject: [PATCH 168/233] seat: add missing touch_frame handler wl_touch::frame() is expected to be sent to client to indicate end of touch frame event and not sending it may cause issues. For example, Qt applications using Qt Wayland platform plugin do not consider touch events until this end of frame to be received. --- seat.c | 12 ++++++++++++ seat.h | 1 + 2 files changed, 13 insertions(+) diff --git a/seat.c b/seat.c index 5d80e33..80fd86a 100644 --- a/seat.c +++ b/seat.c @@ -565,6 +565,15 @@ handle_touch_motion(struct wl_listener *listener, void *data) wlr_idle_notify_activity(seat->server->idle, seat->seat); } +static void +handle_touch_frame(struct wl_listener *listener, void *data) +{ + struct cg_seat *seat = wl_container_of(listener, seat, touch_frame); + + wlr_seat_touch_notify_frame(seat->seat); + wlr_idle_notify_activity(seat->server->idle, seat->seat); +} + static void handle_cursor_frame(struct wl_listener *listener, void *data) { @@ -748,6 +757,7 @@ handle_destroy(struct wl_listener *listener, void *data) wl_list_remove(&seat->touch_down.link); wl_list_remove(&seat->touch_up.link); wl_list_remove(&seat->touch_motion.link); + wl_list_remove(&seat->touch_frame.link); wl_list_remove(&seat->request_set_cursor.link); wl_list_remove(&seat->request_set_selection.link); wl_list_remove(&seat->request_set_primary_selection.link); @@ -830,6 +840,8 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) wl_signal_add(&seat->cursor->events.touch_up, &seat->touch_up); seat->touch_motion.notify = handle_touch_motion; wl_signal_add(&seat->cursor->events.touch_motion, &seat->touch_motion); + seat->touch_frame.notify = handle_touch_frame; + wl_signal_add(&seat->cursor->events.touch_frame, &seat->touch_frame); seat->request_set_cursor.notify = handle_request_set_cursor; wl_signal_add(&seat->seat->events.request_set_cursor, &seat->request_set_cursor); diff --git a/seat.h b/seat.h index 52cbee4..19ed936 100644 --- a/seat.h +++ b/seat.h @@ -39,6 +39,7 @@ struct cg_seat { struct wl_listener touch_down; struct wl_listener touch_up; struct wl_listener touch_motion; + struct wl_listener touch_frame; struct wl_list drag_icons; struct wl_listener request_start_drag; From 96ffaa340eda9c75b3e931494d3baeeaaaa7cd10 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Mon, 28 Aug 2023 17:40:54 +0200 Subject: [PATCH 169/233] output: do not always terminate when last output is destroyed Only terminate if the last output was nested under the Wayland or X11 backend. If not, using DRM backend for example, terminating Cage when unplugging the last monitor or simply turning it off does not seem to be the right behavior. --- output.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/output.c b/output.c index 465c0ed..2d931ea 100644 --- a/output.c +++ b/output.c @@ -206,10 +206,25 @@ handle_output_layout_change(struct wl_listener *listener, void *data) update_output_manager_config(server); } +static bool +is_nested_output(struct cg_output *output) +{ + if (wlr_output_is_wl(output->wlr_output)) { + return true; + } +#if WLR_HAS_X11_BACKEND + if (wlr_output_is_x11(output->wlr_output)) { + return true; + } +#endif + return false; +} + static void output_destroy(struct cg_output *output) { struct cg_server *server = output->server; + bool was_nested_output = is_nested_output(output); output->wlr_output->data = NULL; @@ -223,7 +238,7 @@ output_destroy(struct cg_output *output) free(output); - if (wl_list_empty(&server->outputs)) { + if (wl_list_empty(&server->outputs) && was_nested_output) { wl_display_terminate(server->wl_display); } else if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST && !wl_list_empty(&server->outputs)) { struct cg_output *prev = wl_container_of(server->outputs.next, prev, link); From a769943447dbdccf5849b82ced1cde7da3b1ef38 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Fri, 1 Sep 2023 09:38:07 +0200 Subject: [PATCH 170/233] output: ensure output is marked as enabled before trying to set mode Otherwise, testing to set preferred / "best" mode will always return an error. Consequently, output will simply be configured with last and probably "worst" mode. --- output.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/output.c b/output.c index 2d931ea..94faa1e 100644 --- a/output.c +++ b/output.c @@ -287,6 +287,9 @@ handle_new_output(struct wl_listener *listener, void *data) wl_signal_add(&wlr_output->events.frame, &output->frame); if (!wl_list_empty(&wlr_output->modes)) { + /* Ensure the output is marked as enabled before trying to set mode */ + wlr_output_enable(wlr_output, true); + struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); if (preferred_mode) { wlr_output_set_mode(wlr_output, preferred_mode); From 4dc3cf80b2755a8f81cc0c5c7e0176d532f54ab4 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Tue, 12 Sep 2023 14:09:24 +0000 Subject: [PATCH 171/233] output: fix crash when re-enabling DRM output The output is disabled then re-enabled using the wlr-output-management protocol with tool such as wlr-randr. $ wlr-randr --output HDMI-A-1 --off $ wlr-randr --output HDMI-A-1 --on When re-enabled the new output configuration is committed before the output to be added to the global output layout. However, handle_output_commit() expects the output to be already part of this global layout and assert failed. Now, do not treat this in handle_output_commit() and simply ensure the resulting scene output is not NULL in handle_output_frame(). --- output.c | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/output.c b/output.c index 94faa1e..96a5086 100644 --- a/output.c +++ b/output.c @@ -68,6 +68,29 @@ update_output_manager_config(struct cg_server *server) wlr_output_manager_v1_set_configuration(server->output_manager_v1, config); } +static inline void +output_layout_add_auto(struct cg_output *output) +{ + wlr_output_layout_add_auto(output->server->output_layout, output->wlr_output); + output->scene_output = wlr_scene_get_scene_output(output->server->scene, output->wlr_output); + assert(output->scene_output != NULL); +} + +static inline void +output_layout_add(struct cg_output *output, int32_t x, int32_t y) +{ + wlr_output_layout_add(output->server->output_layout, output->wlr_output, x, y); + output->scene_output = wlr_scene_get_scene_output(output->server->scene, output->wlr_output); + assert(output->scene_output != NULL); +} + +static inline void +output_layout_remove(struct cg_output *output) +{ + wlr_output_layout_remove(output->server->output_layout, output->wlr_output); + output->scene_output = NULL; +} + static void output_enable(struct cg_output *output) { @@ -78,12 +101,11 @@ output_enable(struct cg_output *output) * duplicate the enabled property in cg_output. */ wlr_log(WLR_DEBUG, "Enabling output %s", wlr_output->name); - 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); + if (wlr_output_commit(wlr_output)) { + output_layout_add_auto(output); + } update_output_manager_config(output->server); } @@ -98,12 +120,10 @@ 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); wlr_output_commit(wlr_output); + output_layout_remove(output); } static bool @@ -136,9 +156,9 @@ output_apply_config(struct cg_output *output, struct wlr_output_configuration_he } if (head->state.enabled) { - wlr_output_layout_add(output->server->output_layout, head->state.output, head->state.x, head->state.y); + output_layout_add(output, head->state.x, head->state.y); } else { - wlr_output_layout_remove(output->server->output_layout, output->wlr_output); + output_layout_remove(output); } return true; @@ -149,7 +169,7 @@ handle_output_frame(struct wl_listener *listener, void *data) { struct cg_output *output = wl_container_of(listener, output, frame); - if (!output->wlr_output->enabled) { + if (!output->wlr_output->enabled || !output->scene_output) { return; } @@ -170,15 +190,6 @@ handle_output_commit(struct wl_listener *listener, void *data) * - output layout change will also be called if needed to position the views * - always update output manager configuration even if the output is now disabled */ - if (event->committed & WLR_OUTPUT_STATE_ENABLED) { - if (output->wlr_output->enabled) { - output->scene_output = wlr_scene_get_scene_output(output->server->scene, output->wlr_output); - assert(output->scene_output != NULL); - } else { - output->scene_output = NULL; - } - } - if (event->committed & OUTPUT_CONFIG_UPDATED) { update_output_manager_config(output->server); } @@ -234,7 +245,7 @@ output_destroy(struct cg_output *output) wl_list_remove(&output->frame.link); wl_list_remove(&output->link); - wlr_output_layout_remove(server->output_layout, output->wlr_output); + output_layout_remove(output); free(output); From efbf7c035b9271cbcd3c4dc28dc1f925872ab57d Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Wed, 8 Nov 2023 17:22:06 +0100 Subject: [PATCH 172/233] seat: move initial cursor center to dedicated function --- cage.c | 6 +----- seat.c | 9 +++++++++ seat.h | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/cage.c b/cage.c index 7a4bd9f..f0526be 100644 --- a/cage.c +++ b/cage.c @@ -579,11 +579,7 @@ main(int argc, char *argv[]) goto end; } - /* Place the cursor in the center of the output layout. */ - struct wlr_box layout_box; - wlr_output_layout_get_box(server.output_layout, NULL, &layout_box); - wlr_cursor_warp(server.seat->cursor, NULL, layout_box.width / 2, layout_box.height / 2); - + seat_center_cursor(server.seat); wl_display_run(server.wl_display); #if CAGE_HAS_XWAYLAND diff --git a/seat.c b/seat.c index 80fd86a..d456834 100644 --- a/seat.c +++ b/seat.c @@ -944,3 +944,12 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) process_cursor_motion(seat, -1); } + +void +seat_center_cursor(struct cg_seat *seat) +{ + /* Place the cursor in the center of the output layout. */ + struct wlr_box layout_box; + wlr_output_layout_get_box(seat->server->output_layout, NULL, &layout_box); + wlr_cursor_warp(seat->cursor, NULL, layout_box.width / 2, layout_box.height / 2); +} diff --git a/seat.h b/seat.h index 19ed936..b27b912 100644 --- a/seat.h +++ b/seat.h @@ -91,5 +91,6 @@ struct cg_seat *seat_create(struct cg_server *server, struct wlr_backend *backen void seat_destroy(struct cg_seat *seat); struct cg_view *seat_get_focus(struct cg_seat *seat); void seat_set_focus(struct cg_seat *seat, struct cg_view *view); +void seat_center_cursor(struct cg_seat *seat); #endif From 2ab480910e24ba73bb88878f608f3b27957cf687 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Thu, 9 Nov 2023 17:14:37 +0100 Subject: [PATCH 173/233] cage: add relative-pointer-unstable-v1 support --- cage.c | 8 ++++++++ seat.c | 35 ++++++++++++++++++++++++----------- seat.h | 2 +- server.h | 3 +++ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/cage.c b/cage.c index f0526be..4296187 100644 --- a/cage.c +++ b/cage.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -517,6 +518,13 @@ main(int argc, char *argv[]) } wl_signal_add(&virtual_pointer->events.new_virtual_pointer, &server.new_virtual_pointer); + server.relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server.wl_display); + if (!server.relative_pointer_manager) { + wlr_log(WLR_ERROR, "Unable to create the relative pointer manager"); + ret = 1; + goto end; + } + #if CAGE_HAS_XWAYLAND xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { diff --git a/seat.c b/seat.c index d456834..f67af68 100644 --- a/seat.c +++ b/seat.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -607,20 +608,25 @@ handle_cursor_button(struct wl_listener *listener, void *data) } static void -process_cursor_motion(struct cg_seat *seat, uint32_t time) +process_cursor_motion(struct cg_seat *seat, uint32_t time_msec, double dx, double dy, double dx_unaccel, + double dy_unaccel) { double sx, sy; struct wlr_seat *wlr_seat = seat->seat; struct wlr_surface *surface = NULL; struct cg_view *view = desktop_view_at(seat->server, seat->cursor->x, seat->cursor->y, &surface, &sx, &sy); - if (!view) { wlr_seat_pointer_clear_focus(wlr_seat); } else { wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(wlr_seat, time_msec, sx, sy); + } - wlr_seat_pointer_notify_motion(wlr_seat, time, sx, sy); + if (dx != 0 || dy != 0) { + wlr_relative_pointer_manager_v1_send_relative_motion(seat->server->relative_pointer_manager, wlr_seat, + (uint64_t) time_msec * 1000, dx, dy, dx_unaccel, + dy_unaccel); } struct cg_drag_icon *drag_icon; @@ -637,19 +643,26 @@ handle_cursor_motion_absolute(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_absolute); struct wlr_pointer_motion_absolute_event *event = data; + double lx, ly; + wlr_cursor_absolute_to_layout_coords(seat->cursor, &event->pointer->base, event->x, event->y, &lx, &ly); + + double dx = lx - seat->cursor->x; + double dy = ly - seat->cursor->y; + wlr_cursor_warp_absolute(seat->cursor, &event->pointer->base, event->x, event->y); - process_cursor_motion(seat, event->time_msec); + process_cursor_motion(seat, event->time_msec, dx, dy, dx, dy); wlr_idle_notify_activity(seat->server->idle, seat->seat); } static void -handle_cursor_motion(struct wl_listener *listener, void *data) +handle_cursor_motion_relative(struct wl_listener *listener, void *data) { - struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion); + struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_relative); struct wlr_pointer_motion_event *event = data; wlr_cursor_move(seat->cursor, &event->pointer->base, event->delta_x, event->delta_y); - process_cursor_motion(seat, event->time_msec); + process_cursor_motion(seat, event->time_msec, event->delta_x, event->delta_y, event->unaccel_dx, + event->unaccel_dy); wlr_idle_notify_activity(seat->server->idle, seat->seat); } @@ -749,7 +762,7 @@ handle_destroy(struct wl_listener *listener, void *data) { struct cg_seat *seat = wl_container_of(listener, seat, destroy); wl_list_remove(&seat->destroy.link); - wl_list_remove(&seat->cursor_motion.link); + wl_list_remove(&seat->cursor_motion_relative.link); wl_list_remove(&seat->cursor_motion_absolute.link); wl_list_remove(&seat->cursor_button.link); wl_list_remove(&seat->cursor_axis.link); @@ -823,8 +836,8 @@ seat_create(struct cg_server *server, struct wlr_backend *backend) } } - seat->cursor_motion.notify = handle_cursor_motion; - wl_signal_add(&seat->cursor->events.motion, &seat->cursor_motion); + seat->cursor_motion_relative.notify = handle_cursor_motion_relative; + wl_signal_add(&seat->cursor->events.motion, &seat->cursor_motion_relative); seat->cursor_motion_absolute.notify = handle_cursor_motion_absolute; wl_signal_add(&seat->cursor->events.motion_absolute, &seat->cursor_motion_absolute); seat->cursor_button.notify = handle_cursor_button; @@ -942,7 +955,7 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) wlr_seat_keyboard_notify_enter(wlr_seat, view->wlr_surface, NULL, 0, NULL); } - process_cursor_motion(seat, -1); + process_cursor_motion(seat, -1, 0, 0, 0, 0); } void diff --git a/seat.h b/seat.h index b27b912..4b7bfda 100644 --- a/seat.h +++ b/seat.h @@ -27,7 +27,7 @@ struct cg_seat { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; - struct wl_listener cursor_motion; + struct wl_listener cursor_motion_relative; struct wl_listener cursor_motion_absolute; struct wl_listener cursor_button; struct wl_listener cursor_axis; diff --git a/server.h b/server.h index 643ac0d..de58456 100644 --- a/server.h +++ b/server.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #if CAGE_HAS_XWAYLAND #include @@ -51,6 +52,8 @@ struct cg_server { struct wl_listener output_manager_apply; struct wl_listener output_manager_test; + struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; + bool xdg_decoration; bool allow_vt_switch; bool return_app_code; From d40dd3bd994eab8bd6258d0cb401eddc3b33e53a Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Thu, 9 Nov 2023 17:27:32 +0100 Subject: [PATCH 174/233] cage: remove not really used variables in server initialization --- cage.c | 76 ++++++++++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/cage.c b/cage.c index 4296187..f78a03f 100644 --- a/cage.c +++ b/cage.c @@ -261,29 +261,7 @@ int main(int argc, char *argv[]) { struct cg_server server = {0}; - struct wl_event_loop *event_loop = NULL; - struct wl_event_source *sigint_source = NULL; - struct wl_event_source *sigterm_source = NULL; struct wl_event_source *sigchld_source = NULL; - struct wlr_compositor *compositor = NULL; - struct wlr_subcompositor *subcompositor = NULL; - struct wlr_data_device_manager *data_device_manager = NULL; - struct wlr_server_decoration_manager *server_decoration_manager = NULL; - struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL; - struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL; - struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; - struct wlr_single_pixel_buffer_manager_v1 *single_pixel_buffer = NULL; - struct wlr_xdg_output_manager_v1 *output_manager = NULL; - struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; - struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard = NULL; - struct wlr_virtual_pointer_manager_v1 *virtual_pointer = NULL; - struct wlr_viewporter *viewporter = NULL; - struct wlr_presentation *presentation = NULL; - struct wlr_xdg_shell *xdg_shell = NULL; -#if CAGE_HAS_XWAYLAND - struct wlr_xwayland *xwayland = NULL; - struct wlr_xcursor_manager *xcursor_manager = NULL; -#endif pid_t pid = 0; int ret = 0, app_ret = 0; @@ -309,9 +287,11 @@ main(int argc, char *argv[]) return 1; } - event_loop = wl_display_get_event_loop(server.wl_display); - sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); - sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); + struct wl_event_loop *event_loop = wl_display_get_event_loop(server.wl_display); + struct wl_event_source *sigint_source = + wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); + struct wl_event_source *sigterm_source = + wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); server.backend = wlr_backend_autocreate(server.wl_display); if (!server.backend) { @@ -362,22 +342,20 @@ main(int argc, char *argv[]) wlr_scene_attach_output_layout(server.scene, server.output_layout); - compositor = wlr_compositor_create(server.wl_display, server.renderer); + struct wlr_compositor *compositor = wlr_compositor_create(server.wl_display, server.renderer); if (!compositor) { wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); ret = 1; goto end; } - subcompositor = wlr_subcompositor_create(server.wl_display); - if (!subcompositor) { + if (!wlr_subcompositor_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the wlroots subcompositor"); ret = 1; goto end; } - data_device_manager = wlr_data_device_manager_create(server.wl_display); - if (!data_device_manager) { + if (!wlr_data_device_manager_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the data device manager"); ret = 1; goto end; @@ -413,7 +391,7 @@ main(int argc, char *argv[]) wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1); wl_list_init(&server.inhibitors); - xdg_shell = wlr_xdg_shell_create(server.wl_display, 4); + struct wlr_xdg_shell *xdg_shell = wlr_xdg_shell_create(server.wl_display, 4); if (!xdg_shell) { wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); ret = 1; @@ -422,7 +400,8 @@ main(int argc, char *argv[]) server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; wl_signal_add(&xdg_shell->events.new_surface, &server.new_xdg_shell_surface); - xdg_decoration_manager = wlr_xdg_decoration_manager_v1_create(server.wl_display); + struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = + wlr_xdg_decoration_manager_v1_create(server.wl_display); if (!xdg_decoration_manager) { wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager"); ret = 1; @@ -431,7 +410,8 @@ main(int argc, char *argv[]) wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, &server.xdg_toplevel_decoration); server.xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; - server_decoration_manager = wlr_server_decoration_manager_create(server.wl_display); + struct wlr_server_decoration_manager *server_decoration_manager = + wlr_server_decoration_manager_create(server.wl_display); if (!server_decoration_manager) { wlr_log(WLR_ERROR, "Unable to create the server decoration manager"); ret = 1; @@ -441,14 +421,13 @@ 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) { + if (!wlr_viewporter_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the viewporter interface"); ret = 1; goto end; } - presentation = wlr_presentation_create(server.wl_display, server.backend); + struct wlr_presentation *presentation = wlr_presentation_create(server.wl_display, server.backend); if (!presentation) { wlr_log(WLR_ERROR, "Unable to create the presentation interface"); ret = 1; @@ -456,29 +435,25 @@ main(int argc, char *argv[]) } wlr_scene_set_presentation(server.scene, presentation); - export_dmabuf_manager = wlr_export_dmabuf_manager_v1_create(server.wl_display); - if (!export_dmabuf_manager) { + if (!wlr_export_dmabuf_manager_v1_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); ret = 1; goto end; } - screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display); - if (!screencopy_manager) { + if (!wlr_screencopy_manager_v1_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the screencopy manager"); ret = 1; goto end; } - single_pixel_buffer = wlr_single_pixel_buffer_manager_v1_create(server.wl_display); - if (!single_pixel_buffer) { + if (!wlr_single_pixel_buffer_manager_v1_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the single pixel buffer manager"); ret = 1; goto end; } - output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout); - if (!output_manager) { + if (!wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout)) { wlr_log(WLR_ERROR, "Unable to create the output manager"); ret = 1; goto end; @@ -495,14 +470,14 @@ main(int argc, char *argv[]) server.output_manager_test.notify = handle_output_manager_test; wl_signal_add(&server.output_manager_v1->events.test, &server.output_manager_test); - gamma_control_manager = wlr_gamma_control_manager_v1_create(server.wl_display); - if (!gamma_control_manager) { + if (!wlr_gamma_control_manager_v1_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); ret = 1; goto end; } - virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(server.wl_display); + struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard = + wlr_virtual_keyboard_manager_v1_create(server.wl_display); if (!virtual_keyboard) { wlr_log(WLR_ERROR, "Unable to create the virtual keyboard manager"); ret = 1; @@ -510,7 +485,8 @@ main(int argc, char *argv[]) } wl_signal_add(&virtual_keyboard->events.new_virtual_keyboard, &server.new_virtual_keyboard); - virtual_pointer = wlr_virtual_pointer_manager_v1_create(server.wl_display); + struct wlr_virtual_pointer_manager_v1 *virtual_pointer = + wlr_virtual_pointer_manager_v1_create(server.wl_display); if (!virtual_pointer) { wlr_log(WLR_ERROR, "Unable to create the virtual pointer manager"); ret = 1; @@ -526,7 +502,7 @@ main(int argc, char *argv[]) } #if CAGE_HAS_XWAYLAND - xwayland = wlr_xwayland_create(server.wl_display, compositor, true); + struct wlr_xwayland *xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { wlr_log(WLR_ERROR, "Cannot create XWayland server"); ret = 1; @@ -535,7 +511,7 @@ main(int argc, char *argv[]) server.new_xwayland_surface.notify = handle_xwayland_surface_new; wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); - xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); + struct wlr_xcursor_manager *xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); if (!xcursor_manager) { wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); ret = 1; From 1f3e3043dd08609ec50ef81363a8a41df9826d0a Mon Sep 17 00:00:00 2001 From: Moon Sungjoon Date: Wed, 22 Nov 2023 14:41:00 +0800 Subject: [PATCH 175/233] CI: Set `fail-fast' to false This allows other jobs to continue running even if one job fails --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a98291a..0991ad4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,6 +9,7 @@ jobs: compile: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: CC: [ gcc, clang ] OS: [ "alpine:edge", "archlinux:base-devel" ] From 34eb3ec2c81fde3349eed63daba8b244b0bfd46f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 27 Nov 2023 00:17:36 +0100 Subject: [PATCH 176/233] Make Xwayland optional at runtime Closes: https://github.com/cage-kiosk/cage/issues/293 --- cage.c | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/cage.c b/cage.c index f78a03f..af2fc4f 100644 --- a/cage.c +++ b/cage.c @@ -502,36 +502,37 @@ main(int argc, char *argv[]) } #if CAGE_HAS_XWAYLAND + struct wlr_xcursor_manager *xcursor_manager = NULL; struct wlr_xwayland *xwayland = wlr_xwayland_create(server.wl_display, compositor, true); if (!xwayland) { wlr_log(WLR_ERROR, "Cannot create XWayland server"); - ret = 1; - goto end; - } - server.new_xwayland_surface.notify = handle_xwayland_surface_new; - wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); - - struct wlr_xcursor_manager *xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); - if (!xcursor_manager) { - wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); - ret = 1; - goto end; - } - - if (setenv("DISPLAY", xwayland->display_name, true) < 0) { - wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland. Clients may not be able to connect"); } else { - wlr_log(WLR_DEBUG, "XWayland is running on display %s", xwayland->display_name); - } + server.new_xwayland_surface.notify = handle_xwayland_surface_new; + wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); - if (!wlr_xcursor_manager_load(xcursor_manager, 1)) { - wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); - } - struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); - if (xcursor) { - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, image->width, image->height, - image->hotspot_x, image->hotspot_y); + xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); + if (!xcursor_manager) { + wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); + ret = 1; + goto end; + } + + if (setenv("DISPLAY", xwayland->display_name, true) < 0) { + wlr_log_errno(WLR_ERROR, + "Unable to set DISPLAY for XWayland. Clients may not be able to connect"); + } else { + wlr_log(WLR_DEBUG, "XWayland is running on display %s", xwayland->display_name); + } + + if (!wlr_xcursor_manager_load(xcursor_manager, 1)) { + wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); + } + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); + if (xcursor) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4, image->width, image->height, + image->hotspot_x, image->hotspot_y); + } } #endif @@ -555,7 +556,9 @@ main(int argc, char *argv[]) } #if CAGE_HAS_XWAYLAND - wlr_xwayland_set_seat(xwayland, server.seat->seat); + if (xwayland) { + wlr_xwayland_set_seat(xwayland, server.seat->seat); + } #endif if (!spawn_primary_client(&server, argv + optind, &pid, &sigchld_source)) { From 624355485a6ca865e9237b2f9366764b7dda52c4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:36:49 +0200 Subject: [PATCH 177/233] Use new wlr_backend_autocreate signature The session is now stored explicitly, with wlr_backend_get_session being dropped. --- cage.c | 2 +- seat.c | 6 +++--- server.h | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cage.c b/cage.c index af2fc4f..53d1e35 100644 --- a/cage.c +++ b/cage.c @@ -293,7 +293,7 @@ main(int argc, char *argv[]) struct wl_event_source *sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); - server.backend = wlr_backend_autocreate(server.wl_display); + server.backend = wlr_backend_autocreate(server.wl_display, &server.session); if (!server.backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); ret = 1; diff --git a/seat.c b/seat.c index f67af68..d047b59 100644 --- a/seat.c +++ b/seat.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -263,10 +264,9 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) #endif if (server->allow_vt_switch && sym >= XKB_KEY_XF86Switch_VT_1 && sym <= XKB_KEY_XF86Switch_VT_12) { if (wlr_backend_is_multi(server->backend)) { - struct wlr_session *session = wlr_backend_get_session(server->backend); - if (session) { + if (server->session) { unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1; - wlr_session_change_vt(session, vt); + wlr_session_change_vt(server->session, vt); } } } else { diff --git a/server.h b/server.h index de58456..fef4b5e 100644 --- a/server.h +++ b/server.h @@ -24,6 +24,7 @@ struct cg_server { struct wlr_backend *backend; struct wlr_renderer *renderer; struct wlr_allocator *allocator; + struct wlr_session *session; struct cg_seat *seat; struct wlr_idle *idle; From 64e2a44124db6e19733784581a9de93a39dc8ca7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:37:58 +0200 Subject: [PATCH 178/233] output: Remove wlr_output_damage include --- output.c | 1 - output.h | 1 - 2 files changed, 2 deletions(-) diff --git a/output.c b/output.c index 96a5086..f5d0992 100644 --- a/output.c +++ b/output.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/output.h b/output.h index 4783fd1..780930e 100644 --- a/output.h +++ b/output.h @@ -3,7 +3,6 @@ #include #include -#include #include "server.h" #include "view.h" From b772a00df8449e6bbd7474ec338e101657cb60f7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:38:29 +0200 Subject: [PATCH 179/233] output: Call wlr_scene_output_create --- output.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/output.c b/output.c index f5d0992..8bf8b59 100644 --- a/output.c +++ b/output.c @@ -70,24 +70,21 @@ update_output_manager_config(struct cg_server *server) static inline void output_layout_add_auto(struct cg_output *output) { - wlr_output_layout_add_auto(output->server->output_layout, output->wlr_output); - output->scene_output = wlr_scene_get_scene_output(output->server->scene, output->wlr_output); assert(output->scene_output != NULL); + wlr_output_layout_add_auto(output->server->output_layout, output->wlr_output); } static inline void output_layout_add(struct cg_output *output, int32_t x, int32_t y) { - wlr_output_layout_add(output->server->output_layout, output->wlr_output, x, y); - output->scene_output = wlr_scene_get_scene_output(output->server->scene, output->wlr_output); assert(output->scene_output != NULL); + wlr_output_layout_add(output->server->output_layout, output->wlr_output, x, y); } static inline void output_layout_remove(struct cg_output *output) { wlr_output_layout_remove(output->server->output_layout, output->wlr_output); - output->scene_output = NULL; } static void @@ -296,6 +293,12 @@ handle_new_output(struct wl_listener *listener, void *data) output->frame.notify = handle_output_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); + output->scene_output = wlr_scene_output_create(server->scene, wlr_output); + if (!output->scene_output) { + wlr_log(WLR_ERROR, "Failed to allocate scene output"); + return; + } + if (!wl_list_empty(&wlr_output->modes)) { /* Ensure the output is marked as enabled before trying to set mode */ wlr_output_enable(wlr_output, true); From b51a6e950fdc7a448be4efce12488e5641eef75d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:39:36 +0200 Subject: [PATCH 180/233] output: wlr_scene_output_commit NULL options --- output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output.c b/output.c index 8bf8b59..733e194 100644 --- a/output.c +++ b/output.c @@ -169,7 +169,7 @@ handle_output_frame(struct wl_listener *listener, void *data) return; } - wlr_scene_output_commit(output->scene_output); + wlr_scene_output_commit(output->scene_output, NULL); struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC, &now); From 2f7ab094d4ef8711ee418b5a06f566a3e7a91cf3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:39:53 +0200 Subject: [PATCH 181/233] output: Remove output mode handler This is replaced by monitoring for WLR_OUTPUT_STATE_MODE on commit. --- output.c | 18 +----------------- output.h | 1 - 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/output.c b/output.c index 733e194..599d6ad 100644 --- a/output.c +++ b/output.c @@ -42,7 +42,7 @@ #endif #define OUTPUT_CONFIG_UPDATED \ - (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_SCALE | WLR_OUTPUT_STATE_TRANSFORM | \ + (WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_SCALE | WLR_OUTPUT_STATE_TRANSFORM | \ WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) static void @@ -191,19 +191,6 @@ handle_output_commit(struct wl_listener *listener, void *data) } } -static void -handle_output_mode(struct wl_listener *listener, void *data) -{ - struct cg_output *output = wl_container_of(listener, output, mode); - - if (!output->wlr_output->enabled) { - return; - } - - view_position_all(output->server); - update_output_manager_config(output->server); -} - void handle_output_layout_change(struct wl_listener *listener, void *data) { @@ -237,7 +224,6 @@ output_destroy(struct cg_output *output) wl_list_remove(&output->destroy.link); wl_list_remove(&output->commit.link); - wl_list_remove(&output->mode.link); wl_list_remove(&output->frame.link); wl_list_remove(&output->link); @@ -286,8 +272,6 @@ handle_new_output(struct wl_listener *listener, void *data) output->commit.notify = handle_output_commit; wl_signal_add(&wlr_output->events.commit, &output->commit); - output->mode.notify = handle_output_mode; - 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->frame.notify = handle_output_frame; diff --git a/output.h b/output.h index 780930e..a3a1a4c 100644 --- a/output.h +++ b/output.h @@ -13,7 +13,6 @@ struct cg_output { struct wlr_scene_output *scene_output; struct wl_listener commit; - struct wl_listener mode; struct wl_listener destroy; struct wl_listener frame; From 8df120dafdcfbcec4b3f217615cd8df86a77a97c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 21 Nov 2023 19:28:06 +0100 Subject: [PATCH 182/233] output: Use state field in wlr_output_event_commit --- output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output.c b/output.c index 599d6ad..7ca7bb7 100644 --- a/output.c +++ b/output.c @@ -186,7 +186,7 @@ handle_output_commit(struct wl_listener *listener, void *data) * - output layout change will also be called if needed to position the views * - always update output manager configuration even if the output is now disabled */ - if (event->committed & OUTPUT_CONFIG_UPDATED) { + if (event->state->committed & OUTPUT_CONFIG_UPDATED) { update_output_manager_config(output->server); } } From 4ea6a8b1a79a4d1fa94d17885b70ae8a64157ea3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:40:21 +0200 Subject: [PATCH 183/233] shell: Use new try_from surface getters --- seat.c | 2 +- xdg_shell.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/seat.c b/seat.c index d047b59..5e1beaf 100644 --- a/seat.c +++ b/seat.c @@ -65,7 +65,7 @@ desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surfa } struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_buffer(scene_buffer); + struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); if (!scene_surface) { return NULL; } diff --git a/xdg_shell.c b/xdg_shell.c index c577dc5..9d75b84 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -46,11 +46,13 @@ static struct cg_view * popup_get_view(struct wlr_xdg_popup *popup) { while (true) { - if (popup->parent == NULL || !wlr_surface_is_xdg_surface(popup->parent)) { + if (popup->parent == NULL) { + return NULL; + } + struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_try_from_wlr_surface(popup->parent); + if (xdg_surface == NULL) { return NULL; } - - 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; @@ -254,7 +256,10 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) } struct wlr_scene_tree *parent_scene_tree = NULL; - struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent); + struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(popup->parent); + if (parent == NULL) { + return; + } switch (parent->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; parent_scene_tree = view->scene_tree; From 2d4b7a4e233c989f0555c8a3ca88a3cabffa0a84 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:40:33 +0200 Subject: [PATCH 184/233] shell: Use new map/unmap events For xwayland we must listen on associate/dissociate to set up and tear down the map/unmap event handlers instead of during surface create/destroy. --- xdg_shell.c | 4 ++-- xwayland.c | 39 +++++++++++++++++++++++++++++++++------ xwayland.h | 2 ++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index 9d75b84..046dbd8 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -238,9 +238,9 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) xdg_shell_view->xdg_toplevel = xdg_surface->toplevel; xdg_shell_view->map.notify = handle_xdg_shell_surface_map; - wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); + wl_signal_add(&xdg_surface->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); + wl_signal_add(&xdg_surface->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; diff --git a/xwayland.c b/xwayland.c index ef37a49..eec7fb9 100644 --- a/xwayland.c +++ b/xwayland.c @@ -41,8 +41,15 @@ static void get_geometry(struct cg_view *view, int *width_out, int *height_out) { struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); - *width_out = xwayland_view->xwayland_surface->surface->current.width; - *height_out = xwayland_view->xwayland_surface->surface->current.height; + struct wlr_xwayland_surface *xsurface = xwayland_view->xwayland_surface; + if (xsurface->surface == NULL) { + *width_out = 0; + *height_out = 0; + return; + } + + *width_out = xsurface->surface->current.width; + *height_out = xsurface->surface->current.height; } static bool @@ -151,6 +158,26 @@ static const struct cg_view_impl xwayland_view_impl = { .destroy = destroy, }; +void +handle_xwayland_associate(struct wl_listener *listener, void *data) +{ + struct cg_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, associate); + struct wlr_xwayland_surface *xsurface = xwayland_view->xwayland_surface; + + xwayland_view->map.notify = handle_xwayland_surface_map; + wl_signal_add(&xsurface->surface->events.map, &xwayland_view->map); + xwayland_view->unmap.notify = handle_xwayland_surface_unmap; + wl_signal_add(&xsurface->surface->events.unmap, &xwayland_view->unmap); +} + +void +handle_xwayland_dissociate(struct wl_listener *listener, void *data) +{ + struct cg_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, dissociate); + wl_list_remove(&xwayland_view->map.link); + wl_list_remove(&xwayland_view->unmap.link); +} + void handle_xwayland_surface_new(struct wl_listener *listener, void *data) { @@ -166,10 +193,10 @@ handle_xwayland_surface_new(struct wl_listener *listener, void *data) view_init(&xwayland_view->view, server, CAGE_XWAYLAND_VIEW, &xwayland_view_impl); xwayland_view->xwayland_surface = xwayland_surface; - xwayland_view->map.notify = handle_xwayland_surface_map; - wl_signal_add(&xwayland_surface->events.map, &xwayland_view->map); - xwayland_view->unmap.notify = handle_xwayland_surface_unmap; - wl_signal_add(&xwayland_surface->events.unmap, &xwayland_view->unmap); + xwayland_view->associate.notify = handle_xwayland_associate; + wl_signal_add(&xwayland_surface->events.associate, &xwayland_view->associate); + xwayland_view->dissociate.notify = handle_xwayland_dissociate; + wl_signal_add(&xwayland_surface->events.dissociate, &xwayland_view->dissociate); xwayland_view->destroy.notify = handle_xwayland_surface_destroy; wl_signal_add(&xwayland_surface->events.destroy, &xwayland_view->destroy); xwayland_view->request_fullscreen.notify = handle_xwayland_surface_request_fullscreen; diff --git a/xwayland.h b/xwayland.h index 31edb8f..bca4b02 100644 --- a/xwayland.h +++ b/xwayland.h @@ -10,6 +10,8 @@ struct cg_xwayland_view { struct cg_view view; struct wlr_xwayland_surface *xwayland_surface; struct wl_listener destroy; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener unmap; struct wl_listener map; struct wl_listener request_fullscreen; From b55e40ad9dcd6d9488d4c56ee8ca9582d5d5df0e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:40:54 +0200 Subject: [PATCH 185/233] seat: New cursor/xcursor interface --- seat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seat.c b/seat.c index 5e1beaf..fed1292 100644 --- a/seat.c +++ b/seat.c @@ -128,9 +128,9 @@ update_capabilities(struct cg_seat *seat) /* Hide cursor if the seat doesn't have pointer capability. */ if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) { - wlr_cursor_set_image(seat->cursor, NULL, 0, 0, 0, 0, 0, 0); + wlr_cursor_unset_image(seat->cursor); } else { - wlr_xcursor_manager_set_cursor_image(seat->xcursor_manager, DEFAULT_XCURSOR, seat->cursor); + wlr_cursor_set_xcursor(seat->cursor, seat->xcursor_manager, DEFAULT_XCURSOR); } } From a30f2bcec18623ff9a11261bccea37daf80a0746 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 30 Sep 2023 13:41:07 +0200 Subject: [PATCH 186/233] Use new wlr_compositor_create signature --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 53d1e35..7d9f248 100644 --- a/cage.c +++ b/cage.c @@ -342,7 +342,7 @@ main(int argc, char *argv[]) wlr_scene_attach_output_layout(server.scene, server.output_layout); - struct wlr_compositor *compositor = wlr_compositor_create(server.wl_display, server.renderer); + struct wlr_compositor *compositor = wlr_compositor_create(server.wl_display, 6, server.renderer); if (!compositor) { wlr_log(WLR_ERROR, "Unable to create the wlroots compositor"); ret = 1; From 1ff7945ba1fef9f280f70d21f8e45396f7fe517c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 21 Nov 2023 19:20:13 +0100 Subject: [PATCH 187/233] Switch from wlr_idle to wlr_idle_notify_v1 The latter implemented the KDE protocol which has been dropped. --- cage.c | 4 ++-- idle_inhibit_v1.c | 4 ++-- seat.c | 28 ++++++++++++++-------------- server.h | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/cage.c b/cage.c index 7d9f248..9e6eb13 100644 --- a/cage.c +++ b/cage.c @@ -25,8 +25,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -374,7 +374,7 @@ main(int argc, char *argv[]) goto end; } - server.idle = wlr_idle_create(server.wl_display); + server.idle = wlr_idle_notifier_v1_create(server.wl_display); if (!server.idle) { wlr_log(WLR_ERROR, "Unable to create the idle tracker"); ret = 1; diff --git a/idle_inhibit_v1.c b/idle_inhibit_v1.c index 5aba865..683cfe2 100644 --- a/idle_inhibit_v1.c +++ b/idle_inhibit_v1.c @@ -8,8 +8,8 @@ #include #include -#include #include +#include #include "idle_inhibit_v1.h" #include "server.h" @@ -32,7 +32,7 @@ idle_inhibit_v1_check_active(struct cg_server *server) Hence, we simply check for any inhibitors and inhibit accordingly. */ bool inhibited = !wl_list_empty(&server->inhibitors); - wlr_idle_set_enabled(server->idle, NULL, !inhibited); + wlr_idle_notifier_v1_set_inhibited(server->idle, inhibited); } static void diff --git a/seat.c b/seat.c index fed1292..8008dd9 100644 --- a/seat.c +++ b/seat.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -250,7 +250,7 @@ handle_modifier_event(struct wlr_keyboard *keyboard, struct cg_seat *seat) wlr_seat_set_keyboard(seat->seat, keyboard); wlr_seat_keyboard_notify_modifiers(seat->seat, &keyboard->modifiers); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static bool @@ -272,7 +272,7 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) } else { return false; } - wlr_idle_notify_activity(server->idle, server->seat->seat); + wlr_idle_notifier_v1_notify_activity(server->idle, server->seat->seat); return true; } @@ -304,7 +304,7 @@ handle_key_event(struct wlr_keyboard *keyboard, struct cg_seat *seat, void *data wlr_seat_keyboard_notify_key(seat->seat, event->time_msec, event->keycode, event->state); } - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -512,7 +512,7 @@ handle_touch_down(struct wl_listener *listener, void *data) press_cursor_button(seat, &event->touch->base, event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED, lx, ly); } - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -531,7 +531,7 @@ handle_touch_up(struct wl_listener *listener, void *data) } wlr_seat_touch_notify_up(seat->seat, event->time_msec, event->touch_id); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -563,7 +563,7 @@ handle_touch_motion(struct wl_listener *listener, void *data) seat->touch_ly = ly; } - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -572,7 +572,7 @@ handle_touch_frame(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, touch_frame); wlr_seat_touch_notify_frame(seat->seat); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -581,7 +581,7 @@ handle_cursor_frame(struct wl_listener *listener, void *data) struct cg_seat *seat = wl_container_of(listener, seat, cursor_frame); wlr_seat_pointer_notify_frame(seat->seat); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -592,7 +592,7 @@ handle_cursor_axis(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, event->source); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -604,7 +604,7 @@ handle_cursor_button(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state); press_cursor_button(seat, &event->pointer->base, event->time_msec, event->button, event->state, seat->cursor->x, seat->cursor->y); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -634,7 +634,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time_msec, double dx, doubl drag_icon_update_position(drag_icon); } - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -651,7 +651,7 @@ handle_cursor_motion_absolute(struct wl_listener *listener, void *data) wlr_cursor_warp_absolute(seat->cursor, &event->pointer->base, event->x, event->y); process_cursor_motion(seat, event->time_msec, dx, dy, dx, dy); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void @@ -663,7 +663,7 @@ handle_cursor_motion_relative(struct wl_listener *listener, void *data) wlr_cursor_move(seat->cursor, &event->pointer->base, event->delta_x, event->delta_y); process_cursor_motion(seat, event->time_msec, event->delta_x, event->delta_y, event->unaccel_dx, event->unaccel_dy); - wlr_idle_notify_activity(seat->server->idle, seat->seat); + wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } static void diff --git a/server.h b/server.h index fef4b5e..c346f7a 100644 --- a/server.h +++ b/server.h @@ -4,8 +4,8 @@ #include "config.h" #include -#include #include +#include #include #include #include @@ -27,7 +27,7 @@ struct cg_server { struct wlr_session *session; struct cg_seat *seat; - struct wlr_idle *idle; + struct wlr_idle_notifier_v1 *idle; struct wlr_idle_inhibit_manager_v1 *idle_inhibit_v1; struct wl_listener new_idle_inhibitor_v1; struct wl_list inhibitors; From c801544d6144b396e7a7601b2d9108b4e5fbee61 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Nov 2023 17:30:59 +0100 Subject: [PATCH 188/233] meson: Convert xwayland option to feature type wlroots as a subproject now yields the xwayland meson option to its parent. We need to match the type for this to work. This also adds support for auto mode, where xwayland is used if present but no warning is given otherwise. --- .github/workflows/main.yml | 6 +++--- meson.build | 4 ++-- meson_options.txt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0991ad4..78cf1b0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: matrix: CC: [ gcc, clang ] OS: [ "alpine:edge", "archlinux:base-devel" ] - xwayland: [ true, false ] + xwayland: [ enabled, disabled ] container: ${{ matrix.OS }} env: CC: ${{ matrix.CC }} @@ -54,7 +54,7 @@ jobs: run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 - name: Check for formatting changes run: | - meson build-clang-format -Dxwayland=true + meson build-clang-format -Dxwayland=enabled ninja -C build-clang-format clang-format-check scan-build: @@ -73,5 +73,5 @@ jobs: run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 - name: Run scan-build run: | - meson build-scan-build -Dxwayland=true + meson build-scan-build -Dxwayland=enabled ninja -C build-scan-build scan-build diff --git a/meson.build b/meson.build index fd84262..d38b4d1 100644 --- a/meson.build +++ b/meson.build @@ -64,9 +64,9 @@ server_protos = declare_dependency( sources: server_protos_headers, ) -if get_option('xwayland') +if not get_option('xwayland').disabled() wlroots_has_xwayland = wlroots.get_variable(pkgconfig: 'have_xwayland', internal: 'have_xwayland') == 'true' - if not wlroots_has_xwayland + if get_option('xwayland').enabled() and not wlroots_has_xwayland error('Cannot build Cage with XWayland support: wlroots has been built without it') endif have_xwayland = true diff --git a/meson_options.txt b/meson_options.txt index 22055dc..d64f510 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1,2 @@ option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') -option('xwayland', type: 'boolean', value: false, description: 'Enable support for X11 applications') +option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') From 67def26d83ba3790f0e83cd84865128344ee1222 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Nov 2023 17:43:01 +0100 Subject: [PATCH 189/233] ci: Fix Alpine xwayland dependency --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 78cf1b0..e4987c3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,7 @@ jobs: - name: Install dependencies (Alpine) if: "matrix.OS == 'alpine:edge'" - run: apk add build-base xcb-util-wm-dev libseat-dev clang git eudev-dev mesa-dev libdrm-dev libinput-dev libxkbcommon-dev pixman-dev wayland-dev meson wayland-protocols xwayland scdoc-doc hwdata + 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-dev scdoc-doc hwdata - name: Install dependencies (Arch) if: "matrix.OS == 'archlinux:base-devel'" From b40be06da20e05f8c28971e7696a78018a22147b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Nov 2023 05:34:28 +0100 Subject: [PATCH 190/233] ci: Upgrade wlroots to 0.17 --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e4987c3..ecb0dc7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 # TODO: use --fatal-meson-warnings when on wlroots 0.15.0 - name: Compile Cage (XWayland=${{ matrix.xwayland }}) @@ -51,7 +51,7 @@ jobs: pacman-key --init pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 - name: Check for formatting changes run: | meson build-clang-format -Dxwayland=enabled @@ -70,7 +70,7 @@ jobs: pacman-key --init pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.16.0 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 - name: Run scan-build run: | meson build-scan-build -Dxwayland=enabled From c9d2f3afac640a5b89daef24fa4fae39c85c9c7a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Nov 2023 05:34:38 +0100 Subject: [PATCH 191/233] meson: Bump minimum wlroots to 0.17 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d38b4d1..45b3f91 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.16.0', fallback: ['wlroots', 'wlroots']) +wlroots = dependency('wlroots', version: '>= 0.17.0', fallback: ['wlroots', 'wlroots']) wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') xkbcommon = dependency('xkbcommon') From 63c0887664975918e4f476f649d4c694d4f503a9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 25 Nov 2023 12:29:57 +0100 Subject: [PATCH 192/233] output: Implement request_state event listener wlroots backends no longer change state on their own, and instead send a request_state event. Monitor this event and apply any state we receive. --- output.c | 14 ++++++++++++++ output.h | 1 + 2 files changed, 15 insertions(+) diff --git a/output.c b/output.c index 7ca7bb7..63b812f 100644 --- a/output.c +++ b/output.c @@ -191,6 +191,17 @@ handle_output_commit(struct wl_listener *listener, void *data) } } +static void +handle_output_request_state(struct wl_listener *listener, void *data) +{ + struct cg_output *output = wl_container_of(listener, output, request_state); + struct wlr_output_event_request_state *event = data; + + if (wlr_output_commit_state(output->wlr_output, event->state)) { + update_output_manager_config(output->server); + } +} + void handle_output_layout_change(struct wl_listener *listener, void *data) { @@ -224,6 +235,7 @@ output_destroy(struct cg_output *output) wl_list_remove(&output->destroy.link); wl_list_remove(&output->commit.link); + wl_list_remove(&output->request_state.link); wl_list_remove(&output->frame.link); wl_list_remove(&output->link); @@ -272,6 +284,8 @@ handle_new_output(struct wl_listener *listener, void *data) output->commit.notify = handle_output_commit; wl_signal_add(&wlr_output->events.commit, &output->commit); + output->request_state.notify = handle_output_request_state; + wl_signal_add(&wlr_output->events.request_state, &output->request_state); output->destroy.notify = handle_output_destroy; wl_signal_add(&wlr_output->events.destroy, &output->destroy); output->frame.notify = handle_output_frame; diff --git a/output.h b/output.h index a3a1a4c..fa72545 100644 --- a/output.h +++ b/output.h @@ -13,6 +13,7 @@ struct cg_output { struct wlr_scene_output *scene_output; struct wl_listener commit; + struct wl_listener request_state; struct wl_listener destroy; struct wl_listener frame; From f0bc13bef715559674bd8828442aaf3c470ee5e3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 25 Nov 2023 12:48:30 +0100 Subject: [PATCH 193/233] output: Add scene output layout helper manually --- cage.c | 2 +- output.c | 8 ++++++-- server.h | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cage.c b/cage.c index 9e6eb13..3da875d 100644 --- a/cage.c +++ b/cage.c @@ -340,7 +340,7 @@ main(int argc, char *argv[]) goto end; } - wlr_scene_attach_output_layout(server.scene, server.output_layout); + server.scene_output_layout = wlr_scene_attach_output_layout(server.scene, server.output_layout); struct wlr_compositor *compositor = wlr_compositor_create(server.wl_display, 6, server.renderer); if (!compositor) { diff --git a/output.c b/output.c index 63b812f..25e2e10 100644 --- a/output.c +++ b/output.c @@ -71,14 +71,18 @@ static inline void output_layout_add_auto(struct cg_output *output) { assert(output->scene_output != NULL); - wlr_output_layout_add_auto(output->server->output_layout, output->wlr_output); + struct wlr_output_layout_output *layout_output = + wlr_output_layout_add_auto(output->server->output_layout, output->wlr_output); + wlr_scene_output_layout_add_output(output->server->scene_output_layout, layout_output, output->scene_output); } static inline void output_layout_add(struct cg_output *output, int32_t x, int32_t y) { assert(output->scene_output != NULL); - wlr_output_layout_add(output->server->output_layout, output->wlr_output, x, y); + struct wlr_output_layout_output *layout_output = + wlr_output_layout_add(output->server->output_layout, output->wlr_output, x, y); + wlr_scene_output_layout_add_output(output->server->scene_output_layout, layout_output, output->scene_output); } static inline void diff --git a/server.h b/server.h index c346f7a..9bf4430 100644 --- a/server.h +++ b/server.h @@ -34,6 +34,8 @@ struct cg_server { enum cg_multi_output_mode output_mode; struct wlr_output_layout *output_layout; + struct wlr_scene_output_layout *scene_output_layout; + struct wlr_scene *scene; /* Includes disabled outputs; depending on the output_mode * some outputs may be disabled. */ From 8a009212bcc7d7766e1f1601605a3ae923a84b1a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 13 Dec 2023 15:37:15 +0100 Subject: [PATCH 194/233] output: Transition to wlr_output_state We previously used the wlr_output's built-in pending state and wlr_output_rollback. The modern state API is much nicer. --- output.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/output.c b/output.c index 25e2e10..714c828 100644 --- a/output.c +++ b/output.c @@ -101,9 +101,10 @@ output_enable(struct cg_output *output) * duplicate the enabled property in cg_output. */ wlr_log(WLR_DEBUG, "Enabling output %s", wlr_output->name); - wlr_output_enable(wlr_output, true); + struct wlr_output_state state = {0}; + wlr_output_state_set_enabled(&state, true); - if (wlr_output_commit(wlr_output)) { + if (wlr_output_commit_state(wlr_output, &state)) { output_layout_add_auto(output); } @@ -114,44 +115,45 @@ static void output_disable(struct cg_output *output) { struct wlr_output *wlr_output = output->wlr_output; - if (!wlr_output->enabled) { wlr_log(WLR_DEBUG, "Not disabling already disabled output %s", wlr_output->name); return; } wlr_log(WLR_DEBUG, "Disabling output %s", wlr_output->name); - wlr_output_enable(wlr_output, false); - wlr_output_commit(wlr_output); + struct wlr_output_state state = {0}; + wlr_output_state_set_enabled(&state, false); + wlr_output_commit_state(wlr_output, &state); output_layout_remove(output); } static bool output_apply_config(struct cg_output *output, struct wlr_output_configuration_head_v1 *head, bool test_only) { - wlr_output_enable(output->wlr_output, head->state.enabled); + struct wlr_output_state state = {0}; + wlr_output_state_set_enabled(&state, head->state.enabled); if (head->state.enabled) { /* Do not mess with these parameters for output to be disabled */ - wlr_output_set_scale(output->wlr_output, head->state.scale); - wlr_output_set_transform(output->wlr_output, head->state.transform); + wlr_output_state_set_scale(&state, head->state.scale); + wlr_output_state_set_transform(&state, head->state.transform); if (head->state.mode) { - wlr_output_set_mode(output->wlr_output, head->state.mode); + wlr_output_state_set_mode(&state, head->state.mode); } else { - wlr_output_set_custom_mode(output->wlr_output, head->state.custom_mode.width, - head->state.custom_mode.height, head->state.custom_mode.refresh); + wlr_output_state_set_custom_mode(&state, head->state.custom_mode.width, + head->state.custom_mode.height, + head->state.custom_mode.refresh); } } if (test_only) { - bool ret = wlr_output_test(output->wlr_output); - wlr_output_rollback(output->wlr_output); + bool ret = wlr_output_test_state(output->wlr_output, &state); return ret; } /* Apply output configuration */ - if (!wlr_output_commit(output->wlr_output)) { + if (!wlr_output_commit_state(output->wlr_output, &state)) { return false; } @@ -301,23 +303,22 @@ handle_new_output(struct wl_listener *listener, void *data) return; } + struct wlr_output_state state = {0}; + wlr_output_state_set_enabled(&state, true); if (!wl_list_empty(&wlr_output->modes)) { - /* Ensure the output is marked as enabled before trying to set mode */ - wlr_output_enable(wlr_output, true); - struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); if (preferred_mode) { - wlr_output_set_mode(wlr_output, preferred_mode); + wlr_output_state_set_mode(&state, preferred_mode); } - if (!wlr_output_test(wlr_output)) { + if (!wlr_output_test_state(wlr_output, &state)) { 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)) { + wlr_output_state_set_mode(&state, mode); + if (wlr_output_test_state(wlr_output, &state)) { break; } } @@ -334,8 +335,13 @@ handle_new_output(struct wl_listener *listener, void *data) wlr_output->scale); } - output_enable(output); + wlr_log(WLR_DEBUG, "Enabling new output %s", wlr_output->name); + if (wlr_output_commit_state(wlr_output, &state)) { + output_layout_add_auto(output); + } + view_position_all(output->server); + update_output_manager_config(output->server); } void From b6f8f925854cd90592b6f8abb4c8393ec51c9571 Mon Sep 17 00:00:00 2001 From: Supreeeme Date: Sat, 10 Feb 2024 00:24:48 -0500 Subject: [PATCH 195/233] xwayland: fix double wl_list_remove When destroying an xwayland surface, the dissociate and destroy handlers are called, but both of these were removing the map and unmap signal handlers, causing a segfault when the destroy handler went to remove them. Fixes #309 --- xwayland.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/xwayland.c b/xwayland.c index eec7fb9..de81408 100644 --- a/xwayland.c +++ b/xwayland.c @@ -139,8 +139,6 @@ handle_xwayland_surface_destroy(struct wl_listener *listener, void *data) struct cg_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, destroy); struct cg_view *view = &xwayland_view->view; - wl_list_remove(&xwayland_view->map.link); - wl_list_remove(&xwayland_view->unmap.link); wl_list_remove(&xwayland_view->destroy.link); wl_list_remove(&xwayland_view->request_fullscreen.link); xwayland_view->xwayland_surface = NULL; From 767ccf9bbd0dba6c8f8bc17587d1a112a3fc2335 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:25:51 +0100 Subject: [PATCH 196/233] output: use wlr_output_head_v1_state_apply() No need to hand-roll this code, there is a wlroots helper for it. Additionally, this fixes missing adaptive sync handling. --- output.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/output.c b/output.c index 714c828..471879c 100644 --- a/output.c +++ b/output.c @@ -131,21 +131,7 @@ static bool output_apply_config(struct cg_output *output, struct wlr_output_configuration_head_v1 *head, bool test_only) { struct wlr_output_state state = {0}; - wlr_output_state_set_enabled(&state, head->state.enabled); - - if (head->state.enabled) { - /* Do not mess with these parameters for output to be disabled */ - wlr_output_state_set_scale(&state, head->state.scale); - wlr_output_state_set_transform(&state, head->state.transform); - - if (head->state.mode) { - wlr_output_state_set_mode(&state, head->state.mode); - } else { - wlr_output_state_set_custom_mode(&state, head->state.custom_mode.width, - head->state.custom_mode.height, - head->state.custom_mode.refresh); - } - } + wlr_output_head_v1_state_apply(&head->state, &state); if (test_only) { bool ret = wlr_output_test_state(output->wlr_output, &state); From d07afac4ae5511f427db023c89bee85045ed11f4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:54:36 +0100 Subject: [PATCH 197/233] output: fix assert when re-adding output to layout wlr_scene_output_layout_add_output() aborts when called with an already-added output. To reproduce, run wlr-randr to reconfigure one of the enabled outputs. --- output.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/output.c b/output.c index 471879c..6eb2472 100644 --- a/output.c +++ b/output.c @@ -80,8 +80,12 @@ static inline void output_layout_add(struct cg_output *output, int32_t x, int32_t y) { assert(output->scene_output != NULL); + bool exists = wlr_output_layout_get(output->server->output_layout, output->wlr_output); struct wlr_output_layout_output *layout_output = wlr_output_layout_add(output->server->output_layout, output->wlr_output, x, y); + if (exists) { + return; + } wlr_scene_output_layout_add_output(output->server->scene_output_layout, layout_output, output->scene_output); } From 9d43282fa0cd5925a6f9304f0218fd79ae9fcd94 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:15:49 +0100 Subject: [PATCH 198/233] Add .editorconfig Allows text editors to display files with the correct tab width. --- .editorconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e9e7800 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = tab +indent_size = 8 +max_line_length = 120 From e7d8780f46277af87881e0be91cb2092541bb1d5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 24 Feb 2024 10:28:31 +0100 Subject: [PATCH 199/233] Add support for primary selection --- cage.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cage.c b/cage.c index 3da875d..f109788 100644 --- a/cage.c +++ b/cage.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -361,6 +362,12 @@ main(int argc, char *argv[]) goto end; } + if (!wlr_primary_selection_v1_device_manager_create(server.wl_display)) { + wlr_log(WLR_ERROR, "Unable to create primary selection device manager"); + ret = 1; + goto end; + } + /* Configure a listener to be notified when new outputs are * available on the backend. We use this only to detect the * first output and ignore subsequent outputs. */ From d3fb99d6654325ec46277cfdb589f89316bed701 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 8 Jul 2024 19:13:11 +0200 Subject: [PATCH 200/233] build: drop xwayland option This is unnecessary because Xwayland logic doesn't bring in new dependencies. We can just compile in our Xwayland-related code when wlroots has been built with Xwayland support. See this Sway patch: https://github.com/swaywm/sway/pull/8165 --- .github/workflows/main.yml | 6 +++--- README.md | 8 +++----- meson.build | 10 +--------- meson_options.txt | 1 - 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ecb0dc7..2ac6191 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: # 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 }} + meson build-${{ matrix.CC }}-${{matrix.xwayland }} -Dwlroots:xwayland=${{ matrix.xwayland }} ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }} format: @@ -54,7 +54,7 @@ jobs: run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 - name: Check for formatting changes run: | - meson build-clang-format -Dxwayland=enabled + meson build-clang-format -Dwlroots:xwayland=enabled ninja -C build-clang-format clang-format-check scan-build: @@ -73,5 +73,5 @@ jobs: run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 - name: Run scan-build run: | - meson build-scan-build -Dxwayland=enabled + meson build-scan-build -Dwlroots:xwayland=enabled ninja -C build-scan-build scan-build diff --git a/README.md b/README.md index 71cee17..a8331e3 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,9 @@ $ ninja -C build By default, this builds a debug build. To build a release build, use `meson build --buildtype=release`. -Cage comes with compile-time support for XWayland. To enable this, -first make sure that your version of wlroots is compiled with this -option. Then, add `-Dxwayland=true` to the `meson` command above. Note -that you'll need to have the XWayland binary installed on your system -for this to work. +Cage comes with compile-time support for XWayland. To enable this, make sure +that your version of wlroots is compiled with this option. Note that you'll +need to have the XWayland binary installed on your system for this to work. You can run Cage by running `./build/cage APPLICATION`. If you run it from within an existing X11 or Wayland session, it will open in a virtual output as diff --git a/meson.build b/meson.build index 45b3f91..4c0cbe2 100644 --- a/meson.build +++ b/meson.build @@ -64,15 +64,7 @@ server_protos = declare_dependency( sources: server_protos_headers, ) -if not get_option('xwayland').disabled() - wlroots_has_xwayland = wlroots.get_variable(pkgconfig: 'have_xwayland', internal: 'have_xwayland') == 'true' - if get_option('xwayland').enabled() and not wlroots_has_xwayland - error('Cannot build Cage with XWayland support: wlroots has been built without it') - endif - have_xwayland = true -else - have_xwayland = false -endif +have_xwayland = wlroots.get_variable(pkgconfig: 'have_xwayland', internal: 'have_xwayland') == 'true' version = '@0@'.format(meson.project_version()) git = find_program('git', native: true, required: false) diff --git a/meson_options.txt b/meson_options.txt index d64f510..e40a23d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,2 +1 @@ option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') -option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') From 018d5bc4b92b6c067a2df18edf2dfff95cc51c65 Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Wed, 21 Aug 2024 17:59:36 +0200 Subject: [PATCH 201/233] readme: update wlroots dependency version --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index a8331e3..86e26ef 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,7 @@ All releases are published on [GitHub](https://github.com/cage-kiosk/cage/releas You can build Cage with the [meson](https://mesonbuild.com/) build system. It requires wayland, wlroots, and xkbcommon to be installed. Optionally, install -scdoc for manual pages. Note that Cage is developed against the latest tag of -wlroots, in order to not constantly chase breaking changes as soon as they -occur. +scdoc for manual pages. Cage is currently based on branch 0.17 of wlroots. Simply execute the following steps to build Cage: From df508d65e7e7413ba986a0d63a1660deda7bbe4c Mon Sep 17 00:00:00 2001 From: Jonathan GUILLOT Date: Wed, 21 Aug 2024 18:06:34 +0200 Subject: [PATCH 202/233] readme: update meson commands --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 86e26ef..45fbafe 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,12 @@ scdoc for manual pages. Cage is currently based on branch 0.17 of wlroots. Simply execute the following steps to build Cage: ``` -$ meson build -$ ninja -C build +$ meson setup build +$ meson compile -C build ``` By default, this builds a debug build. To build a release build, use `meson -build --buildtype=release`. +setup build --buildtype=release`. Cage comes with compile-time support for XWayland. To enable this, make sure that your version of wlroots is compiled with this option. Note that you'll From 69c5eccc50457b268ff54dc7e07520dc3dc6df37 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 24 Aug 2024 15:06:13 +0200 Subject: [PATCH 203/233] ci: turn on --fatal-meson-warnings Catches mistakes such as non-existing build options. --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2ac6191..cea4715 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,10 +34,11 @@ jobs: - name: Fetch wlroots as a subproject run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 - # TODO: use --fatal-meson-warnings when on wlroots 0.15.0 - name: Compile Cage (XWayland=${{ matrix.xwayland }}) run: | - meson build-${{ matrix.CC }}-${{matrix.xwayland }} -Dwlroots:xwayland=${{ matrix.xwayland }} + meson --fatal-meson-warnings \ + build-${{ matrix.CC }}-${{matrix.xwayland }} \ + -Dwlroots:xwayland=${{ matrix.xwayland }} ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }} format: From eaeab71ffa3ab5884df09c5664c00e368ca2585e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Aug 2024 11:21:06 +0200 Subject: [PATCH 204/233] cage: fix SIGINT/SIGTERM handler data server.wl_display is already a pointer. Reported-by: Jonathan GUILLOT --- cage.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cage.c b/cage.c index f109788..cc99357 100644 --- a/cage.c +++ b/cage.c @@ -290,9 +290,9 @@ main(int argc, char *argv[]) struct wl_event_loop *event_loop = wl_display_get_event_loop(server.wl_display); struct wl_event_source *sigint_source = - wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display); + wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, server.wl_display); struct wl_event_source *sigterm_source = - wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display); + wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, server.wl_display); server.backend = wlr_backend_autocreate(server.wl_display, &server.session); if (!server.backend) { From 8714a82c244b3b045c5f0c5bbe3bf0d2c4518074 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:17:47 +0100 Subject: [PATCH 205/233] Bump wlroots requirement to v0.18 --- .github/workflows/main.yml | 6 +++--- README.md | 2 +- meson.build | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cea4715..e82dbf1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: 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.17 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 - name: Compile Cage (XWayland=${{ matrix.xwayland }}) run: | @@ -52,7 +52,7 @@ jobs: pacman-key --init pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 - name: Check for formatting changes run: | meson build-clang-format -Dwlroots:xwayland=enabled @@ -71,7 +71,7 @@ jobs: pacman-key --init pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.17 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 - name: Run scan-build run: | meson build-scan-build -Dwlroots:xwayland=enabled diff --git a/README.md b/README.md index 45fbafe..ec6ce78 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ All releases are published on [GitHub](https://github.com/cage-kiosk/cage/releas You can build Cage with the [meson](https://mesonbuild.com/) build system. It requires wayland, wlroots, and xkbcommon to be installed. Optionally, install -scdoc for manual pages. Cage is currently based on branch 0.17 of wlroots. +scdoc for manual pages. Cage is currently based on branch 0.18 of wlroots. Simply execute the following steps to build Cage: diff --git a/meson.build b/meson.build index 4c0cbe2..a2f328e 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots', version: '>= 0.17.0', fallback: ['wlroots', 'wlroots']) +wlroots = dependency('wlroots-0.18', fallback: ['wlroots', 'wlroots']) wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') xkbcommon = dependency('xkbcommon') From 47ea6a5d682ec275f7100a638fdcdcc2202ffbf7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:17:27 +0100 Subject: [PATCH 206/233] seat: pass relative direction to wlr_seat_pointer_notify_axis() --- seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seat.c b/seat.c index 8008dd9..3671964 100644 --- a/seat.c +++ b/seat.c @@ -591,7 +591,7 @@ handle_cursor_axis(struct wl_listener *listener, void *data) struct wlr_pointer_axis_event *event = data; wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, - event->delta_discrete, event->source); + event->delta_discrete, event->source, event->relative_direction); wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat); } From b9add8b729c2fc7ff6483f72613e405cb92bd560 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:19:03 +0100 Subject: [PATCH 207/233] cage: create backend with wl_event_loop and output layout with wl_display --- cage.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cage.c b/cage.c index cc99357..0de286d 100644 --- a/cage.c +++ b/cage.c @@ -294,7 +294,7 @@ main(int argc, char *argv[]) struct wl_event_source *sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, server.wl_display); - server.backend = wlr_backend_autocreate(server.wl_display, &server.session); + server.backend = wlr_backend_autocreate(event_loop, &server.session); if (!server.backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); ret = 1; @@ -325,7 +325,7 @@ main(int argc, char *argv[]) wl_list_init(&server.views); wl_list_init(&server.outputs); - server.output_layout = wlr_output_layout_create(); + server.output_layout = wlr_output_layout_create(server.wl_display); if (!server.output_layout) { wlr_log(WLR_ERROR, "Unable to create output layout"); ret = 1; @@ -596,6 +596,5 @@ end: /* This function is not null-safe, but we only ever get here with a proper wl_display. */ wl_display_destroy(server.wl_display); - wlr_output_layout_destroy(server.output_layout); return ret; } From 7cc49d2292bd7f13422024b0f0eb4fb4220fd038 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:19:37 +0100 Subject: [PATCH 208/233] cage: drop wlr_scene_set_presentation() Scene-graph will do the right thing without this call. --- cage.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cage.c b/cage.c index 0de286d..9a33ea0 100644 --- a/cage.c +++ b/cage.c @@ -440,7 +440,6 @@ main(int argc, char *argv[]) ret = 1; goto end; } - wlr_scene_set_presentation(server.scene, presentation); if (!wlr_export_dmabuf_manager_v1_create(server.wl_display)) { wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager"); From 874a4a1e79fc9cad1c5fbf95e0db7be16bb524bc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:48:25 +0100 Subject: [PATCH 209/233] xdg_shell: use new lifecycle events --- cage.c | 6 ++- server.h | 3 +- xdg_shell.c | 117 ++++++++++++++++++++++++++-------------------------- xdg_shell.h | 3 +- 4 files changed, 66 insertions(+), 63 deletions(-) diff --git a/cage.c b/cage.c index 9a33ea0..b5ba6c5 100644 --- a/cage.c +++ b/cage.c @@ -404,8 +404,10 @@ main(int argc, char *argv[]) ret = 1; goto end; } - server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; - wl_signal_add(&xdg_shell->events.new_surface, &server.new_xdg_shell_surface); + server.new_xdg_toplevel.notify = handle_new_xdg_toplevel; + wl_signal_add(&xdg_shell->events.new_toplevel, &server.new_xdg_toplevel); + server.new_xdg_popup.notify = handle_new_xdg_popup; + wl_signal_add(&xdg_shell->events.new_popup, &server.new_xdg_popup); struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = wlr_xdg_decoration_manager_v1_create(server.wl_display); diff --git a/server.h b/server.h index 9bf4430..8759ed5 100644 --- a/server.h +++ b/server.h @@ -44,7 +44,8 @@ struct cg_server { struct wl_listener output_layout_change; struct wl_listener xdg_toplevel_decoration; - struct wl_listener new_xdg_shell_surface; + struct wl_listener new_xdg_toplevel; + struct wl_listener new_xdg_popup; struct wl_listener new_virtual_keyboard; struct wl_listener new_virtual_pointer; diff --git a/xdg_shell.c b/xdg_shell.c index 046dbd8..c65c496 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -221,72 +221,71 @@ static const struct cg_view_impl xdg_shell_view_impl = { }; void -handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) +handle_new_xdg_toplevel(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; + struct cg_server *server = wl_container_of(listener, server, new_xdg_toplevel); + struct wlr_xdg_toplevel *toplevel = data; - switch (xdg_surface->role) { + struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view)); + if (!xdg_shell_view) { + wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view"); + return; + } + + view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); + xdg_shell_view->xdg_toplevel = toplevel; + + xdg_shell_view->map.notify = handle_xdg_shell_surface_map; + wl_signal_add(&toplevel->base->surface->events.map, &xdg_shell_view->map); + xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap; + wl_signal_add(&toplevel->base->surface->events.unmap, &xdg_shell_view->unmap); + xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy; + wl_signal_add(&toplevel->events.destroy, &xdg_shell_view->destroy); + xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen; + wl_signal_add(&toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); + + toplevel->base->data = xdg_shell_view; +} + +void +handle_new_xdg_popup(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, new_xdg_popup); + struct wlr_xdg_popup *popup = data; + + struct cg_view *view = popup_get_view(popup); + if (view == NULL) { + return; + } + + struct wlr_scene_tree *parent_scene_tree = NULL; + struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(popup->parent); + if (parent == NULL) { + return; + } + switch (parent->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; - } - - view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); - xdg_shell_view->xdg_toplevel = xdg_surface->toplevel; - - xdg_shell_view->map.notify = handle_xdg_shell_surface_map; - wl_signal_add(&xdg_surface->surface->events.map, &xdg_shell_view->map); - xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap; - wl_signal_add(&xdg_surface->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; + parent_scene_tree = view->scene_tree; break; - case WLR_XDG_SURFACE_ROLE_POPUP:; - struct wlr_xdg_popup *popup = xdg_surface->popup; - struct cg_view *view = popup_get_view(popup); - if (view == NULL) { - return; - } - - struct wlr_scene_tree *parent_scene_tree = NULL; - struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(popup->parent); - if (parent == NULL) { - return; - } - switch (parent->role) { - case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; - parent_scene_tree = view->scene_tree; - break; - case WLR_XDG_SURFACE_ROLE_POPUP: - parent_scene_tree = parent->data; - break; - case WLR_XDG_SURFACE_ROLE_NONE: - break; - } - if (parent_scene_tree == NULL) { - return; - } - - struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, xdg_surface); - if (popup_scene_tree == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); - return; - } - - popup_unconstrain(view, popup); - - xdg_surface->data = popup_scene_tree; + case WLR_XDG_SURFACE_ROLE_POPUP: + parent_scene_tree = parent->data; break; case WLR_XDG_SURFACE_ROLE_NONE: - assert(false); // unreachable + break; } + if (parent_scene_tree == NULL) { + return; + } + + struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, popup->base); + if (popup_scene_tree == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); + return; + } + + popup_unconstrain(view, popup); + + popup->base->data = popup_scene_tree; } void diff --git a/xdg_shell.h b/xdg_shell.h index 2fd506a..0175c70 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -24,7 +24,8 @@ struct cg_xdg_decoration { struct wl_listener request_mode; }; -void handle_xdg_shell_surface_new(struct wl_listener *listener, void *data); +void handle_new_xdg_toplevel(struct wl_listener *listener, void *data); +void handle_new_xdg_popup(struct wl_listener *listener, void *data); void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data); From a81cc2a8e47426a644cc5384d81c8b4d8999da86 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 24 Aug 2024 15:00:40 +0200 Subject: [PATCH 210/233] seat: rename WLR_INPUT_DEVICE_TABLET_TOOL to WLR_INPUT_DEVICE_TABLET --- seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seat.c b/seat.c index 3671964..4e287d9 100644 --- a/seat.c +++ b/seat.c @@ -441,7 +441,7 @@ handle_new_input(struct wl_listener *listener, void *data) case WLR_INPUT_DEVICE_SWITCH: wlr_log(WLR_DEBUG, "Switch input is not implemented"); return; - case WLR_INPUT_DEVICE_TABLET_TOOL: + case WLR_INPUT_DEVICE_TABLET: case WLR_INPUT_DEVICE_TABLET_PAD: wlr_log(WLR_DEBUG, "Tablet input is not implemented"); return; From 17af2f7be923194621b8bc2f0899e838d6a93dd4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 24 Aug 2024 15:05:10 +0200 Subject: [PATCH 211/233] ci: workaround libwayland C23 bug --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e82dbf1..e897f2d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,11 +34,14 @@ jobs: - name: Fetch wlroots as a subproject run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 + # TODO: drop explicit c_std when this is released: + # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/401 - name: Compile Cage (XWayland=${{ matrix.xwayland }}) run: | meson --fatal-meson-warnings \ build-${{ matrix.CC }}-${{matrix.xwayland }} \ - -Dwlroots:xwayland=${{ matrix.xwayland }} + -Dwlroots:xwayland=${{ matrix.xwayland }} \ + -Dwlroots:c_std=c11 ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }} format: From fa901746071522b963de9c2ec7a380452ad65acd Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 24 Aug 2024 15:44:46 +0200 Subject: [PATCH 212/233] xdg_shell: configure surface on initial commit Instead of waiting for the surface to be mapped before sending a configure event, do it on initial commit. Note, wlroots 0.18 no longer sends automatic configure events on initial commit. --- view.c | 8 ++++++-- xdg_shell.c | 17 +++++++++++++++++ xdg_shell.h | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/view.c b/view.c index 8948580..8cbeb5e 100644 --- a/view.c +++ b/view.c @@ -67,7 +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_tree->node, view->lx, view->ly); + if (view->scene_tree) { + wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); + } view->impl->maximize(view, layout_box->width, layout_box->height); } @@ -81,7 +83,9 @@ view_center(struct cg_view *view, struct wlr_box *layout_box) view->lx = (layout_box->width - width) / 2; view->ly = (layout_box->height - height) / 2; - wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); + if (view->scene_tree) { + wlr_scene_node_set_position(&view->scene_tree->node, view->lx, view->ly); + } } void diff --git a/xdg_shell.c b/xdg_shell.c index c65c496..783e7f3 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -195,12 +195,27 @@ handle_xdg_shell_surface_map(struct wl_listener *listener, void *data) view_map(view, xdg_shell_view->xdg_toplevel->base->surface); } +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); + + if (!xdg_shell_view->xdg_toplevel->base->initial_commit) { + return; + } + + /* When an xdg_surface performs an initial commit, the compositor must + * reply with a configure so the client can map the surface. */ + view_position(&xdg_shell_view->view); +} + static void handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data) { struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, destroy); struct cg_view *view = &xdg_shell_view->view; + wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->map.link); wl_list_remove(&xdg_shell_view->unmap.link); wl_list_remove(&xdg_shell_view->destroy.link); @@ -235,6 +250,8 @@ handle_new_xdg_toplevel(struct wl_listener *listener, void *data) view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); xdg_shell_view->xdg_toplevel = toplevel; + xdg_shell_view->commit.notify = handle_xdg_shell_surface_commit; + wl_signal_add(&toplevel->base->surface->events.commit, &xdg_shell_view->commit); xdg_shell_view->map.notify = handle_xdg_shell_surface_map; wl_signal_add(&toplevel->base->surface->events.map, &xdg_shell_view->map); xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap; diff --git a/xdg_shell.h b/xdg_shell.h index 0175c70..077a9ae 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -12,6 +12,7 @@ struct cg_xdg_shell_view { struct wlr_xdg_toplevel *xdg_toplevel; struct wl_listener destroy; + struct wl_listener commit; struct wl_listener unmap; struct wl_listener map; struct wl_listener request_fullscreen; From 1abf7e5a4bee554f14472735876be67bb4baae11 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 24 Aug 2024 15:46:11 +0200 Subject: [PATCH 213/233] xdg_shell: wait for initial commit to set xdg-decoration mode Sending the xdg-decoration mode when the xdg_toplevel_decoration object is created is incorrect: we need to wait for the initial commit. --- xdg_shell.c | 49 ++++++++++++++++++++++++++++++++++--------------- xdg_shell.h | 1 + 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index 783e7f3..2767a18 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -19,21 +19,9 @@ #include "xdg_shell.h" static void -xdg_decoration_handle_destroy(struct wl_listener *listener, void *data) +xdg_decoration_set_mode(struct cg_xdg_decoration *xdg_decoration) { - struct cg_xdg_decoration *xdg_decoration = wl_container_of(listener, xdg_decoration, destroy); - - wl_list_remove(&xdg_decoration->destroy.link); - wl_list_remove(&xdg_decoration->request_mode.link); - free(xdg_decoration); -} - -static void -xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data) -{ - struct cg_xdg_decoration *xdg_decoration = wl_container_of(listener, xdg_decoration, request_mode); enum wlr_xdg_toplevel_decoration_v1_mode mode; - if (xdg_decoration->server->xdg_decoration) { mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; } else { @@ -42,6 +30,37 @@ 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_decoration_handle_destroy(struct wl_listener *listener, void *data) +{ + struct cg_xdg_decoration *xdg_decoration = wl_container_of(listener, xdg_decoration, destroy); + + wl_list_remove(&xdg_decoration->destroy.link); + wl_list_remove(&xdg_decoration->commit.link); + wl_list_remove(&xdg_decoration->request_mode.link); + free(xdg_decoration); +} + +static void +xdg_decoration_handle_commit(struct wl_listener *listener, void *data) +{ + struct cg_xdg_decoration *xdg_decoration = wl_container_of(listener, xdg_decoration, commit); + + if (xdg_decoration->wlr_decoration->toplevel->base->initial_commit) { + xdg_decoration_set_mode(xdg_decoration); + } +} + +static void +xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data) +{ + struct cg_xdg_decoration *xdg_decoration = wl_container_of(listener, xdg_decoration, request_mode); + + if (xdg_decoration->wlr_decoration->toplevel->base->initialized) { + xdg_decoration_set_mode(xdg_decoration); + } +} + static struct cg_view * popup_get_view(struct wlr_xdg_popup *popup) { @@ -321,8 +340,8 @@ handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data) xdg_decoration->destroy.notify = xdg_decoration_handle_destroy; wl_signal_add(&wlr_decoration->events.destroy, &xdg_decoration->destroy); + xdg_decoration->commit.notify = xdg_decoration_handle_commit; + wl_signal_add(&wlr_decoration->toplevel->base->surface->events.commit, &xdg_decoration->commit); xdg_decoration->request_mode.notify = xdg_decoration_handle_request_mode; wl_signal_add(&wlr_decoration->events.request_mode, &xdg_decoration->request_mode); - - xdg_decoration_handle_request_mode(&xdg_decoration->request_mode, wlr_decoration); } diff --git a/xdg_shell.h b/xdg_shell.h index 077a9ae..d6553f4 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -22,6 +22,7 @@ struct cg_xdg_decoration { struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; struct cg_server *server; struct wl_listener destroy; + struct wl_listener commit; struct wl_listener request_mode; }; From 412c11ea91647c30abce3c4a0ec6f6b97b408bf0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 28 Aug 2024 15:05:03 +0200 Subject: [PATCH 214/233] cage: fix abort on shutdown Workaround for [1]: register a listener for wl_display destroy and avoid calling wl_display_terminate() after. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/421 --- cage.c | 33 ++++++++++++++++++++++++++------- output.c | 2 +- seat.c | 2 +- server.h | 4 ++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/cage.c b/cage.c index b5ba6c5..26ab9ef 100644 --- a/cage.c +++ b/cage.c @@ -61,6 +61,24 @@ #include "xwayland.h" #endif +void +server_terminate(struct cg_server *server) +{ + // Workaround for https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/421 + if (server->terminated) { + return; + } + + wl_display_terminate(server->wl_display); +} + +static void +handle_display_destroy(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, display_destroy); + server->terminated = true; +} + static int sigchld_handler(int fd, uint32_t mask, void *data) { @@ -76,7 +94,7 @@ sigchld_handler(int fd, uint32_t mask, void *data) } server->return_app_code = true; - wl_display_terminate(server->wl_display); + server_terminate(server); return 0; } @@ -189,13 +207,13 @@ drop_permissions(void) static int handle_signal(int signal, void *data) { - struct wl_display *display = data; + struct cg_server *server = data; switch (signal) { case SIGINT: /* Fallthrough */ case SIGTERM: - wl_display_terminate(display); + server_terminate(server); return 0; default: return 0; @@ -288,11 +306,12 @@ main(int argc, char *argv[]) return 1; } + server.display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(server.wl_display, &server.display_destroy); + struct wl_event_loop *event_loop = wl_display_get_event_loop(server.wl_display); - struct wl_event_source *sigint_source = - wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, server.wl_display); - struct wl_event_source *sigterm_source = - wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, server.wl_display); + struct wl_event_source *sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server); + struct wl_event_source *sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server); server.backend = wlr_backend_autocreate(event_loop, &server.session); if (!server.backend) { diff --git a/output.c b/output.c index 6eb2472..f1c0419 100644 --- a/output.c +++ b/output.c @@ -240,7 +240,7 @@ output_destroy(struct cg_output *output) free(output); if (wl_list_empty(&server->outputs) && was_nested_output) { - wl_display_terminate(server->wl_display); + server_terminate(server); } else if (server->output_mode == CAGE_MULTI_OUTPUT_MODE_LAST && !wl_list_empty(&server->outputs)) { struct cg_output *prev = wl_container_of(server->outputs.next, prev, link); output_enable(prev); diff --git a/seat.c b/seat.c index 4e287d9..cdf8798 100644 --- a/seat.c +++ b/seat.c @@ -258,7 +258,7 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym) { #ifdef DEBUG if (sym == XKB_KEY_Escape) { - wl_display_terminate(server->wl_display); + server_terminate(server); return true; } #endif diff --git a/server.h b/server.h index 8759ed5..f7d70d7 100644 --- a/server.h +++ b/server.h @@ -25,6 +25,7 @@ struct cg_server { struct wlr_renderer *renderer; struct wlr_allocator *allocator; struct wlr_session *session; + struct wl_listener display_destroy; struct cg_seat *seat; struct wlr_idle_notifier_v1 *idle; @@ -61,6 +62,9 @@ struct cg_server { bool xdg_decoration; bool allow_vt_switch; bool return_app_code; + bool terminated; }; +void server_terminate(struct cg_server *server); + #endif From f0651c7671afcf2d0f709c2e04f208dd5f3179f4 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 30 Aug 2024 18:50:11 +0200 Subject: [PATCH 215/233] xdg_shell: wait for initial commit to unconstrain popups --- xdg_shell.c | 55 ++++++++++++++++++++++++++++++++++++++++++++--------- xdg_shell.h | 7 +++++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index 2767a18..cae6c90 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -85,8 +85,13 @@ popup_get_view(struct wlr_xdg_popup *popup) } static void -popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) +popup_unconstrain(struct wlr_xdg_popup *popup) { + struct cg_view *view = popup_get_view(popup); + if (view == NULL) { + return; + } + struct cg_server *server = view->server; struct wlr_box *popup_box = &popup->current.geometry; @@ -283,19 +288,38 @@ handle_new_xdg_toplevel(struct wl_listener *listener, void *data) toplevel->base->data = xdg_shell_view; } +static void +popup_handle_destroy(struct wl_listener *listener, void *data) +{ + struct cg_xdg_popup *popup = wl_container_of(listener, popup, destroy); + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->commit.link); + free(popup); +} + +static void +popup_handle_commit(struct wl_listener *listener, void *data) +{ + struct cg_xdg_popup *popup = wl_container_of(listener, popup, commit); + + if (popup->xdg_popup->base->initial_commit) { + popup_unconstrain(popup->xdg_popup); + } +} + void handle_new_xdg_popup(struct wl_listener *listener, void *data) { struct cg_server *server = wl_container_of(listener, server, new_xdg_popup); - struct wlr_xdg_popup *popup = data; + struct wlr_xdg_popup *wlr_popup = data; - struct cg_view *view = popup_get_view(popup); + struct cg_view *view = popup_get_view(wlr_popup); if (view == NULL) { return; } struct wlr_scene_tree *parent_scene_tree = NULL; - struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(popup->parent); + struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(wlr_popup->parent); if (parent == NULL) { return; } @@ -313,15 +337,28 @@ handle_new_xdg_popup(struct wl_listener *listener, void *data) return; } - struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, popup->base); - if (popup_scene_tree == NULL) { - wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); + struct cg_xdg_popup *popup = calloc(1, sizeof(*popup)); + if (popup == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate popup"); return; } - popup_unconstrain(view, popup); + popup->xdg_popup = wlr_popup; - popup->base->data = popup_scene_tree; + popup->destroy.notify = popup_handle_destroy; + wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); + + popup->commit.notify = popup_handle_commit; + wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + + struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, wlr_popup->base); + if (popup_scene_tree == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); + free(popup); + return; + } + + wlr_popup->base->data = popup_scene_tree; } void diff --git a/xdg_shell.h b/xdg_shell.h index d6553f4..1fc000a 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -26,6 +26,13 @@ struct cg_xdg_decoration { struct wl_listener request_mode; }; +struct cg_xdg_popup { + struct wlr_xdg_popup *xdg_popup; + + struct wl_listener destroy; + struct wl_listener commit; +}; + void handle_new_xdg_toplevel(struct wl_listener *listener, void *data); void handle_new_xdg_popup(struct wl_listener *listener, void *data); From 34de3f7bac48aae64bbbb09a4c10900e0150e968 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 2 Oct 2024 02:55:33 +0200 Subject: [PATCH 216/233] ci: drop libwayland C23 workaround --- .github/workflows/main.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e897f2d..e82dbf1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,14 +34,11 @@ jobs: - name: Fetch wlroots as a subproject run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 - # TODO: drop explicit c_std when this is released: - # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/401 - name: Compile Cage (XWayland=${{ matrix.xwayland }}) run: | meson --fatal-meson-warnings \ build-${{ matrix.CC }}-${{matrix.xwayland }} \ - -Dwlroots:xwayland=${{ matrix.xwayland }} \ - -Dwlroots:c_std=c11 + -Dwlroots:xwayland=${{ matrix.xwayland }} ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }} format: From e128a9f2511644529fa47701a7147d65d9920488 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 6 Oct 2024 15:24:22 +0200 Subject: [PATCH 217/233] build: bump to version 0.2.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a2f328e..7b58cd8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cage', 'c', - version: '0.1.5', + version: '0.2.0', license: 'MIT', meson_version: '>=0.58.1', default_options: [ From 0208f565dc8bd87bd9fec35e0625021f50ca690b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vani=C5=A1?= Date: Sun, 3 Nov 2024 16:29:19 +0100 Subject: [PATCH 218/233] readme: add link to man page --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ec6ce78..d285219 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ This README is only relevant for development resources and instructions. For a description of Cage and installation instructions for end-users, please see [its project page](https://www.hjdskes.nl/projects/cage) and [the Wiki](https://github.com/cage-kiosk/cage/wiki/). +See [the man page](./cage.1.scd) for a list of possible environment variables and run options. ## Release signatures From 852839e59fb4187343a01f7fdd1a6a318ef910b2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 12 Nov 2024 13:45:17 +0100 Subject: [PATCH 219/233] Add CLI flag to enable debug logs For bug reports, it's useful to ask for a debug log. However there's no way for users to enable debug logs without recompiling. Add a CLI flag to do so. --- cage.1.scd | 5 ++++- cage.c | 16 ++++++++++------ server.h | 3 +++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cage.1.scd b/cage.1.scd index 0894f5d..58c4ed1 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -6,7 +6,7 @@ cage - a Wayland kiosk compositor # SYNOPSIS -*cage* [-dhmrsv] [--] _application_ [application argument ...] +*cage* [options...] [--] _application_ [application argument ...] # DESCRIPTION @@ -19,6 +19,9 @@ activities outside the scope of the running application are prevented. *-d* Don't draw client side decorations when possible. +*-D* + Enable debug logging. + *-h* Show the help message. diff --git a/cage.c b/cage.c index 26ab9ef..61c9386 100644 --- a/cage.c +++ b/cage.c @@ -227,6 +227,7 @@ usage(FILE *file, const char *cage) "Usage: %s [OPTIONS] [--] APPLICATION\n" "\n" " -d\t Don't draw client side decorations, when possible\n" + " -D\t Enable debug logging\n" " -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" @@ -246,6 +247,9 @@ parse_args(struct cg_server *server, int argc, char *argv[]) case 'd': server->xdg_decoration = true; break; + case 'D': + server->log_level = WLR_DEBUG; + break; case 'h': usage(stdout, argv[0]); return false; @@ -279,20 +283,20 @@ parse_args(struct cg_server *server, int argc, char *argv[]) int main(int argc, char *argv[]) { - struct cg_server server = {0}; + struct cg_server server = {.log_level = WLR_INFO}; struct wl_event_source *sigchld_source = NULL; pid_t pid = 0; int ret = 0, app_ret = 0; +#ifdef DEBUG + server.log_level = WLR_DEBUG; +#endif + if (!parse_args(&server, argc, argv)) { return 1; } -#ifdef DEBUG - wlr_log_init(WLR_DEBUG, NULL); -#else - wlr_log_init(WLR_ERROR, NULL); -#endif + wlr_log_init(server.log_level, NULL); /* Wayland requires XDG_RUNTIME_DIR to be set. */ if (!getenv("XDG_RUNTIME_DIR")) { diff --git a/server.h b/server.h index f7d70d7..00c2a61 100644 --- a/server.h +++ b/server.h @@ -9,6 +9,8 @@ #include #include #include +#include + #if CAGE_HAS_XWAYLAND #include #endif @@ -63,6 +65,7 @@ struct cg_server { bool allow_vt_switch; bool return_app_code; bool terminated; + enum wlr_log_importance log_level; }; void server_terminate(struct cg_server *server); From 19157d35649f96aa04d26036a76eaed65de60944 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 12 Nov 2024 22:54:58 +0100 Subject: [PATCH 220/233] Make application arguments optional If no application is specified, run without starting a child process. Leave it up to the user to start applications externally and stop cage with a signal. --- cage.1.scd | 2 +- cage.c | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/cage.1.scd b/cage.1.scd index 58c4ed1..ed1f518 100644 --- a/cage.1.scd +++ b/cage.1.scd @@ -6,7 +6,7 @@ cage - a Wayland kiosk compositor # SYNOPSIS -*cage* [options...] [--] _application_ [application argument ...] +*cage* [options...] [--] [_application_...] # DESCRIPTION diff --git a/cage.c b/cage.c index 61c9386..631b95a 100644 --- a/cage.c +++ b/cage.c @@ -224,7 +224,7 @@ static void usage(FILE *file, const char *cage) { fprintf(file, - "Usage: %s [OPTIONS] [--] APPLICATION\n" + "Usage: %s [OPTIONS] [--] [APPLICATION...]\n" "\n" " -d\t Don't draw client side decorations, when possible\n" " -D\t Enable debug logging\n" @@ -272,11 +272,6 @@ parse_args(struct cg_server *server, int argc, char *argv[]) } } - if (optind >= argc) { - usage(stderr, argv[0]); - return false; - } - return true; } @@ -592,7 +587,7 @@ main(int argc, char *argv[]) } #endif - if (!spawn_primary_client(&server, argv + optind, &pid, &sigchld_source)) { + if (optind < argc && !spawn_primary_client(&server, argv + optind, &pid, &sigchld_source)) { ret = 1; goto end; } @@ -607,7 +602,8 @@ main(int argc, char *argv[]) wl_display_destroy_clients(server.wl_display); end: - app_ret = cleanup_primary_client(pid); + if (pid != 0) + app_ret = cleanup_primary_client(pid); if (!ret && server.return_app_code) ret = app_ret; From 360e259ca5c7e86a071fda1ee16284b13540d2b3 Mon Sep 17 00:00:00 2001 From: Horror Proton <107091537+horror-proton@users.noreply.github.com> Date: Mon, 23 Dec 2024 21:49:50 +0800 Subject: [PATCH 221/233] Fix getopt("D") --- cage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 631b95a..8f14746 100644 --- a/cage.c +++ b/cage.c @@ -242,7 +242,7 @@ static bool parse_args(struct cg_server *server, int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "dhm:sv")) != -1) { + while ((c = getopt(argc, argv, "dDhm:sv")) != -1) { switch (c) { case 'd': server->xdg_decoration = true; From 6b1ba34a4a3960fca423b610f6ecb32852f7bde1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 10 Apr 2025 17:42:36 +0200 Subject: [PATCH 222/233] output: drop unused wlr_matrix.h include This is dropped in the next wlroots release. --- output.c | 1 - 1 file changed, 1 deletion(-) diff --git a/output.c b/output.c index f1c0419..5ccc939 100644 --- a/output.c +++ b/output.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include From e21c155bcdc3f6bc8a3acc7c1dc362bcda3f734c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 10 Apr 2025 18:08:15 +0200 Subject: [PATCH 223/233] seat: destroy keyboard groups on shutdown These are not destroyed automatically because they are entirely managed by the compositor. --- seat.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/seat.c b/seat.c index cdf8798..9acbdd3 100644 --- a/seat.c +++ b/seat.c @@ -380,6 +380,16 @@ cleanup: free(cg_group); } +static void +keyboard_group_destroy(struct cg_keyboard_group *keyboard_group) +{ + wl_list_remove(&keyboard_group->key.link); + wl_list_remove(&keyboard_group->modifiers.link); + wlr_keyboard_group_destroy(keyboard_group->wlr_group); + wl_list_remove(&keyboard_group->link); + free(keyboard_group); +} + static void handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard, bool virtual) { @@ -893,6 +903,11 @@ seat_destroy(struct cg_seat *seat) wl_list_remove(&seat->request_start_drag.link); wl_list_remove(&seat->start_drag.link); + struct cg_keyboard_group *keyboard_group, *keyboard_group_tmp; + wl_list_for_each_safe (keyboard_group, keyboard_group_tmp, &seat->keyboard_groups, link) { + keyboard_group_destroy(keyboard_group); + } + // Destroying the wlr seat will trigger the destroy handler on our seat, // which will in turn free it. wlr_seat_destroy(seat->seat); From 6efb3b50421d9adc8d1220ccae63af45d423f5cf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 10 Apr 2025 18:09:01 +0200 Subject: [PATCH 224/233] cage: remove global server listeners on shutdown --- cage.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cage.c b/cage.c index 8f14746..40a675d 100644 --- a/cage.c +++ b/cage.c @@ -596,11 +596,25 @@ main(int argc, char *argv[]) wl_display_run(server.wl_display); #if CAGE_HAS_XWAYLAND + if (xwayland) { + wl_list_remove(&server.new_xwayland_surface.link); + } wlr_xwayland_destroy(xwayland); wlr_xcursor_manager_destroy(xcursor_manager); #endif wl_display_destroy_clients(server.wl_display); + wl_list_remove(&server.new_virtual_pointer.link); + wl_list_remove(&server.new_virtual_keyboard.link); + wl_list_remove(&server.output_manager_apply.link); + wl_list_remove(&server.output_manager_test.link); + wl_list_remove(&server.xdg_toplevel_decoration.link); + wl_list_remove(&server.new_xdg_toplevel.link); + wl_list_remove(&server.new_xdg_popup.link); + wl_list_remove(&server.new_idle_inhibitor_v1.link); + wl_list_remove(&server.new_output.link); + wl_list_remove(&server.output_layout_change.link); + end: if (pid != 0) app_ret = cleanup_primary_client(pid); From 9ad44e4f521edf446ad66559726e6deeb8204101 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 10 Apr 2025 17:50:15 +0200 Subject: [PATCH 225/233] Upgrade wlroots to v0.19 --- .github/workflows/main.yml | 9 ++++++--- cage.c | 2 +- meson.build | 2 +- seat.c | 2 +- xdg_shell.c | 7 +++---- xwayland.c | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e82dbf1..e0f8093 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,6 +5,9 @@ on: pull_request: branches: [ master ] +env: + WLROOTS_VERSION: 0.19 + jobs: compile: runs-on: ubuntu-latest @@ -32,7 +35,7 @@ jobs: 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.18 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Compile Cage (XWayland=${{ matrix.xwayland }}) run: | @@ -52,7 +55,7 @@ jobs: pacman-key --init pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Check for formatting changes run: | meson build-clang-format -Dwlroots:xwayland=enabled @@ -71,7 +74,7 @@ jobs: pacman-key --init pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata - name: Fetch wlroots as a subproject - run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b 0.18 + run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Run scan-build run: | meson build-scan-build -Dwlroots:xwayland=enabled diff --git a/cage.c b/cage.c index 40a675d..77ebc88 100644 --- a/cage.c +++ b/cage.c @@ -454,7 +454,7 @@ main(int argc, char *argv[]) goto end; } - struct wlr_presentation *presentation = wlr_presentation_create(server.wl_display, server.backend); + struct wlr_presentation *presentation = wlr_presentation_create(server.wl_display, server.backend, 2); if (!presentation) { wlr_log(WLR_ERROR, "Unable to create the presentation interface"); ret = 1; diff --git a/meson.build b/meson.build index 7b58cd8..07ca800 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,7 @@ if is_freebsd ) endif -wlroots = dependency('wlroots-0.18', fallback: ['wlroots', 'wlroots']) +wlroots = dependency('wlroots-0.19', fallback: ['wlroots', 'wlroots']) wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_server = dependency('wayland-server') xkbcommon = dependency('xkbcommon') diff --git a/seat.c b/seat.c index 9acbdd3..5f659a4 100644 --- a/seat.c +++ b/seat.c @@ -937,7 +937,7 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) #if CAGE_HAS_XWAYLAND if (view->type == CAGE_XWAYLAND_VIEW) { struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); - if (!wlr_xwayland_or_surface_wants_focus(xwayland_view->xwayland_surface)) { + if (!wlr_xwayland_surface_override_redirect_wants_focus(xwayland_view->xwayland_surface)) { return; } } diff --git a/xdg_shell.c b/xdg_shell.c index cae6c90..10224ae 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -128,11 +128,10 @@ static void get_geometry(struct cg_view *view, int *width_out, int *height_out) { struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); - struct wlr_box geom; + struct wlr_xdg_surface *xdg_surface = xdg_shell_view->xdg_toplevel->base; - wlr_xdg_surface_get_geometry(xdg_shell_view->xdg_toplevel->base, &geom); - *width_out = geom.width; - *height_out = geom.height; + *width_out = xdg_surface->geometry.width; + *height_out = xdg_surface->geometry.height; } static bool diff --git a/xwayland.c b/xwayland.c index de81408..3df7a08 100644 --- a/xwayland.c +++ b/xwayland.c @@ -92,7 +92,7 @@ maximize(struct cg_view *view, int output_width, int output_height) struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view); wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, view->lx, view->ly, output_width, output_height); - wlr_xwayland_surface_set_maximized(xwayland_view->xwayland_surface, true); + wlr_xwayland_surface_set_maximized(xwayland_view->xwayland_surface, true, true); } static void From 119f98f2b8f98789197b5acacd15546f14b43714 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 1 Jun 2025 15:08:50 +0200 Subject: [PATCH 226/233] xdg_shell: rename xdg_toplevel signal handlers These handlers aren't invoked for all types of xdg_shell surfaces: they are only invoked for xdg_toplevel, and are not for xdg_popup. Rename them accordingly. --- xdg_shell.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index 10224ae..cc86bf6 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -184,7 +184,7 @@ destroy(struct cg_view *view) } static void -handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void *data) +handle_xdg_toplevel_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); @@ -201,7 +201,7 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void * } static void -handle_xdg_shell_surface_unmap(struct wl_listener *listener, void *data) +handle_xdg_toplevel_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; @@ -210,7 +210,7 @@ handle_xdg_shell_surface_unmap(struct wl_listener *listener, void *data) } static void -handle_xdg_shell_surface_map(struct wl_listener *listener, void *data) +handle_xdg_toplevel_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; @@ -219,7 +219,7 @@ handle_xdg_shell_surface_map(struct wl_listener *listener, void *data) } static void -handle_xdg_shell_surface_commit(struct wl_listener *listener, void *data) +handle_xdg_toplevel_commit(struct wl_listener *listener, void *data) { struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, commit); @@ -233,7 +233,7 @@ handle_xdg_shell_surface_commit(struct wl_listener *listener, void *data) } static void -handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data) +handle_xdg_toplevel_destroy(struct wl_listener *listener, void *data) { struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, destroy); struct cg_view *view = &xdg_shell_view->view; @@ -273,15 +273,15 @@ handle_new_xdg_toplevel(struct wl_listener *listener, void *data) view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); xdg_shell_view->xdg_toplevel = toplevel; - xdg_shell_view->commit.notify = handle_xdg_shell_surface_commit; + xdg_shell_view->commit.notify = handle_xdg_toplevel_commit; wl_signal_add(&toplevel->base->surface->events.commit, &xdg_shell_view->commit); - xdg_shell_view->map.notify = handle_xdg_shell_surface_map; + xdg_shell_view->map.notify = handle_xdg_toplevel_map; wl_signal_add(&toplevel->base->surface->events.map, &xdg_shell_view->map); - xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap; + xdg_shell_view->unmap.notify = handle_xdg_toplevel_unmap; wl_signal_add(&toplevel->base->surface->events.unmap, &xdg_shell_view->unmap); - xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy; + xdg_shell_view->destroy.notify = handle_xdg_toplevel_destroy; wl_signal_add(&toplevel->events.destroy, &xdg_shell_view->destroy); - xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen; + xdg_shell_view->request_fullscreen.notify = handle_xdg_toplevel_request_fullscreen; wl_signal_add(&toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); toplevel->base->data = xdg_shell_view; From 60d41fb93c2fad58bc30ebd511390d81e7579789 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 1 Jun 2025 15:05:37 +0200 Subject: [PATCH 227/233] xdg_shell: handle xdg_popup reposition signal We are advertising xdg-shell v4, but forgot to handle this signal. --- xdg_shell.c | 12 ++++++++++++ xdg_shell.h | 1 + 2 files changed, 13 insertions(+) diff --git a/xdg_shell.c b/xdg_shell.c index cc86bf6..117a344 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -293,6 +293,7 @@ popup_handle_destroy(struct wl_listener *listener, void *data) struct cg_xdg_popup *popup = wl_container_of(listener, popup, destroy); wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->commit.link); + wl_list_remove(&popup->reposition.link); free(popup); } @@ -306,6 +307,14 @@ popup_handle_commit(struct wl_listener *listener, void *data) } } +static void +popup_handle_reposition(struct wl_listener *listener, void *data) +{ + struct cg_xdg_popup *popup = wl_container_of(listener, popup, reposition); + + popup_unconstrain(popup->xdg_popup); +} + void handle_new_xdg_popup(struct wl_listener *listener, void *data) { @@ -350,6 +359,9 @@ handle_new_xdg_popup(struct wl_listener *listener, void *data) popup->commit.notify = popup_handle_commit; wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + popup->reposition.notify = popup_handle_reposition; + wl_signal_add(&wlr_popup->events.reposition, &popup->reposition); + struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, wlr_popup->base); if (popup_scene_tree == NULL) { wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); diff --git a/xdg_shell.h b/xdg_shell.h index 1fc000a..f819549 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -31,6 +31,7 @@ struct cg_xdg_popup { struct wl_listener destroy; struct wl_listener commit; + struct wl_listener reposition; }; void handle_new_xdg_toplevel(struct wl_listener *listener, void *data); From 63f186632ef721589a68ca47d3ee3949f789337a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 1 Jun 2025 15:13:55 +0200 Subject: [PATCH 228/233] xdg_shell: bump to v5 v5 adds the wm_capabilities event. cage only supports fullscreen. --- cage.c | 2 +- xdg_shell.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 77ebc88..3452239 100644 --- a/cage.c +++ b/cage.c @@ -416,7 +416,7 @@ main(int argc, char *argv[]) wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1); wl_list_init(&server.inhibitors); - struct wlr_xdg_shell *xdg_shell = wlr_xdg_shell_create(server.wl_display, 4); + struct wlr_xdg_shell *xdg_shell = wlr_xdg_shell_create(server.wl_display, 5); if (!xdg_shell) { wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); ret = 1; diff --git a/xdg_shell.c b/xdg_shell.c index 117a344..5493918 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -227,6 +227,8 @@ handle_xdg_toplevel_commit(struct wl_listener *listener, void *data) return; } + wlr_xdg_toplevel_set_wm_capabilities(xdg_shell_view->xdg_toplevel, XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + /* When an xdg_surface performs an initial commit, the compositor must * reply with a configure so the client can map the surface. */ view_position(&xdg_shell_view->view); From e8eec5412938c4600e4a2ba912207efe3d9e41ff Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 12 Jun 2025 00:04:54 +0200 Subject: [PATCH 229/233] ci: install libdisplay-info This dependency was missing. --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e0f8093..809e858 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,13 +26,13 @@ jobs: - 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-dev scdoc-doc hwdata + 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-dev scdoc-doc hwdata libdisplay-info-dev - 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 + pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc libdisplay-info - name: Fetch wlroots as a subproject run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION @@ -53,7 +53,7 @@ jobs: - name: Install dependencies run: | pacman-key --init - pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata + pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata libdisplay-info - name: Fetch wlroots as a subproject run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Check for formatting changes @@ -72,7 +72,7 @@ jobs: - name: Install dependencies run: | pacman-key --init - pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata + pacman -Syu --noconfirm xcb-util-wm seatd git clang meson libinput libdrm mesa libxkbcommon wayland wayland-protocols xorg-server-xwayland scdoc hwdata libdisplay-info - name: Fetch wlroots as a subproject run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Run scan-build From c311ee5cdc9f17c04582b6603cf263aff570499f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 12 Jun 2025 00:10:40 +0200 Subject: [PATCH 230/233] ci: set --wrap-mode=nodownload Make sure Meson doesn't automagically download and build dependencies, so that we use system libraries. --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 809e858..31693bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,7 +39,7 @@ jobs: - name: Compile Cage (XWayland=${{ matrix.xwayland }}) run: | - meson --fatal-meson-warnings \ + meson --fatal-meson-warnings --wrap-mode=nodownload \ build-${{ matrix.CC }}-${{matrix.xwayland }} \ -Dwlroots:xwayland=${{ matrix.xwayland }} ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }} @@ -58,7 +58,7 @@ jobs: run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Check for formatting changes run: | - meson build-clang-format -Dwlroots:xwayland=enabled + meson --wrap-mode=nodownload build-clang-format -Dwlroots:xwayland=enabled ninja -C build-clang-format clang-format-check scan-build: @@ -77,5 +77,5 @@ jobs: run: git clone https://gitlab.freedesktop.org/wlroots/wlroots.git subprojects/wlroots -b $WLROOTS_VERSION - name: Run scan-build run: | - meson build-scan-build -Dwlroots:xwayland=enabled + meson --wrap-mode=nodownload build-scan-build -Dwlroots:xwayland=enabled ninja -C build-scan-build scan-build From 3da3ec0c2776594a546478f0fc31f96ef74e03ac Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 16:36:55 +0100 Subject: [PATCH 231/233] output: use backend commits Pass the whole new desired state to the backend, so that the backend can leverage KMS atomic commits. --- output.c | 85 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/output.c b/output.c index 5ccc939..093836b 100644 --- a/output.c +++ b/output.c @@ -21,12 +21,14 @@ #if WLR_HAS_X11_BACKEND #include #endif +#include #include #include #include #include #include #include +#include #include #include #include @@ -130,31 +132,6 @@ output_disable(struct cg_output *output) output_layout_remove(output); } -static bool -output_apply_config(struct cg_output *output, struct wlr_output_configuration_head_v1 *head, bool test_only) -{ - struct wlr_output_state state = {0}; - wlr_output_head_v1_state_apply(&head->state, &state); - - if (test_only) { - bool ret = wlr_output_test_state(output->wlr_output, &state); - return ret; - } - - /* Apply output configuration */ - if (!wlr_output_commit_state(output->wlr_output, &state)) { - return false; - } - - if (head->state.enabled) { - output_layout_add(output, head->state.x, head->state.y); - } else { - output_layout_remove(output); - } - - return true; -} - static void handle_output_frame(struct wl_listener *listener, void *data) { @@ -355,17 +332,63 @@ output_set_window_title(struct cg_output *output, const char *title) static bool output_config_apply(struct cg_server *server, struct wlr_output_configuration_v1 *config, bool test_only) { - struct wlr_output_configuration_head_v1 *head; + bool ok = false; - wl_list_for_each (head, &config->heads, link) { - struct cg_output *output = head->state.output->data; + size_t states_len; + struct wlr_backend_output_state *states = wlr_output_configuration_v1_build_state(config, &states_len); + if (states == NULL) { + return false; + } - if (!output_apply_config(output, head, test_only)) { - return false; + struct wlr_output_swapchain_manager swapchain_manager; + wlr_output_swapchain_manager_init(&swapchain_manager, server->backend); + + ok = wlr_output_swapchain_manager_prepare(&swapchain_manager, states, states_len); + if (!ok || test_only) { + goto out; + } + + for (size_t i = 0; i < states_len; i++) { + struct wlr_backend_output_state *backend_state = &states[i]; + struct cg_output *output = backend_state->output->data; + + struct wlr_swapchain *swapchain = + wlr_output_swapchain_manager_get_swapchain(&swapchain_manager, backend_state->output); + struct wlr_scene_output_state_options options = { + .swapchain = swapchain, + }; + struct wlr_output_state *state = &backend_state->base; + if (!wlr_scene_output_build_state(output->scene_output, state, &options)) { + ok = false; + goto out; } } - return true; + ok = wlr_backend_commit(server->backend, states, states_len); + if (!ok) { + goto out; + } + + wlr_output_swapchain_manager_apply(&swapchain_manager); + + struct wlr_output_configuration_head_v1 *head; + wl_list_for_each (head, &config->heads, link) { + struct cg_output *output = head->state.output->data; + + if (head->state.enabled) { + output_layout_add(output, head->state.x, head->state.y); + } else { + output_layout_remove(output); + } + } + +out: + wlr_output_swapchain_manager_finish(&swapchain_manager); + for (size_t i = 0; i < states_len; i++) { + wlr_output_state_finish(&states[i].base); + } + free(states); + return ok; } void From 2e593fe5a8a2186a558ceb414674775e4ba5d2b1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 29 Jun 2025 20:18:33 +0200 Subject: [PATCH 232/233] Fix renderer, allocator and scene memory leaks on exit --- cage.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cage.c b/cage.c index 3452239..9b7c510 100644 --- a/cage.c +++ b/cage.c @@ -630,5 +630,8 @@ end: /* This function is not null-safe, but we only ever get here with a proper wl_display. */ wl_display_destroy(server.wl_display); + wlr_scene_node_destroy(&server.scene->tree.node); + wlr_allocator_destroy(server.allocator); + wlr_renderer_destroy(server.renderer); return ret; } From f9626f79519f8ee22d7bb0c3880a66791d82f923 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Oct 2025 17:46:45 +0200 Subject: [PATCH 233/233] build: bump version to 0.2.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 07ca800..f8ccd76 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('cage', 'c', - version: '0.2.0', + version: '0.2.1', license: 'MIT', meson_version: '>=0.58.1', default_options: [