mirror of
https://github.com/cage-kiosk/cage.git
synced 2025-10-29 05:40:19 -04:00
Compare commits
70 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9626f7951 | ||
|
|
2e593fe5a8 | ||
|
|
3da3ec0c27 | ||
|
|
c311ee5cdc | ||
|
|
e8eec54129 | ||
|
|
63f186632e | ||
|
|
60d41fb93c | ||
|
|
119f98f2b8 | ||
|
|
9ad44e4f52 | ||
|
|
6efb3b5042 | ||
|
|
e21c155bcd | ||
|
|
6b1ba34a4a | ||
|
|
360e259ca5 | ||
|
|
19157d3564 | ||
|
|
852839e59f | ||
|
|
0208f565dc | ||
|
|
e128a9f251 | ||
|
|
34de3f7bac | ||
|
|
f0651c7671 | ||
|
|
412c11ea91 | ||
|
|
1abf7e5a4b | ||
|
|
fa90174607 | ||
|
|
17af2f7be9 | ||
|
|
a81cc2a8e4 | ||
|
|
874a4a1e79 | ||
|
|
7cc49d2292 | ||
|
|
b9add8b729 | ||
|
|
47ea6a5d68 | ||
|
|
8714a82c24 | ||
|
|
eaeab71ffa | ||
|
|
69c5eccc50 | ||
|
|
df508d65e7 | ||
|
|
018d5bc4b9 | ||
|
|
d3fb99d665 | ||
|
|
e7d8780f46 | ||
|
|
9d43282fa0 | ||
|
|
d07afac4ae | ||
|
|
767ccf9bbd | ||
|
|
b6f8f92585 | ||
|
|
8a009212bc | ||
|
|
f0bc13bef7 | ||
|
|
63c0887664 | ||
|
|
c9d2f3afac | ||
|
|
b40be06da2 | ||
|
|
67def26d83 | ||
|
|
c801544d61 | ||
|
|
1ff7945ba1 | ||
|
|
a30f2bcec1 | ||
|
|
b55e40ad9d | ||
|
|
2d4b7a4e23 | ||
|
|
4ea6a8b1a7 | ||
|
|
8df120dafd | ||
|
|
2f7ab094d4 | ||
|
|
b51a6e950f | ||
|
|
b772a00df8 | ||
|
|
64e2a44124 | ||
|
|
624355485a | ||
|
|
34eb3ec2c8 | ||
|
|
1f3e3043dd | ||
|
|
d40dd3bd99 | ||
|
|
2ab480910e | ||
|
|
efbf7c035b | ||
|
|
4dc3cf80b2 | ||
|
|
a769943447 | ||
|
|
96ffaa340e | ||
|
|
7ec7e3df2b | ||
|
|
121e3ac8b2 | ||
|
|
9a4310f8b6 | ||
|
|
d519b5b529 | ||
|
|
ea95a8af72 |
18 changed files with 672 additions and 384 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
|
@ -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
|
||||||
29
.github/workflows/main.yml
vendored
29
.github/workflows/main.yml
vendored
|
|
@ -5,14 +5,18 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
WLROOTS_VERSION: 0.19
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
compile:
|
compile:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
CC: [ gcc, clang ]
|
CC: [ gcc, clang ]
|
||||||
OS: [ "alpine:edge", "archlinux:base-devel" ]
|
OS: [ "alpine:edge", "archlinux:base-devel" ]
|
||||||
xwayland: [ true, false ]
|
xwayland: [ enabled, disabled ]
|
||||||
container: ${{ matrix.OS }}
|
container: ${{ matrix.OS }}
|
||||||
env:
|
env:
|
||||||
CC: ${{ matrix.CC }}
|
CC: ${{ matrix.CC }}
|
||||||
|
|
@ -22,21 +26,22 @@ jobs:
|
||||||
|
|
||||||
- name: Install dependencies (Alpine)
|
- name: Install dependencies (Alpine)
|
||||||
if: "matrix.OS == 'alpine:edge'"
|
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 libdisplay-info-dev
|
||||||
|
|
||||||
- name: Install dependencies (Arch)
|
- name: Install dependencies (Arch)
|
||||||
if: "matrix.OS == 'archlinux:base-devel'"
|
if: "matrix.OS == 'archlinux:base-devel'"
|
||||||
run: |
|
run: |
|
||||||
pacman-key --init
|
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
|
- 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 $WLROOTS_VERSION
|
||||||
|
|
||||||
# TODO: use --fatal-meson-warnings when on wlroots 0.15.0
|
|
||||||
- name: Compile Cage (XWayland=${{ matrix.xwayland }})
|
- name: Compile Cage (XWayland=${{ matrix.xwayland }})
|
||||||
run: |
|
run: |
|
||||||
meson build-${{ matrix.CC }}-${{matrix.xwayland }} -Dxwayland=${{ matrix.xwayland }}
|
meson --fatal-meson-warnings --wrap-mode=nodownload \
|
||||||
|
build-${{ matrix.CC }}-${{matrix.xwayland }} \
|
||||||
|
-Dwlroots:xwayland=${{ matrix.xwayland }}
|
||||||
ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }}
|
ninja -C build-${{ matrix.CC }}-${{matrix.xwayland }}
|
||||||
|
|
||||||
format:
|
format:
|
||||||
|
|
@ -48,12 +53,12 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
pacman-key --init
|
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
|
- 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 $WLROOTS_VERSION
|
||||||
- name: Check for formatting changes
|
- name: Check for formatting changes
|
||||||
run: |
|
run: |
|
||||||
meson build-clang-format -Dxwayland=true
|
meson --wrap-mode=nodownload build-clang-format -Dwlroots:xwayland=enabled
|
||||||
ninja -C build-clang-format clang-format-check
|
ninja -C build-clang-format clang-format-check
|
||||||
|
|
||||||
scan-build:
|
scan-build:
|
||||||
|
|
@ -67,10 +72,10 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
pacman-key --init
|
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
|
- 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 $WLROOTS_VERSION
|
||||||
- name: Run scan-build
|
- name: Run scan-build
|
||||||
run: |
|
run: |
|
||||||
meson build-scan-build -Dxwayland=true
|
meson --wrap-mode=nodownload build-scan-build -Dwlroots:xwayland=enabled
|
||||||
ninja -C build-scan-build scan-build
|
ninja -C build-scan-build scan-build
|
||||||
|
|
|
||||||
37
README.md
37
README.md
|
|
@ -8,57 +8,54 @@ application.
|
||||||
This README is only relevant for development resources and instructions. For a
|
This README is only relevant for development resources and instructions. For a
|
||||||
description of Cage and installation instructions for end-users, please see
|
description of Cage and installation instructions for end-users, please see
|
||||||
[its project page](https://www.hjdskes.nl/projects/cage) and [the
|
[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/).
|
||||||
|
See [the man page](./cage.1.scd) for a list of possible environment variables and run options.
|
||||||
|
|
||||||
## Release signatures
|
## 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
|
||||||
[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).
|
All releases are published on [GitHub](https://github.com/cage-kiosk/cage/releases).
|
||||||
|
|
||||||
## Building and running Cage
|
## Building and running Cage
|
||||||
|
|
||||||
You can build Cage with the [meson](https://mesonbuild.com/) build system. It
|
You can build Cage with the [meson](https://mesonbuild.com/) build system. It
|
||||||
requires wayland, wlroots, and xkbcommon to be installed. Optionally, install
|
requires wayland, wlroots, and xkbcommon to be installed. Optionally, install
|
||||||
scdoc for manual pages. Note that Cage is developed against the latest tag of
|
scdoc for manual pages. Cage is currently based on branch 0.18 of wlroots.
|
||||||
wlroots, in order to not constantly chase breaking changes as soon as they
|
|
||||||
occur.
|
|
||||||
|
|
||||||
Simply execute the following steps to build Cage:
|
Simply execute the following steps to build Cage:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ meson build
|
$ meson setup build
|
||||||
$ ninja -C build
|
$ meson compile -C build
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, this builds a debug build. To build a release build, use `meson
|
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,
|
Cage comes with compile-time support for XWayland. To enable this, make sure
|
||||||
first make sure that your version of wlroots is compiled with this
|
that your version of wlroots is compiled with this option. Note that you'll
|
||||||
option. Then, add `-Dxwayland=true` to the `meson` command above. Note
|
need to have the XWayland binary installed on your system for this to work.
|
||||||
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
|
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
|
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
|
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
|
KMS+DRM backend. In debug mode (default build type with Meson), press
|
||||||
<kbd>Alt</kbd>+<kbd>Esc</kbd> to quit. For more configuration options, see
|
<kbd>Alt</kbd>+<kbd>Esc</kbd> 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.
|
Cage is based on the annotated source of tinywl and rootston.
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
|
||||||
For any bug, please [create an
|
For any bug, please [create an
|
||||||
issue](https://github.com/Hjdskes/cage/issues/new) on
|
issue](https://github.com/cage-kiosk/cage/issues/new) on
|
||||||
[GitHub](https://github.com/Hjdskes/cage).
|
[GitHub](https://github.com/cage-kiosk/cage).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Please see
|
Please see
|
||||||
[LICENSE](https://github.com/Hjdskes/cage/blob/master/LICENSE) on
|
[LICENSE](https://github.com/cage-kiosk/cage/blob/master/LICENSE) on
|
||||||
[GitHub](https://github.com/Hjdskes/cage).
|
[GitHub](https://github.com/cage-kiosk/cage).
|
||||||
|
|
||||||
Copyright © 2018-2020 Jente Hidskes <dev@hjdskes.nl>
|
Copyright © 2018-2020 Jente Hidskes <dev@hjdskes.nl>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ cage - a Wayland kiosk compositor
|
||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
*cage* [-dhmrsv] [--] _application_ [application argument ...]
|
*cage* [options...] [--] [_application_...]
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
|
|
@ -19,6 +19,9 @@ activities outside the scope of the running application are prevented.
|
||||||
*-d*
|
*-d*
|
||||||
Don't draw client side decorations when possible.
|
Don't draw client side decorations when possible.
|
||||||
|
|
||||||
|
*-D*
|
||||||
|
Enable debug logging.
|
||||||
|
|
||||||
*-h*
|
*-h*
|
||||||
Show the help message.
|
Show the help message.
|
||||||
|
|
||||||
|
|
@ -61,7 +64,7 @@ _XKB_DEFAULT_VARIANT_, _XKB_DEFAULT_OPTIONS_
|
||||||
|
|
||||||
# BUGS
|
# BUGS
|
||||||
|
|
||||||
Report bugs at https://github.com/Hjdskes/cage
|
Report bugs at https://github.com/cage-kiosk/cage
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
|
|
|
||||||
260
cage.c
260
cage.c
|
|
@ -25,11 +25,13 @@
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
|
||||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||||
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output_management_v1.h>
|
#include <wlr/types/wlr_output_management_v1.h>
|
||||||
#include <wlr/types/wlr_presentation_time.h>
|
#include <wlr/types/wlr_presentation_time.h>
|
||||||
|
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||||
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
#include <wlr/types/wlr_screencopy_v1.h>
|
#include <wlr/types/wlr_screencopy_v1.h>
|
||||||
#include <wlr/types/wlr_server_decoration.h>
|
#include <wlr/types/wlr_server_decoration.h>
|
||||||
|
|
@ -59,10 +61,28 @@
|
||||||
#include "xwayland.h"
|
#include "xwayland.h"
|
||||||
#endif
|
#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
|
static int
|
||||||
sigchld_handler(int fd, uint32_t mask, void *data)
|
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 Cage's read pipe. */
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -73,7 +93,8 @@ sigchld_handler(int fd, uint32_t mask, void *data)
|
||||||
wlr_log(WLR_DEBUG, "Connection closed by server");
|
wlr_log(WLR_DEBUG, "Connection closed by server");
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_display_terminate(display);
|
server->return_app_code = true;
|
||||||
|
server_terminate(server);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +118,7 @@ set_cloexec(int fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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];
|
int fd[2];
|
||||||
if (pipe(fd) != 0) {
|
if (pipe(fd) != 0) {
|
||||||
|
|
@ -131,15 +152,15 @@ spawn_primary_client(struct wl_display *display, char *argv[], pid_t *pid_out, s
|
||||||
/* Close write, we only need read in Cage. */
|
/* Close write, we only need read in Cage. */
|
||||||
close(fd[1]);
|
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;
|
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);
|
wlr_log(WLR_DEBUG, "Child process created with pid %d", pid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
cleanup_primary_client(pid_t pid)
|
cleanup_primary_client(pid_t pid)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
@ -148,9 +169,14 @@ cleanup_primary_client(pid_t pid)
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
wlr_log(WLR_DEBUG, "Child exited normally with exit status %d", WEXITSTATUS(status));
|
wlr_log(WLR_DEBUG, "Child exited normally with exit status %d", WEXITSTATUS(status));
|
||||||
|
return WEXITSTATUS(status);
|
||||||
} else if (WIFSIGNALED(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));
|
wlr_log(WLR_DEBUG, "Child was terminated by a signal (%d)", WTERMSIG(status));
|
||||||
|
return 128 + WTERMSIG(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -181,13 +207,13 @@ drop_permissions(void)
|
||||||
static int
|
static int
|
||||||
handle_signal(int signal, void *data)
|
handle_signal(int signal, void *data)
|
||||||
{
|
{
|
||||||
struct wl_display *display = data;
|
struct cg_server *server = data;
|
||||||
|
|
||||||
switch (signal) {
|
switch (signal) {
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
/* Fallthrough */
|
/* Fallthrough */
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
wl_display_terminate(display);
|
server_terminate(server);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -198,9 +224,10 @@ static void
|
||||||
usage(FILE *file, const char *cage)
|
usage(FILE *file, const char *cage)
|
||||||
{
|
{
|
||||||
fprintf(file,
|
fprintf(file,
|
||||||
"Usage: %s [OPTIONS] [--] APPLICATION\n"
|
"Usage: %s [OPTIONS] [--] [APPLICATION...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -d\t Don't draw client side decorations, when possible\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"
|
" -h\t Display this help message\n"
|
||||||
" -m extend Extend the display across all connected outputs (default)\n"
|
" -m extend Extend the display across all connected outputs (default)\n"
|
||||||
" -m last Use only the last connected output\n"
|
" -m last Use only the last connected output\n"
|
||||||
|
|
@ -215,11 +242,14 @@ static bool
|
||||||
parse_args(struct cg_server *server, int argc, char *argv[])
|
parse_args(struct cg_server *server, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt(argc, argv, "dhm:sv")) != -1) {
|
while ((c = getopt(argc, argv, "dDhm:sv")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
server->xdg_decoration = true;
|
server->xdg_decoration = true;
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
server->log_level = WLR_DEBUG;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(stdout, argv[0]);
|
usage(stdout, argv[0]);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -242,53 +272,26 @@ parse_args(struct cg_server *server, int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optind >= argc) {
|
|
||||||
usage(stderr, argv[0]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct cg_server server = {0};
|
struct cg_server server = {.log_level = WLR_INFO};
|
||||||
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 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;
|
pid_t pid = 0;
|
||||||
int ret = 0;
|
int ret = 0, app_ret = 0;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
server.log_level = WLR_DEBUG;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!parse_args(&server, argc, argv)) {
|
if (!parse_args(&server, argc, argv)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
wlr_log_init(server.log_level, NULL);
|
||||||
wlr_log_init(WLR_DEBUG, NULL);
|
|
||||||
#else
|
|
||||||
wlr_log_init(WLR_ERROR, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Wayland requires XDG_RUNTIME_DIR to be set. */
|
/* Wayland requires XDG_RUNTIME_DIR to be set. */
|
||||||
if (!getenv("XDG_RUNTIME_DIR")) {
|
if (!getenv("XDG_RUNTIME_DIR")) {
|
||||||
|
|
@ -302,11 +305,14 @@ main(int argc, char *argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_loop = wl_display_get_event_loop(server.wl_display);
|
server.display_destroy.notify = handle_display_destroy;
|
||||||
sigint_source = wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display);
|
wl_display_add_destroy_listener(server.wl_display, &server.display_destroy);
|
||||||
sigterm_source = wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display);
|
|
||||||
|
|
||||||
server.backend = wlr_backend_autocreate(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);
|
||||||
|
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) {
|
if (!server.backend) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the wlroots backend");
|
wlr_log(WLR_ERROR, "Unable to create the wlroots backend");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -337,7 +343,7 @@ main(int argc, char *argv[])
|
||||||
wl_list_init(&server.views);
|
wl_list_init(&server.views);
|
||||||
wl_list_init(&server.outputs);
|
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) {
|
if (!server.output_layout) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create output layout");
|
wlr_log(WLR_ERROR, "Unable to create output layout");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -353,29 +359,33 @@ main(int argc, char *argv[])
|
||||||
goto end;
|
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);
|
||||||
|
|
||||||
compositor = wlr_compositor_create(server.wl_display, server.renderer);
|
struct wlr_compositor *compositor = wlr_compositor_create(server.wl_display, 6, server.renderer);
|
||||||
if (!compositor) {
|
if (!compositor) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the wlroots compositor");
|
wlr_log(WLR_ERROR, "Unable to create the wlroots compositor");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
subcompositor = wlr_subcompositor_create(server.wl_display);
|
if (!wlr_subcompositor_create(server.wl_display)) {
|
||||||
if (!subcompositor) {
|
|
||||||
wlr_log(WLR_ERROR, "Unable to create the wlroots subcompositor");
|
wlr_log(WLR_ERROR, "Unable to create the wlroots subcompositor");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_device_manager = wlr_data_device_manager_create(server.wl_display);
|
if (!wlr_data_device_manager_create(server.wl_display)) {
|
||||||
if (!data_device_manager) {
|
|
||||||
wlr_log(WLR_ERROR, "Unable to create the data device manager");
|
wlr_log(WLR_ERROR, "Unable to create the data device manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
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
|
/* Configure a listener to be notified when new outputs are
|
||||||
* available on the backend. We use this only to detect the
|
* available on the backend. We use this only to detect the
|
||||||
* first output and ignore subsequent outputs. */
|
* first output and ignore subsequent outputs. */
|
||||||
|
|
@ -389,7 +399,7 @@ main(int argc, char *argv[])
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
server.idle = wlr_idle_create(server.wl_display);
|
server.idle = wlr_idle_notifier_v1_create(server.wl_display);
|
||||||
if (!server.idle) {
|
if (!server.idle) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the idle tracker");
|
wlr_log(WLR_ERROR, "Unable to create the idle tracker");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -406,16 +416,19 @@ main(int argc, char *argv[])
|
||||||
wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1);
|
wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1);
|
||||||
wl_list_init(&server.inhibitors);
|
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, 5);
|
||||||
if (!xdg_shell) {
|
if (!xdg_shell) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the XDG shell interface");
|
wlr_log(WLR_ERROR, "Unable to create the XDG shell interface");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new;
|
server.new_xdg_toplevel.notify = handle_new_xdg_toplevel;
|
||||||
wl_signal_add(&xdg_shell->events.new_surface, &server.new_xdg_shell_surface);
|
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);
|
||||||
|
|
||||||
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) {
|
if (!xdg_decoration_manager) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager");
|
wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -424,7 +437,8 @@ main(int argc, char *argv[])
|
||||||
wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, &server.xdg_toplevel_decoration);
|
wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration, &server.xdg_toplevel_decoration);
|
||||||
server.xdg_toplevel_decoration.notify = handle_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) {
|
if (!server_decoration_manager) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the server decoration manager");
|
wlr_log(WLR_ERROR, "Unable to create the server decoration manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -434,44 +448,38 @@ main(int argc, char *argv[])
|
||||||
server_decoration_manager, server.xdg_decoration ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER
|
server_decoration_manager, server.xdg_decoration ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER
|
||||||
: WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT);
|
: WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT);
|
||||||
|
|
||||||
viewporter = wlr_viewporter_create(server.wl_display);
|
if (!wlr_viewporter_create(server.wl_display)) {
|
||||||
if (!viewporter) {
|
|
||||||
wlr_log(WLR_ERROR, "Unable to create the viewporter interface");
|
wlr_log(WLR_ERROR, "Unable to create the viewporter interface");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
presentation = wlr_presentation_create(server.wl_display, server.backend);
|
struct wlr_presentation *presentation = wlr_presentation_create(server.wl_display, server.backend, 2);
|
||||||
if (!presentation) {
|
if (!presentation) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the presentation interface");
|
wlr_log(WLR_ERROR, "Unable to create the presentation interface");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
wlr_scene_set_presentation(server.scene, presentation);
|
|
||||||
|
|
||||||
export_dmabuf_manager = wlr_export_dmabuf_manager_v1_create(server.wl_display);
|
if (!wlr_export_dmabuf_manager_v1_create(server.wl_display)) {
|
||||||
if (!export_dmabuf_manager) {
|
|
||||||
wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager");
|
wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display);
|
if (!wlr_screencopy_manager_v1_create(server.wl_display)) {
|
||||||
if (!screencopy_manager) {
|
|
||||||
wlr_log(WLR_ERROR, "Unable to create the screencopy manager");
|
wlr_log(WLR_ERROR, "Unable to create the screencopy manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
single_pixel_buffer = wlr_single_pixel_buffer_manager_v1_create(server.wl_display);
|
if (!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");
|
wlr_log(WLR_ERROR, "Unable to create the single pixel buffer manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
output_manager = wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout);
|
if (!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");
|
wlr_log(WLR_ERROR, "Unable to create the output manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
|
|
@ -488,14 +496,14 @@ main(int argc, char *argv[])
|
||||||
server.output_manager_test.notify = handle_output_manager_test;
|
server.output_manager_test.notify = handle_output_manager_test;
|
||||||
wl_signal_add(&server.output_manager_v1->events.test, &server.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 (!wlr_gamma_control_manager_v1_create(server.wl_display)) {
|
||||||
if (!gamma_control_manager) {
|
|
||||||
wlr_log(WLR_ERROR, "Unable to create the gamma control manager");
|
wlr_log(WLR_ERROR, "Unable to create the gamma control manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
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) {
|
if (!virtual_keyboard) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the virtual keyboard manager");
|
wlr_log(WLR_ERROR, "Unable to create the virtual keyboard manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -503,7 +511,8 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
wl_signal_add(&virtual_keyboard->events.new_virtual_keyboard, &server.new_virtual_keyboard);
|
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) {
|
if (!virtual_pointer) {
|
||||||
wlr_log(WLR_ERROR, "Unable to create the virtual pointer manager");
|
wlr_log(WLR_ERROR, "Unable to create the virtual pointer manager");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
@ -511,37 +520,45 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
wl_signal_add(&virtual_pointer->events.new_virtual_pointer, &server.new_virtual_pointer);
|
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
|
#if CAGE_HAS_XWAYLAND
|
||||||
xwayland = wlr_xwayland_create(server.wl_display, compositor, true);
|
struct wlr_xcursor_manager *xcursor_manager = NULL;
|
||||||
|
struct wlr_xwayland *xwayland = wlr_xwayland_create(server.wl_display, compositor, true);
|
||||||
if (!xwayland) {
|
if (!xwayland) {
|
||||||
wlr_log(WLR_ERROR, "Cannot create XWayland server");
|
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);
|
|
||||||
|
|
||||||
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 {
|
} 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)) {
|
xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE);
|
||||||
wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme");
|
if (!xcursor_manager) {
|
||||||
}
|
wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager");
|
||||||
struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1);
|
ret = 1;
|
||||||
if (xcursor) {
|
goto end;
|
||||||
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);
|
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
|
#endif
|
||||||
|
|
||||||
|
|
@ -565,29 +582,44 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CAGE_HAS_XWAYLAND
|
#if CAGE_HAS_XWAYLAND
|
||||||
wlr_xwayland_set_seat(xwayland, server.seat->seat);
|
if (xwayland) {
|
||||||
|
wlr_xwayland_set_seat(xwayland, server.seat->seat);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!spawn_primary_client(server.wl_display, argv + optind, &pid, &sigchld_source)) {
|
if (optind < argc && !spawn_primary_client(&server, argv + optind, &pid, &sigchld_source)) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Place the cursor in the center of the output layout. */
|
seat_center_cursor(server.seat);
|
||||||
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);
|
wl_display_run(server.wl_display);
|
||||||
|
|
||||||
#if CAGE_HAS_XWAYLAND
|
#if CAGE_HAS_XWAYLAND
|
||||||
|
if (xwayland) {
|
||||||
|
wl_list_remove(&server.new_xwayland_surface.link);
|
||||||
|
}
|
||||||
wlr_xwayland_destroy(xwayland);
|
wlr_xwayland_destroy(xwayland);
|
||||||
wlr_xcursor_manager_destroy(xcursor_manager);
|
wlr_xcursor_manager_destroy(xcursor_manager);
|
||||||
#endif
|
#endif
|
||||||
wl_display_destroy_clients(server.wl_display);
|
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:
|
end:
|
||||||
cleanup_primary_client(pid);
|
if (pid != 0)
|
||||||
|
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(sigint_source);
|
||||||
wl_event_source_remove(sigterm_source);
|
wl_event_source_remove(sigterm_source);
|
||||||
|
|
@ -598,6 +630,8 @@ end:
|
||||||
/* This function is not null-safe, but we only ever get here
|
/* This function is not null-safe, but we only ever get here
|
||||||
with a proper wl_display. */
|
with a proper wl_display. */
|
||||||
wl_display_destroy(server.wl_display);
|
wl_display_destroy(server.wl_display);
|
||||||
wlr_output_layout_destroy(server.output_layout);
|
wlr_scene_node_destroy(&server.scene->tree.node);
|
||||||
|
wlr_allocator_destroy(server.allocator);
|
||||||
|
wlr_renderer_destroy(server.renderer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
|
||||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||||
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
|
|
||||||
#include "idle_inhibit_v1.h"
|
#include "idle_inhibit_v1.h"
|
||||||
#include "server.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
|
Hence, we simply check for any inhibitors and inhibit
|
||||||
accordingly. */
|
accordingly. */
|
||||||
bool inhibited = !wl_list_empty(&server->inhibitors);
|
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
|
static void
|
||||||
|
|
|
||||||
14
meson.build
14
meson.build
|
|
@ -1,5 +1,5 @@
|
||||||
project('cage', 'c',
|
project('cage', 'c',
|
||||||
version: '0.1.5',
|
version: '0.2.1',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>=0.58.1',
|
meson_version: '>=0.58.1',
|
||||||
default_options: [
|
default_options: [
|
||||||
|
|
@ -35,7 +35,7 @@ if is_freebsd
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
wlroots = dependency('wlroots', version: '>= 0.16.0', fallback: ['wlroots', 'wlroots'])
|
wlroots = dependency('wlroots-0.19', fallback: ['wlroots', 'wlroots'])
|
||||||
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
|
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
|
||||||
wayland_server = dependency('wayland-server')
|
wayland_server = dependency('wayland-server')
|
||||||
xkbcommon = dependency('xkbcommon')
|
xkbcommon = dependency('xkbcommon')
|
||||||
|
|
@ -64,15 +64,7 @@ server_protos = declare_dependency(
|
||||||
sources: server_protos_headers,
|
sources: server_protos_headers,
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_option('xwayland')
|
have_xwayland = wlroots.get_variable(pkgconfig: 'have_xwayland', internal: 'have_xwayland') == 'true'
|
||||||
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')
|
|
||||||
endif
|
|
||||||
have_xwayland = true
|
|
||||||
else
|
|
||||||
have_xwayland = false
|
|
||||||
endif
|
|
||||||
|
|
||||||
version = '@0@'.format(meson.project_version())
|
version = '@0@'.format(meson.project_version())
|
||||||
git = find_program('git', native: true, required: false)
|
git = find_program('git', native: true, required: false)
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
|
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')
|
|
||||||
|
|
|
||||||
227
output.c
227
output.c
|
|
@ -21,14 +21,14 @@
|
||||||
#if WLR_HAS_X11_BACKEND
|
#if WLR_HAS_X11_BACKEND
|
||||||
#include <wlr/backend/x11.h>
|
#include <wlr/backend/x11.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <wlr/render/swapchain.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_output_damage.h>
|
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output_management_v1.h>
|
#include <wlr/types/wlr_output_management_v1.h>
|
||||||
|
#include <wlr/types/wlr_output_swapchain_manager.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OUTPUT_CONFIG_UPDATED \
|
#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)
|
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -68,6 +68,34 @@ update_output_manager_config(struct cg_server *server)
|
||||||
wlr_output_manager_v1_set_configuration(server->output_manager_v1, config);
|
wlr_output_manager_v1_set_configuration(server->output_manager_v1, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
output_layout_add_auto(struct cg_output *output)
|
||||||
|
{
|
||||||
|
assert(output->scene_output != NULL);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
output_layout_remove(struct cg_output *output)
|
||||||
|
{
|
||||||
|
wlr_output_layout_remove(output->server->output_layout, output->wlr_output);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
output_enable(struct cg_output *output)
|
output_enable(struct cg_output *output)
|
||||||
{
|
{
|
||||||
|
|
@ -78,12 +106,12 @@ output_enable(struct cg_output *output)
|
||||||
* duplicate the enabled property in cg_output. */
|
* duplicate the enabled property in cg_output. */
|
||||||
wlr_log(WLR_DEBUG, "Enabling output %s", wlr_output->name);
|
wlr_log(WLR_DEBUG, "Enabling output %s", wlr_output->name);
|
||||||
|
|
||||||
wlr_output_layout_add_auto(output->server->output_layout, wlr_output);
|
struct wlr_output_state state = {0};
|
||||||
wlr_output_enable(wlr_output, true);
|
wlr_output_state_set_enabled(&state, true);
|
||||||
wlr_output_commit(wlr_output);
|
|
||||||
|
|
||||||
output->scene_output = wlr_scene_get_scene_output(output->server->scene, wlr_output);
|
if (wlr_output_commit_state(wlr_output, &state)) {
|
||||||
assert(output->scene_output != NULL);
|
output_layout_add_auto(output);
|
||||||
|
}
|
||||||
|
|
||||||
update_output_manager_config(output->server);
|
update_output_manager_config(output->server);
|
||||||
}
|
}
|
||||||
|
|
@ -92,56 +120,16 @@ static void
|
||||||
output_disable(struct cg_output *output)
|
output_disable(struct cg_output *output)
|
||||||
{
|
{
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
|
||||||
if (!wlr_output->enabled) {
|
if (!wlr_output->enabled) {
|
||||||
wlr_log(WLR_DEBUG, "Not disabling already disabled output %s", wlr_output->name);
|
wlr_log(WLR_DEBUG, "Not disabling already disabled output %s", wlr_output->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
output->scene_output = NULL;
|
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "Disabling output %s", wlr_output->name);
|
wlr_log(WLR_DEBUG, "Disabling output %s", wlr_output->name);
|
||||||
wlr_output_enable(wlr_output, false);
|
struct wlr_output_state state = {0};
|
||||||
wlr_output_layout_remove(output->server->output_layout, wlr_output);
|
wlr_output_state_set_enabled(&state, false);
|
||||||
wlr_output_commit(wlr_output);
|
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);
|
|
||||||
|
|
||||||
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
|
static void
|
||||||
|
|
@ -149,11 +137,11 @@ handle_output_frame(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
struct cg_output *output = wl_container_of(listener, output, frame);
|
struct cg_output *output = wl_container_of(listener, output, frame);
|
||||||
|
|
||||||
if (!output->wlr_output->enabled) {
|
if (!output->wlr_output->enabled || !output->scene_output) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_scene_output_commit(output->scene_output);
|
wlr_scene_output_commit(output->scene_output, NULL);
|
||||||
|
|
||||||
struct timespec now = {0};
|
struct timespec now = {0};
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
@ -170,31 +158,20 @@ handle_output_commit(struct wl_listener *listener, void *data)
|
||||||
* - output layout change will also be called if needed to position the views
|
* - 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 */
|
* - always update output manager configuration even if the output is now disabled */
|
||||||
|
|
||||||
if (event->committed & WLR_OUTPUT_STATE_ENABLED) {
|
if (event->state->committed & OUTPUT_CONFIG_UPDATED) {
|
||||||
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);
|
update_output_manager_config(output->server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_output_mode(struct wl_listener *listener, void *data)
|
handle_output_request_state(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
struct cg_output *output = wl_container_of(listener, output, mode);
|
struct cg_output *output = wl_container_of(listener, output, request_state);
|
||||||
|
struct wlr_output_event_request_state *event = data;
|
||||||
|
|
||||||
if (!output->wlr_output->enabled) {
|
if (wlr_output_commit_state(output->wlr_output, event->state)) {
|
||||||
return;
|
update_output_manager_config(output->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
view_position_all(output->server);
|
|
||||||
update_output_manager_config(output->server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -206,25 +183,40 @@ handle_output_layout_change(struct wl_listener *listener, void *data)
|
||||||
update_output_manager_config(server);
|
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
|
static void
|
||||||
output_destroy(struct cg_output *output)
|
output_destroy(struct cg_output *output)
|
||||||
{
|
{
|
||||||
struct cg_server *server = output->server;
|
struct cg_server *server = output->server;
|
||||||
|
bool was_nested_output = is_nested_output(output);
|
||||||
|
|
||||||
output->wlr_output->data = NULL;
|
output->wlr_output->data = NULL;
|
||||||
|
|
||||||
wl_list_remove(&output->destroy.link);
|
wl_list_remove(&output->destroy.link);
|
||||||
wl_list_remove(&output->commit.link);
|
wl_list_remove(&output->commit.link);
|
||||||
wl_list_remove(&output->mode.link);
|
wl_list_remove(&output->request_state.link);
|
||||||
wl_list_remove(&output->frame.link);
|
wl_list_remove(&output->frame.link);
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
|
|
||||||
wlr_output_layout_remove(server->output_layout, output->wlr_output);
|
output_layout_remove(output);
|
||||||
|
|
||||||
free(output);
|
free(output);
|
||||||
|
|
||||||
if (wl_list_empty(&server->outputs)) {
|
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)) {
|
} 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);
|
struct cg_output *prev = wl_container_of(server->outputs.next, prev, link);
|
||||||
output_enable(prev);
|
output_enable(prev);
|
||||||
|
|
@ -264,27 +256,35 @@ handle_new_output(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
output->commit.notify = handle_output_commit;
|
output->commit.notify = handle_output_commit;
|
||||||
wl_signal_add(&wlr_output->events.commit, &output->commit);
|
wl_signal_add(&wlr_output->events.commit, &output->commit);
|
||||||
output->mode.notify = handle_output_mode;
|
output->request_state.notify = handle_output_request_state;
|
||||||
wl_signal_add(&wlr_output->events.mode, &output->mode);
|
wl_signal_add(&wlr_output->events.request_state, &output->request_state);
|
||||||
output->destroy.notify = handle_output_destroy;
|
output->destroy.notify = handle_output_destroy;
|
||||||
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
||||||
output->frame.notify = handle_output_frame;
|
output->frame.notify = handle_output_frame;
|
||||||
wl_signal_add(&wlr_output->events.frame, &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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_output_state state = {0};
|
||||||
|
wlr_output_state_set_enabled(&state, true);
|
||||||
if (!wl_list_empty(&wlr_output->modes)) {
|
if (!wl_list_empty(&wlr_output->modes)) {
|
||||||
struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output);
|
struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output);
|
||||||
if (preferred_mode) {
|
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;
|
struct wlr_output_mode *mode;
|
||||||
wl_list_for_each (mode, &wlr_output->modes, link) {
|
wl_list_for_each (mode, &wlr_output->modes, link) {
|
||||||
if (mode == preferred_mode) {
|
if (mode == preferred_mode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_set_mode(wlr_output, mode);
|
wlr_output_state_set_mode(&state, mode);
|
||||||
if (wlr_output_test(wlr_output)) {
|
if (wlr_output_test_state(wlr_output, &state)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -301,8 +301,13 @@ handle_new_output(struct wl_listener *listener, void *data)
|
||||||
wlr_output->scale);
|
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);
|
view_position_all(output->server);
|
||||||
|
update_output_manager_config(output->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -327,17 +332,63 @@ output_set_window_title(struct cg_output *output, const char *title)
|
||||||
static bool
|
static bool
|
||||||
output_config_apply(struct cg_server *server, struct wlr_output_configuration_v1 *config, bool test_only)
|
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) {
|
size_t states_len;
|
||||||
struct cg_output *output = head->state.output->data;
|
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)) {
|
struct wlr_output_swapchain_manager swapchain_manager;
|
||||||
return false;
|
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
|
void
|
||||||
|
|
|
||||||
3
output.h
3
output.h
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_output_damage.h>
|
|
||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
|
|
@ -14,7 +13,7 @@ struct cg_output {
|
||||||
struct wlr_scene_output *scene_output;
|
struct wlr_scene_output *scene_output;
|
||||||
|
|
||||||
struct wl_listener commit;
|
struct wl_listener commit;
|
||||||
struct wl_listener mode;
|
struct wl_listener request_state;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
struct wl_listener frame;
|
struct wl_listener frame;
|
||||||
|
|
||||||
|
|
|
||||||
117
seat.c
117
seat.c
|
|
@ -17,11 +17,13 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/backend/multi.h>
|
#include <wlr/backend/multi.h>
|
||||||
|
#include <wlr/backend/session.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_keyboard_group.h>
|
#include <wlr/types/wlr_keyboard_group.h>
|
||||||
#include <wlr/types/wlr_primary_selection.h>
|
#include <wlr/types/wlr_primary_selection.h>
|
||||||
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
#include <wlr/types/wlr_seat.h>
|
#include <wlr/types/wlr_seat.h>
|
||||||
#include <wlr/types/wlr_touch.h>
|
#include <wlr/types/wlr_touch.h>
|
||||||
|
|
@ -63,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_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) {
|
if (!scene_surface) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -126,9 +128,9 @@ update_capabilities(struct cg_seat *seat)
|
||||||
|
|
||||||
/* Hide cursor if the seat doesn't have pointer capability. */
|
/* Hide cursor if the seat doesn't have pointer capability. */
|
||||||
if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) {
|
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 {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,7 +250,7 @@ handle_modifier_event(struct wlr_keyboard *keyboard, struct cg_seat *seat)
|
||||||
wlr_seat_set_keyboard(seat->seat, keyboard);
|
wlr_seat_set_keyboard(seat->seat, keyboard);
|
||||||
wlr_seat_keyboard_notify_modifiers(seat->seat, &keyboard->modifiers);
|
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
|
static bool
|
||||||
|
|
@ -256,22 +258,21 @@ handle_keybinding(struct cg_server *server, xkb_keysym_t sym)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (sym == XKB_KEY_Escape) {
|
if (sym == XKB_KEY_Escape) {
|
||||||
wl_display_terminate(server->wl_display);
|
server_terminate(server);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#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)) {
|
if (wlr_backend_is_multi(server->backend)) {
|
||||||
struct wlr_session *session = wlr_backend_get_session(server->backend);
|
if (server->session) {
|
||||||
if (session) {
|
|
||||||
unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1;
|
unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1;
|
||||||
wlr_session_change_vt(session, vt);
|
wlr_session_change_vt(server->session, vt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
wlr_idle_notify_activity(server->idle, server->seat->seat);
|
wlr_idle_notifier_v1_notify_activity(server->idle, server->seat->seat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,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_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
|
static void
|
||||||
|
|
@ -379,6 +380,16 @@ cleanup:
|
||||||
free(cg_group);
|
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
|
static void
|
||||||
handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard, bool virtual)
|
handle_new_keyboard(struct cg_seat *seat, struct wlr_keyboard *keyboard, bool virtual)
|
||||||
{
|
{
|
||||||
|
|
@ -440,7 +451,7 @@ handle_new_input(struct wl_listener *listener, void *data)
|
||||||
case WLR_INPUT_DEVICE_SWITCH:
|
case WLR_INPUT_DEVICE_SWITCH:
|
||||||
wlr_log(WLR_DEBUG, "Switch input is not implemented");
|
wlr_log(WLR_DEBUG, "Switch input is not implemented");
|
||||||
return;
|
return;
|
||||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
case WLR_INPUT_DEVICE_TABLET:
|
||||||
case WLR_INPUT_DEVICE_TABLET_PAD:
|
case WLR_INPUT_DEVICE_TABLET_PAD:
|
||||||
wlr_log(WLR_DEBUG, "Tablet input is not implemented");
|
wlr_log(WLR_DEBUG, "Tablet input is not implemented");
|
||||||
return;
|
return;
|
||||||
|
|
@ -511,7 +522,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);
|
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
|
static void
|
||||||
|
|
@ -530,7 +541,7 @@ handle_touch_up(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_seat_touch_notify_up(seat->seat, event->time_msec, event->touch_id);
|
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
|
static void
|
||||||
|
|
@ -562,7 +573,16 @@ handle_touch_motion(struct wl_listener *listener, void *data)
|
||||||
seat->touch_ly = ly;
|
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
|
||||||
|
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_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -571,7 +591,7 @@ handle_cursor_frame(struct wl_listener *listener, void *data)
|
||||||
struct cg_seat *seat = wl_container_of(listener, seat, cursor_frame);
|
struct cg_seat *seat = wl_container_of(listener, seat, cursor_frame);
|
||||||
|
|
||||||
wlr_seat_pointer_notify_frame(seat->seat);
|
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
|
static void
|
||||||
|
|
@ -581,8 +601,8 @@ handle_cursor_axis(struct wl_listener *listener, void *data)
|
||||||
struct wlr_pointer_axis_event *event = data;
|
struct wlr_pointer_axis_event *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);
|
event->delta_discrete, event->source, event->relative_direction);
|
||||||
wlr_idle_notify_activity(seat->server->idle, seat->seat);
|
wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -594,24 +614,29 @@ handle_cursor_button(struct wl_listener *listener, void *data)
|
||||||
wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state);
|
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,
|
press_cursor_button(seat, &event->pointer->base, event->time_msec, event->button, event->state, seat->cursor->x,
|
||||||
seat->cursor->y);
|
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
|
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;
|
double sx, sy;
|
||||||
struct wlr_seat *wlr_seat = seat->seat;
|
struct wlr_seat *wlr_seat = seat->seat;
|
||||||
struct wlr_surface *surface = NULL;
|
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) {
|
if (!view) {
|
||||||
wlr_seat_pointer_clear_focus(wlr_seat);
|
wlr_seat_pointer_clear_focus(wlr_seat);
|
||||||
} else {
|
} else {
|
||||||
wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
|
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;
|
struct cg_drag_icon *drag_icon;
|
||||||
|
|
@ -619,7 +644,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time)
|
||||||
drag_icon_update_position(drag_icon);
|
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
|
static void
|
||||||
|
|
@ -628,20 +653,27 @@ handle_cursor_motion_absolute(struct wl_listener *listener, void *data)
|
||||||
struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_absolute);
|
struct cg_seat *seat = wl_container_of(listener, seat, cursor_motion_absolute);
|
||||||
struct wlr_pointer_motion_absolute_event *event = data;
|
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);
|
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);
|
wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
struct wlr_pointer_motion_event *event = data;
|
||||||
|
|
||||||
wlr_cursor_move(seat->cursor, &event->pointer->base, 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);
|
process_cursor_motion(seat, event->time_msec, event->delta_x, event->delta_y, event->unaccel_dx,
|
||||||
wlr_idle_notify_activity(seat->server->idle, seat->seat);
|
event->unaccel_dy);
|
||||||
|
wlr_idle_notifier_v1_notify_activity(seat->server->idle, seat->seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -740,7 +772,7 @@ handle_destroy(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
struct cg_seat *seat = wl_container_of(listener, seat, destroy);
|
struct cg_seat *seat = wl_container_of(listener, seat, destroy);
|
||||||
wl_list_remove(&seat->destroy.link);
|
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_motion_absolute.link);
|
||||||
wl_list_remove(&seat->cursor_button.link);
|
wl_list_remove(&seat->cursor_button.link);
|
||||||
wl_list_remove(&seat->cursor_axis.link);
|
wl_list_remove(&seat->cursor_axis.link);
|
||||||
|
|
@ -748,6 +780,7 @@ handle_destroy(struct wl_listener *listener, void *data)
|
||||||
wl_list_remove(&seat->touch_down.link);
|
wl_list_remove(&seat->touch_down.link);
|
||||||
wl_list_remove(&seat->touch_up.link);
|
wl_list_remove(&seat->touch_up.link);
|
||||||
wl_list_remove(&seat->touch_motion.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_cursor.link);
|
||||||
wl_list_remove(&seat->request_set_selection.link);
|
wl_list_remove(&seat->request_set_selection.link);
|
||||||
wl_list_remove(&seat->request_set_primary_selection.link);
|
wl_list_remove(&seat->request_set_primary_selection.link);
|
||||||
|
|
@ -813,8 +846,8 @@ seat_create(struct cg_server *server, struct wlr_backend *backend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
seat->cursor_motion.notify = handle_cursor_motion;
|
seat->cursor_motion_relative.notify = handle_cursor_motion_relative;
|
||||||
wl_signal_add(&seat->cursor->events.motion, &seat->cursor_motion);
|
wl_signal_add(&seat->cursor->events.motion, &seat->cursor_motion_relative);
|
||||||
seat->cursor_motion_absolute.notify = handle_cursor_motion_absolute;
|
seat->cursor_motion_absolute.notify = handle_cursor_motion_absolute;
|
||||||
wl_signal_add(&seat->cursor->events.motion_absolute, &seat->cursor_motion_absolute);
|
wl_signal_add(&seat->cursor->events.motion_absolute, &seat->cursor_motion_absolute);
|
||||||
seat->cursor_button.notify = handle_cursor_button;
|
seat->cursor_button.notify = handle_cursor_button;
|
||||||
|
|
@ -830,6 +863,8 @@ seat_create(struct cg_server *server, struct wlr_backend *backend)
|
||||||
wl_signal_add(&seat->cursor->events.touch_up, &seat->touch_up);
|
wl_signal_add(&seat->cursor->events.touch_up, &seat->touch_up);
|
||||||
seat->touch_motion.notify = handle_touch_motion;
|
seat->touch_motion.notify = handle_touch_motion;
|
||||||
wl_signal_add(&seat->cursor->events.touch_motion, &seat->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;
|
seat->request_set_cursor.notify = handle_request_set_cursor;
|
||||||
wl_signal_add(&seat->seat->events.request_set_cursor, &seat->request_set_cursor);
|
wl_signal_add(&seat->seat->events.request_set_cursor, &seat->request_set_cursor);
|
||||||
|
|
@ -868,6 +903,11 @@ seat_destroy(struct cg_seat *seat)
|
||||||
wl_list_remove(&seat->request_start_drag.link);
|
wl_list_remove(&seat->request_start_drag.link);
|
||||||
wl_list_remove(&seat->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,
|
// Destroying the wlr seat will trigger the destroy handler on our seat,
|
||||||
// which will in turn free it.
|
// which will in turn free it.
|
||||||
wlr_seat_destroy(seat->seat);
|
wlr_seat_destroy(seat->seat);
|
||||||
|
|
@ -897,7 +937,7 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view)
|
||||||
#if CAGE_HAS_XWAYLAND
|
#if CAGE_HAS_XWAYLAND
|
||||||
if (view->type == CAGE_XWAYLAND_VIEW) {
|
if (view->type == CAGE_XWAYLAND_VIEW) {
|
||||||
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -930,5 +970,14 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view)
|
||||||
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);
|
process_cursor_motion(seat, -1, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
seat.h
4
seat.h
|
|
@ -27,7 +27,7 @@ struct cg_seat {
|
||||||
|
|
||||||
struct wlr_cursor *cursor;
|
struct wlr_cursor *cursor;
|
||||||
struct wlr_xcursor_manager *xcursor_manager;
|
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_motion_absolute;
|
||||||
struct wl_listener cursor_button;
|
struct wl_listener cursor_button;
|
||||||
struct wl_listener cursor_axis;
|
struct wl_listener cursor_axis;
|
||||||
|
|
@ -39,6 +39,7 @@ struct cg_seat {
|
||||||
struct wl_listener touch_down;
|
struct wl_listener touch_down;
|
||||||
struct wl_listener touch_up;
|
struct wl_listener touch_up;
|
||||||
struct wl_listener touch_motion;
|
struct wl_listener touch_motion;
|
||||||
|
struct wl_listener touch_frame;
|
||||||
|
|
||||||
struct wl_list drag_icons;
|
struct wl_list drag_icons;
|
||||||
struct wl_listener request_start_drag;
|
struct wl_listener request_start_drag;
|
||||||
|
|
@ -90,5 +91,6 @@ struct cg_seat *seat_create(struct cg_server *server, struct wlr_backend *backen
|
||||||
void seat_destroy(struct cg_seat *seat);
|
void seat_destroy(struct cg_seat *seat);
|
||||||
struct cg_view *seat_get_focus(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_set_focus(struct cg_seat *seat, struct cg_view *view);
|
||||||
|
void seat_center_cursor(struct cg_seat *seat);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
21
server.h
21
server.h
|
|
@ -4,10 +4,13 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
|
||||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||||
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
#if CAGE_HAS_XWAYLAND
|
#if CAGE_HAS_XWAYLAND
|
||||||
#include <wlr/xwayland.h>
|
#include <wlr/xwayland.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -23,15 +26,19 @@ struct cg_server {
|
||||||
struct wlr_backend *backend;
|
struct wlr_backend *backend;
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
struct wlr_allocator *allocator;
|
struct wlr_allocator *allocator;
|
||||||
|
struct wlr_session *session;
|
||||||
|
struct wl_listener display_destroy;
|
||||||
|
|
||||||
struct cg_seat *seat;
|
struct cg_seat *seat;
|
||||||
struct wlr_idle *idle;
|
struct wlr_idle_notifier_v1 *idle;
|
||||||
struct wlr_idle_inhibit_manager_v1 *idle_inhibit_v1;
|
struct wlr_idle_inhibit_manager_v1 *idle_inhibit_v1;
|
||||||
struct wl_listener new_idle_inhibitor_v1;
|
struct wl_listener new_idle_inhibitor_v1;
|
||||||
struct wl_list inhibitors;
|
struct wl_list inhibitors;
|
||||||
|
|
||||||
enum cg_multi_output_mode output_mode;
|
enum cg_multi_output_mode output_mode;
|
||||||
struct wlr_output_layout *output_layout;
|
struct wlr_output_layout *output_layout;
|
||||||
|
struct wlr_scene_output_layout *scene_output_layout;
|
||||||
|
|
||||||
struct wlr_scene *scene;
|
struct wlr_scene *scene;
|
||||||
/* Includes disabled outputs; depending on the output_mode
|
/* Includes disabled outputs; depending on the output_mode
|
||||||
* some outputs may be disabled. */
|
* some outputs may be disabled. */
|
||||||
|
|
@ -40,7 +47,8 @@ struct cg_server {
|
||||||
struct wl_listener output_layout_change;
|
struct wl_listener output_layout_change;
|
||||||
|
|
||||||
struct wl_listener xdg_toplevel_decoration;
|
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_keyboard;
|
||||||
struct wl_listener new_virtual_pointer;
|
struct wl_listener new_virtual_pointer;
|
||||||
|
|
@ -51,8 +59,15 @@ struct cg_server {
|
||||||
struct wl_listener output_manager_apply;
|
struct wl_listener output_manager_apply;
|
||||||
struct wl_listener output_manager_test;
|
struct wl_listener output_manager_test;
|
||||||
|
|
||||||
|
struct wlr_relative_pointer_manager_v1 *relative_pointer_manager;
|
||||||
|
|
||||||
bool xdg_decoration;
|
bool xdg_decoration;
|
||||||
bool allow_vt_switch;
|
bool allow_vt_switch;
|
||||||
|
bool return_app_code;
|
||||||
|
bool terminated;
|
||||||
|
enum wlr_log_importance log_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void server_terminate(struct cg_server *server);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
8
view.c
8
view.c
|
|
@ -67,7 +67,9 @@ view_maximize(struct cg_view *view, struct wlr_box *layout_box)
|
||||||
view->lx = layout_box->x;
|
view->lx = layout_box->x;
|
||||||
view->ly = layout_box->y;
|
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);
|
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->lx = (layout_box->width - width) / 2;
|
||||||
view->ly = (layout_box->height - height) / 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
|
void
|
||||||
|
|
|
||||||
256
xdg_shell.c
256
xdg_shell.c
|
|
@ -19,21 +19,9 @@
|
||||||
#include "xdg_shell.h"
|
#include "xdg_shell.h"
|
||||||
|
|
||||||
static void
|
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;
|
enum wlr_xdg_toplevel_decoration_v1_mode mode;
|
||||||
|
|
||||||
if (xdg_decoration->server->xdg_decoration) {
|
if (xdg_decoration->server->xdg_decoration) {
|
||||||
mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
|
mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -42,15 +30,48 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data)
|
||||||
wlr_xdg_toplevel_decoration_v1_set_mode(xdg_decoration->wlr_decoration, mode);
|
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 *
|
static struct cg_view *
|
||||||
popup_get_view(struct wlr_xdg_popup *popup)
|
popup_get_view(struct wlr_xdg_popup *popup)
|
||||||
{
|
{
|
||||||
while (true) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(popup->parent);
|
|
||||||
switch (xdg_surface->role) {
|
switch (xdg_surface->role) {
|
||||||
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
|
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
|
||||||
return xdg_surface->data;
|
return xdg_surface->data;
|
||||||
|
|
@ -64,8 +85,13 @@ popup_get_view(struct wlr_xdg_popup *popup)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 cg_server *server = view->server;
|
||||||
struct wlr_box *popup_box = &popup->current.geometry;
|
struct wlr_box *popup_box = &popup->current.geometry;
|
||||||
|
|
||||||
|
|
@ -102,11 +128,10 @@ static void
|
||||||
get_geometry(struct cg_view *view, int *width_out, int *height_out)
|
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 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 = xdg_surface->geometry.width;
|
||||||
*width_out = geom.width;
|
*height_out = xdg_surface->geometry.height;
|
||||||
*height_out = geom.height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -159,7 +184,7 @@ destroy(struct cg_view *view)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_fullscreen);
|
||||||
|
|
||||||
|
|
@ -176,7 +201,7 @@ handle_xdg_shell_surface_request_fullscreen(struct wl_listener *listener, void *
|
||||||
}
|
}
|
||||||
|
|
||||||
static 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_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, unmap);
|
||||||
struct cg_view *view = &xdg_shell_view->view;
|
struct cg_view *view = &xdg_shell_view->view;
|
||||||
|
|
@ -185,7 +210,7 @@ handle_xdg_shell_surface_unmap(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, map);
|
||||||
struct cg_view *view = &xdg_shell_view->view;
|
struct cg_view *view = &xdg_shell_view->view;
|
||||||
|
|
@ -194,11 +219,28 @@ handle_xdg_shell_surface_map(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_xdg_shell_surface_destroy(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);
|
||||||
|
|
||||||
|
if (!xdg_shell_view->xdg_toplevel->base->initial_commit) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
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_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, destroy);
|
||||||
struct cg_view *view = &xdg_shell_view->view;
|
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->map.link);
|
||||||
wl_list_remove(&xdg_shell_view->unmap.link);
|
wl_list_remove(&xdg_shell_view->unmap.link);
|
||||||
wl_list_remove(&xdg_shell_view->destroy.link);
|
wl_list_remove(&xdg_shell_view->destroy.link);
|
||||||
|
|
@ -219,69 +261,117 @@ static const struct cg_view_impl xdg_shell_view_impl = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
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 cg_server *server = wl_container_of(listener, server, new_xdg_toplevel);
|
||||||
struct wlr_xdg_surface *xdg_surface = data;
|
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->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_toplevel_map;
|
||||||
|
wl_signal_add(&toplevel->base->surface->events.map, &xdg_shell_view->map);
|
||||||
|
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_toplevel_destroy;
|
||||||
|
wl_signal_add(&toplevel->events.destroy, &xdg_shell_view->destroy);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
wl_list_remove(&popup->reposition.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct cg_server *server = wl_container_of(listener, server, new_xdg_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
|
||||||
|
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(wlr_popup->parent);
|
||||||
|
if (parent == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (parent->role) {
|
||||||
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
|
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
|
||||||
struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view));
|
parent_scene_tree = view->scene_tree;
|
||||||
if (!xdg_shell_view) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl);
|
|
||||||
xdg_shell_view->xdg_toplevel = xdg_surface->toplevel;
|
|
||||||
|
|
||||||
xdg_shell_view->map.notify = handle_xdg_shell_surface_map;
|
|
||||||
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
|
|
||||||
xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap;
|
|
||||||
wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap);
|
|
||||||
xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy;
|
|
||||||
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
|
|
||||||
xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen;
|
|
||||||
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen);
|
|
||||||
|
|
||||||
xdg_surface->data = xdg_shell_view;
|
|
||||||
break;
|
break;
|
||||||
case WLR_XDG_SURFACE_ROLE_POPUP:;
|
case WLR_XDG_SURFACE_ROLE_POPUP:
|
||||||
struct wlr_xdg_popup *popup = xdg_surface->popup;
|
parent_scene_tree = parent->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_from_wlr_surface(popup->parent);
|
|
||||||
switch (parent->role) {
|
|
||||||
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:;
|
|
||||||
parent_scene_tree = view->scene_tree;
|
|
||||||
break;
|
|
||||||
case WLR_XDG_SURFACE_ROLE_POPUP:
|
|
||||||
parent_scene_tree = parent->data;
|
|
||||||
break;
|
|
||||||
case WLR_XDG_SURFACE_ROLE_NONE:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (parent_scene_tree == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wlr_scene_tree *popup_scene_tree = wlr_scene_xdg_surface_create(parent_scene_tree, xdg_surface);
|
|
||||||
if (popup_scene_tree == NULL) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
popup_unconstrain(view, popup);
|
|
||||||
|
|
||||||
xdg_surface->data = popup_scene_tree;
|
|
||||||
break;
|
break;
|
||||||
case WLR_XDG_SURFACE_ROLE_NONE:
|
case WLR_XDG_SURFACE_ROLE_NONE:
|
||||||
assert(false); // unreachable
|
break;
|
||||||
}
|
}
|
||||||
|
if (parent_scene_tree == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cg_xdg_popup *popup = calloc(1, sizeof(*popup));
|
||||||
|
if (popup == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to allocate popup");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup->xdg_popup = wlr_popup;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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");
|
||||||
|
free(popup);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_popup->base->data = popup_scene_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -300,8 +390,8 @@ handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
xdg_decoration->destroy.notify = xdg_decoration_handle_destroy;
|
xdg_decoration->destroy.notify = xdg_decoration_handle_destroy;
|
||||||
wl_signal_add(&wlr_decoration->events.destroy, &xdg_decoration->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;
|
xdg_decoration->request_mode.notify = xdg_decoration_handle_request_mode;
|
||||||
wl_signal_add(&wlr_decoration->events.request_mode, &xdg_decoration->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);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
xdg_shell.h
13
xdg_shell.h
|
|
@ -12,6 +12,7 @@ struct cg_xdg_shell_view {
|
||||||
struct wlr_xdg_toplevel *xdg_toplevel;
|
struct wlr_xdg_toplevel *xdg_toplevel;
|
||||||
|
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener commit;
|
||||||
struct wl_listener unmap;
|
struct wl_listener unmap;
|
||||||
struct wl_listener map;
|
struct wl_listener map;
|
||||||
struct wl_listener request_fullscreen;
|
struct wl_listener request_fullscreen;
|
||||||
|
|
@ -21,10 +22,20 @@ struct cg_xdg_decoration {
|
||||||
struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration;
|
struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration;
|
||||||
struct cg_server *server;
|
struct cg_server *server;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener commit;
|
||||||
struct wl_listener request_mode;
|
struct wl_listener request_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
void handle_xdg_shell_surface_new(struct wl_listener *listener, void *data);
|
struct cg_xdg_popup {
|
||||||
|
struct wlr_xdg_popup *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);
|
||||||
|
void handle_new_xdg_popup(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data);
|
void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
|
|
|
||||||
43
xwayland.c
43
xwayland.c
|
|
@ -41,8 +41,15 @@ static void
|
||||||
get_geometry(struct cg_view *view, int *width_out, int *height_out)
|
get_geometry(struct cg_view *view, int *width_out, int *height_out)
|
||||||
{
|
{
|
||||||
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
|
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
|
||||||
*width_out = xwayland_view->xwayland_surface->surface->current.width;
|
struct wlr_xwayland_surface *xsurface = xwayland_view->xwayland_surface;
|
||||||
*height_out = xwayland_view->xwayland_surface->surface->current.height;
|
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
|
static bool
|
||||||
|
|
@ -85,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);
|
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,
|
wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, view->lx, view->ly, output_width,
|
||||||
output_height);
|
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
|
static void
|
||||||
|
|
@ -132,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_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, destroy);
|
||||||
struct cg_view *view = &xwayland_view->view;
|
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->destroy.link);
|
||||||
wl_list_remove(&xwayland_view->request_fullscreen.link);
|
wl_list_remove(&xwayland_view->request_fullscreen.link);
|
||||||
xwayland_view->xwayland_surface = NULL;
|
xwayland_view->xwayland_surface = NULL;
|
||||||
|
|
@ -151,6 +156,26 @@ static const struct cg_view_impl xwayland_view_impl = {
|
||||||
.destroy = destroy,
|
.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
|
void
|
||||||
handle_xwayland_surface_new(struct wl_listener *listener, void *data)
|
handle_xwayland_surface_new(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
|
|
@ -166,10 +191,10 @@ handle_xwayland_surface_new(struct wl_listener *listener, void *data)
|
||||||
view_init(&xwayland_view->view, server, CAGE_XWAYLAND_VIEW, &xwayland_view_impl);
|
view_init(&xwayland_view->view, server, CAGE_XWAYLAND_VIEW, &xwayland_view_impl);
|
||||||
xwayland_view->xwayland_surface = xwayland_surface;
|
xwayland_view->xwayland_surface = xwayland_surface;
|
||||||
|
|
||||||
xwayland_view->map.notify = handle_xwayland_surface_map;
|
xwayland_view->associate.notify = handle_xwayland_associate;
|
||||||
wl_signal_add(&xwayland_surface->events.map, &xwayland_view->map);
|
wl_signal_add(&xwayland_surface->events.associate, &xwayland_view->associate);
|
||||||
xwayland_view->unmap.notify = handle_xwayland_surface_unmap;
|
xwayland_view->dissociate.notify = handle_xwayland_dissociate;
|
||||||
wl_signal_add(&xwayland_surface->events.unmap, &xwayland_view->unmap);
|
wl_signal_add(&xwayland_surface->events.dissociate, &xwayland_view->dissociate);
|
||||||
xwayland_view->destroy.notify = handle_xwayland_surface_destroy;
|
xwayland_view->destroy.notify = handle_xwayland_surface_destroy;
|
||||||
wl_signal_add(&xwayland_surface->events.destroy, &xwayland_view->destroy);
|
wl_signal_add(&xwayland_surface->events.destroy, &xwayland_view->destroy);
|
||||||
xwayland_view->request_fullscreen.notify = handle_xwayland_surface_request_fullscreen;
|
xwayland_view->request_fullscreen.notify = handle_xwayland_surface_request_fullscreen;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ struct cg_xwayland_view {
|
||||||
struct cg_view view;
|
struct cg_view view;
|
||||||
struct wlr_xwayland_surface *xwayland_surface;
|
struct wlr_xwayland_surface *xwayland_surface;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener associate;
|
||||||
|
struct wl_listener dissociate;
|
||||||
struct wl_listener unmap;
|
struct wl_listener unmap;
|
||||||
struct wl_listener map;
|
struct wl_listener map;
|
||||||
struct wl_listener request_fullscreen;
|
struct wl_listener request_fullscreen;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue