diff options
42 files changed, 1098 insertions, 220 deletions
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 7199af85..f1c3d839 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,64 +1,26 @@ image: freebsd packages: -- devel/automake +- devel/evdev-proto +- devel/libepoll-shim +- devel/libudev-devd +- devel/meson # implies ninja +- devel/pkgconf +- graphics/libdrm +- graphics/mesa-libs +- graphics/png +- graphics/wayland +- graphics/wayland-protocols - multimedia/ffmpeg -- devel/gmake -- devel/json-c -- devel/libtool +- x11/libX11 +- x11/libinput +- x11/libxcb - x11/libxkbcommon -- textproc/libxslt -- x11-toolkits/pango -- devel/pkgconf -- print/texinfo -- x11/xcb-util-image +- x11/pixman +# - x11/xcb-util-errors # too recent, not in /quarterly - x11/xcb-util-wm -- python36 -- py36-setuptools sources: - https://github.com/swaywm/wlroots tasks: -- setup: | - # Don't build unnecessary stuff - echo "OPTIONS_UNSET+= NLS DOCS EXAMPLES LIBWACOM" | sudo tee -a /etc/make.conf - # Note: this could probably be set in the FreeBSD base image - echo "BATCH=yes" | sudo tee -a /etc/make.conf -- ports_tree: | - # This is ugly, but fetching and extracting the whole ports tree takes a - # really-really long time... - # First we need a clean tree, and renaming is faster than deleting. - sudo mv /usr/ports /usr/ports.orig - sudo mkdir /usr/ports - # Fetch only needed ports - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/GIDs /usr/ports/GIDs - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/Keywords /usr/ports/Keywords - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/Makefile /usr/ports/Makefile - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/Mk /usr/ports/Mk - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/Templates /usr/ports/Templates - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/Tools /usr/ports/Tools - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/UIDs /usr/ports/UIDs - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/libevdev /usr/ports/devel/libevdev - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/libmtdev /usr/ports/devel/libmtdev - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/libudev-devd /usr/ports/devel/libudev-devd - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/meson /usr/ports/devel/meson - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/ninja /usr/ports/devel/ninja - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/py-evdev /usr/ports/devel/py-evdev - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/devel/py-six /usr/ports/devel/py-six - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/graphics/wayland-protocols /usr/ports/graphics/wayland-protocols - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/graphics/wayland /usr/ports/graphics/wayland - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/lang/python27 /usr/ports/lang/python27 - sudo svnlite export --force https://svn.FreeBSD.org/ports/head/lang/python36 /usr/ports/lang/python36 -- fixup_libinput: | - sudo svnlite export https://github.com/FreeBSDDesktop/freebsd-ports/branches/feature/input/devel/libepoll-shim /usr/ports/devel/libepoll-shim - sudo svnlite export https://github.com/FreeBSDDesktop/freebsd-ports/branches/feature/input/x11/libinput /usr/ports/x11/libinput - sudo svnlite export https://github.com/FreeBSDDesktop/freebsd-ports/branches/feature/input/devel/evdev-proto /usr/ports/devel/evdev-proto - sudo svnlite export https://github.com/FreeBSDDesktop/freebsd-ports/branches/feature/input/devel/py-pyudev /usr/ports/devel/py-pyudev -- ports_build: | - # v4l_compat is a dependency of libinput, but the version in the ports tree - # conflicts with the new evdev-proto. It can be safely removed though. - sudo pkg remove -fy v4l_compat - cd /usr/ports/devel/evdev-proto && sudo make install clean - cd /usr/ports/graphics/wayland-protocols/ && sudo make install - cd /usr/ports/x11/libinput/ && sudo make install clean - fixup_epoll: | cat << 'EOF' | sudo tee /usr/local/libdata/pkgconfig/epoll-shim.pc prefix=/usr/local @@ -70,7 +32,8 @@ tasks: Description: epoll shim implemented using kevent Version: 0 Requires: - Libs: -L${libdir} -L${sharedlibdir} -lepoll-shim -lthr + Libs: -L${libdir} -L${sharedlibdir} -lepoll-shim + Libs.private: -pthread -lrt Cflags: -I${includedir} EOF - wlroots: | diff --git a/backend/backend.c b/backend/backend.c index b369a135..33ad20f2 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -11,6 +11,7 @@ #include <wlr/backend/interface.h> #include <wlr/backend/libinput.h> #include <wlr/backend/multi.h> +#include <wlr/backend/noop.h> #include <wlr/backend/session.h> #include <wlr/backend/wayland.h> #include <wlr/config.h> @@ -133,6 +134,20 @@ static struct wlr_backend *attempt_headless_backend( return backend; } +static struct wlr_backend *attempt_noop_backend(struct wl_display *display) { + struct wlr_backend *backend = wlr_noop_backend_create(display); + if (backend == NULL) { + return NULL; + } + + size_t outputs = parse_outputs_env("WLR_NOOP_OUTPUTS"); + for (size_t i = 0; i < outputs; ++i) { + wlr_noop_add_output(backend); + } + + return backend; +} + static struct wlr_backend *attempt_drm_backend(struct wl_display *display, struct wlr_backend *backend, struct wlr_session *session, wlr_renderer_create_func_t create_renderer_func) { @@ -170,6 +185,8 @@ static struct wlr_backend *attempt_backend_by_name(struct wl_display *display, #endif } else if (strcmp(name, "headless") == 0) { return attempt_headless_backend(display, create_renderer_func); + } else if (strcmp(name, "noop") == 0) { + return attempt_noop_backend(display); } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) { // DRM and libinput need a session if (!*session) { diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 735b7c29..28ee41a5 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -391,6 +391,8 @@ static void attempt_enable_needs_modeset(struct wlr_drm_backend *drm) { if (conn->state == WLR_DRM_CONN_NEEDS_MODESET && conn->crtc != NULL && conn->desired_mode != NULL && conn->desired_enabled) { + wlr_log(WLR_DEBUG, "Output %s has a desired mode and a CRTC, " + "attempting a modeset", conn->output.name); drm_connector_set_mode(&conn->output, conn->desired_mode); } } @@ -637,7 +639,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, plane->surf.height, output->transform); struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y }; - wlr_box_transform(&hotspot, &hotspot, + wlr_box_transform(&hotspot, &hotspot, wlr_output_transform_invert(output->transform), plane->surf.width, plane->surf.height); @@ -981,8 +983,17 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { i++; struct wlr_output_mode *mode = conn->output.current_mode; - if (conn->state != WLR_DRM_CONN_CONNECTED || !changed_outputs[i] - || conn->crtc == NULL) { + if (conn->state != WLR_DRM_CONN_CONNECTED || !changed_outputs[i]) { + continue; + } + + if (conn->crtc == NULL) { + wlr_log(WLR_DEBUG, "Output has %s lost its CRTC", + conn->output.name); + conn->state = WLR_DRM_CONN_NEEDS_MODESET; + wlr_output_update_enabled(&conn->output, false); + conn->desired_mode = conn->output.current_mode; + wlr_output_update_mode(&conn->output, NULL); continue; } diff --git a/backend/meson.build b/backend/meson.build index bf9b4f83..39769ecd 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -20,6 +20,8 @@ backend_files = files( 'libinput/tablet_tool.c', 'libinput/touch.c', 'multi/backend.c', + 'noop/backend.c', + 'noop/output.c', 'session/direct-ipc.c', 'session/session.c', 'wayland/backend.c', diff --git a/backend/noop/backend.c b/backend/noop/backend.c new file mode 100644 index 00000000..340fce0d --- /dev/null +++ b/backend/noop/backend.c @@ -0,0 +1,68 @@ +#include <assert.h> +#include <stdlib.h> +#include <wlr/interfaces/wlr_output.h> +#include <wlr/util/log.h> +#include "backend/noop.h" +#include "util/signal.h" + +struct wlr_noop_backend *noop_backend_from_backend( + struct wlr_backend *wlr_backend) { + assert(wlr_backend_is_noop(wlr_backend)); + return (struct wlr_noop_backend *)wlr_backend; +} + +static bool backend_start(struct wlr_backend *wlr_backend) { + struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); + wlr_log(WLR_INFO, "Starting noop backend"); + + struct wlr_noop_output *output; + wl_list_for_each(output, &backend->outputs, link) { + wlr_output_update_enabled(&output->wlr_output, true); + wlr_signal_emit_safe(&backend->backend.events.new_output, + &output->wlr_output); + } + + backend->started = true; + return true; +} + +static void backend_destroy(struct wlr_backend *wlr_backend) { + struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); + if (!wlr_backend) { + return; + } + + struct wlr_noop_output *output, *output_tmp; + wl_list_for_each_safe(output, output_tmp, &backend->outputs, link) { + wlr_output_destroy(&output->wlr_output); + } + + wlr_signal_emit_safe(&wlr_backend->events.destroy, backend); + + free(backend); +} + +static const struct wlr_backend_impl backend_impl = { + .start = backend_start, + .destroy = backend_destroy, +}; + +struct wlr_backend *wlr_noop_backend_create(struct wl_display *display) { + wlr_log(WLR_INFO, "Creating noop backend"); + + struct wlr_noop_backend *backend = + calloc(1, sizeof(struct wlr_noop_backend)); + if (!backend) { + wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_backend"); + return NULL; + } + wlr_backend_init(&backend->backend, &backend_impl); + backend->display = display; + wl_list_init(&backend->outputs); + + return &backend->backend; +} + +bool wlr_backend_is_noop(struct wlr_backend *backend) { + return backend->impl == &backend_impl; +} diff --git a/backend/noop/output.c b/backend/noop/output.c new file mode 100644 index 00000000..a2595eff --- /dev/null +++ b/backend/noop/output.c @@ -0,0 +1,75 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <wlr/interfaces/wlr_output.h> +#include <wlr/util/log.h> +#include "backend/noop.h" +#include "util/signal.h" + +static struct wlr_noop_output *noop_output_from_output( + struct wlr_output *wlr_output) { + assert(wlr_output_is_noop(wlr_output)); + return (struct wlr_noop_output *)wlr_output; +} + +static void output_transform(struct wlr_output *wlr_output, + enum wl_output_transform transform) { + // empty +} + +static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age) { + return true; +} + +static bool output_swap_buffers(struct wlr_output *wlr_output, + pixman_region32_t *damage) { + return true; +} + +static void output_destroy(struct wlr_output *wlr_output) { + struct wlr_noop_output *output = + noop_output_from_output(wlr_output); + + wl_list_remove(&output->link); + + free(output); +} + +static const struct wlr_output_impl output_impl = { + .transform = output_transform, + .destroy = output_destroy, + .make_current = output_make_current, + .swap_buffers = output_swap_buffers, +}; + +bool wlr_output_is_noop(struct wlr_output *wlr_output) { + return wlr_output->impl == &output_impl; +} + +struct wlr_output *wlr_noop_add_output(struct wlr_backend *wlr_backend) { + struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend); + + struct wlr_noop_output *output = calloc(1, sizeof(struct wlr_noop_output)); + if (output == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_output"); + return NULL; + } + output->backend = backend; + wlr_output_init(&output->wlr_output, &backend->backend, &output_impl, + backend->display); + struct wlr_output *wlr_output = &output->wlr_output; + + strncpy(wlr_output->make, "noop", sizeof(wlr_output->make)); + strncpy(wlr_output->model, "noop", sizeof(wlr_output->model)); + snprintf(wlr_output->name, sizeof(wlr_output->name), "NOOP-%d", + wl_list_length(&backend->outputs) + 1); + + wl_list_insert(&backend->outputs, &output->link); + + if (backend->started) { + wlr_output_update_enabled(wlr_output, true); + wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output); + } + + return wlr_output; +} diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 342d0d4e..391cc3fd 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -1,5 +1,5 @@ #include <assert.h> -#include <dev/evdev/input.h> +#include <linux/input.h> #include <errno.h> #include <fcntl.h> #include <signal.h> diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 2b9634da..42ca00e1 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -1,7 +1,7 @@ #define _POSIX_C_SOURCE 200809L #ifdef __FreeBSD__ #define __BSD_VISIBLE 1 -#include <dev/evdev/input.h> +#include <linux/input.h> #endif #include <errno.h> #include <fcntl.h> diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index df1bf431..da41af02 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -18,7 +18,7 @@ #include "backend/wayland.h" #include "util/signal.h" -#include "xdg-shell-unstable-v6-client-protocol.h" +#include "xdg-shell-client-protocol.h" struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend) { assert(wlr_backend_is_wl(backend)); @@ -49,13 +49,13 @@ static int dispatch_events(int fd, uint32_t mask, void *data) { return 0; } -static void xdg_shell_handle_ping(void *data, struct zxdg_shell_v6 *shell, - uint32_t serial) { - zxdg_shell_v6_pong(shell, serial); +static void xdg_wm_base_handle_ping(void *data, + struct xdg_wm_base *base, uint32_t serial) { + xdg_wm_base_pong(base, serial); } -static const struct zxdg_shell_v6_listener xdg_shell_listener = { - xdg_shell_handle_ping, +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + xdg_wm_base_handle_ping, }; static void registry_global(void *data, struct wl_registry *registry, @@ -77,10 +77,10 @@ static void registry_global(void *data, struct wl_registry *registry, wl->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); - } else if (strcmp(iface, zxdg_shell_v6_interface.name) == 0) { - wl->shell = wl_registry_bind(registry, name, - &zxdg_shell_v6_interface, 1); - zxdg_shell_v6_add_listener(wl->shell, &xdg_shell_listener, NULL); + } else if (strcmp(iface, xdg_wm_base_interface.name) == 0) { + wl->xdg_wm_base = wl_registry_bind(registry, name, + &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(wl->xdg_wm_base, &xdg_wm_base_listener, NULL); } } @@ -153,7 +153,7 @@ static void backend_destroy(struct wlr_backend *backend) { if (wl->shm) { wl_shm_destroy(wl->shm); } - zxdg_shell_v6_destroy(wl->shell); + xdg_wm_base_destroy(wl->xdg_wm_base); wl_compositor_destroy(wl->compositor); wl_registry_destroy(wl->registry); wl_display_disconnect(wl->remote_display); @@ -218,9 +218,9 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, "Remote Wayland compositor does not support wl_compositor"); goto error_registry; } - if (!wl->shell) { + if (!wl->xdg_wm_base) { wlr_log(WLR_ERROR, - "Remote Wayland compositor does not support zxdg_shell_v6"); + "Remote Wayland compositor does not support xdg-shell"); goto error_registry; } @@ -267,8 +267,8 @@ error_registry: if (wl->compositor) { wl_compositor_destroy(wl->compositor); } - if (wl->shell) { - zxdg_shell_v6_destroy(wl->shell); + if (wl->xdg_wm_base) { + xdg_wm_base_destroy(wl->xdg_wm_base); } wl_registry_destroy(wl->registry); error_display: diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 89d5b5c9..a515374b 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -16,7 +16,7 @@ #include "backend/wayland.h" #include "util/signal.h" -#include "xdg-shell-unstable-v6-client-protocol.h" +#include "xdg-shell-client-protocol.h" static struct wlr_wl_output *get_wl_output_from_output( struct wlr_output *wlr_output) { @@ -181,8 +181,8 @@ static void output_destroy(struct wlr_output *wlr_output) { wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface); wl_egl_window_destroy(output->egl_window); - zxdg_toplevel_v6_destroy(output->xdg_toplevel); - zxdg_surface_v6_destroy(output->xdg_surface); + xdg_toplevel_destroy(output->xdg_toplevel); + xdg_surface_destroy(output->xdg_surface); wl_surface_destroy(output->surface); free(output); } @@ -229,22 +229,22 @@ bool wlr_output_is_wl(struct wlr_output *wlr_output) { return wlr_output->impl == &output_impl; } -static void xdg_surface_handle_configure(void *data, struct zxdg_surface_v6 *xdg_surface, - uint32_t serial) { +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { struct wlr_wl_output *output = data; assert(output && output->xdg_surface == xdg_surface); - zxdg_surface_v6_ack_configure(xdg_surface, serial); + xdg_surface_ack_configure(xdg_surface, serial); // nothing else? } -static struct zxdg_surface_v6_listener xdg_surface_listener = { +static struct xdg_surface_listener xdg_surface_listener = { .configure = xdg_surface_handle_configure, }; static void xdg_toplevel_handle_configure(void *data, - struct zxdg_toplevel_v6 *xdg_toplevel, + struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states) { struct wlr_wl_output *output = data; assert(output && output->xdg_toplevel == xdg_toplevel); @@ -258,14 +258,14 @@ static void xdg_toplevel_handle_configure(void *data, } static void xdg_toplevel_handle_close(void *data, - struct zxdg_toplevel_v6 *xdg_toplevel) { + struct xdg_toplevel *xdg_toplevel) { struct wlr_wl_output *output = data; assert(output && output->xdg_toplevel == xdg_toplevel); wlr_output_destroy((struct wlr_output *)output); } -static struct zxdg_toplevel_v6_listener xdg_toplevel_listener = { +static struct xdg_toplevel_listener xdg_toplevel_listener = { .configure = xdg_toplevel_handle_configure, .close = xdg_toplevel_handle_close, }; @@ -301,13 +301,13 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { } wl_surface_set_user_data(output->surface, output); output->xdg_surface = - zxdg_shell_v6_get_xdg_surface(backend->shell, output->surface); + xdg_wm_base_get_xdg_surface(backend->xdg_wm_base, output->surface); if (!output->xdg_surface) { wlr_log_errno(WLR_ERROR, "Could not get xdg surface"); goto error; } output->xdg_toplevel = - zxdg_surface_v6_get_toplevel(output->xdg_surface); + xdg_surface_get_toplevel(output->xdg_surface); if (!output->xdg_toplevel) { wlr_log_errno(WLR_ERROR, "Could not get xdg toplevel"); goto error; @@ -315,13 +315,13 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { char title[32]; if (snprintf(title, sizeof(title), "wlroots - %s", wlr_output->name)) { - zxdg_toplevel_v6_set_title(output->xdg_toplevel, title); + xdg_toplevel_set_title(output->xdg_toplevel, title); } - zxdg_toplevel_v6_set_app_id(output->xdg_toplevel, "wlroots"); - zxdg_surface_v6_add_listener(output->xdg_surface, + xdg_toplevel_set_app_id(output->xdg_toplevel, "wlroots"); + xdg_surface_add_listener(output->xdg_surface, &xdg_surface_listener, output); - zxdg_toplevel_v6_add_listener(output->xdg_toplevel, + xdg_toplevel_add_listener(output->xdg_toplevel, &xdg_toplevel_listener, output); wl_surface_commit(output->surface); @@ -365,3 +365,8 @@ error: wlr_output_destroy(&output->wlr_output); return NULL; } + +void wlr_wl_output_set_title(struct wlr_output *output, const char *title) { + struct wlr_wl_output *wl_output = get_wl_output_from_output(output); + xdg_toplevel_set_title(wl_output->xdg_toplevel, title); +} diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c index a50f478a..915d9958 100644 --- a/backend/x11/input_device.c +++ b/backend/x11/input_device.c @@ -2,11 +2,7 @@ #include <wlr/config.h> -#ifdef __linux__ #include <linux/input-event-codes.h> -#elif __FreeBSD__ -#include <dev/evdev/input-event-codes.h> -#endif #include <xcb/xcb.h> #include <xcb/xfixes.h> diff --git a/docs/env_vars.md b/docs/env_vars.md index b67d1652..fd8fcbac 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -11,7 +11,7 @@ wlroots specific control instead of the atomic interface * *WLR_LIBINPUT_NO_DEVICES*: set to 1 to not fail without any input devices * *WLR_BACKENDS*: comma-separated list of backends to use (available backends: - wayland, x11, headless) + wayland, x11, headless, noop) * *WLR_WL_OUTPUTS*: when using the wayland backend specifies the number of outputs * *WLR_X11_OUTPUTS*: when using the X11 backend specifies the number of outputs * *WLR_HEADLESS_OUTPUTS*: when using the headless backend specifies the number diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c index 48c812e8..348892ab 100644 --- a/examples/idle-inhibit.c +++ b/examples/idle-inhibit.c @@ -8,11 +8,7 @@ #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" -#ifdef __linux__ #include <linux/input-event-codes.h> -#elif __FreeBSD__ -#include <dev/evdev/input-event-codes.h> -#endif /** * Usage: idle-inhibit diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 77b2f6c3..59e2512d 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -1,9 +1,5 @@ #define _POSIX_C_SOURCE 200112L -#ifdef __linux__ #include <linux/input-event-codes.h> -#elif __FreeBSD__ -#include <dev/evdev/input-event-codes.h> -#endif #include <assert.h> #include <GLES2/gl2.h> #include <limits.h> diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 49670c39..a007f712 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -100,6 +100,7 @@ void output_frame_notify(struct wl_listener *listener, void *data) { sample->clear_color[2], sample->clear_color[3]); glClear(GL_COLOR_BUFFER_BIT); + wlr_output_render_software_cursors(wlr_output, NULL); wlr_output_swap_buffers(wlr_output, NULL, NULL); } diff --git a/examples/pointer.c b/examples/pointer.c index cc58c223..c7140d97 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -101,6 +101,7 @@ void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(renderer, state->clear_color); + wlr_output_render_software_cursors(wlr_output, NULL); wlr_output_swap_buffers(wlr_output, NULL, NULL); wlr_renderer_end(renderer); } diff --git a/include/backend/noop.h b/include/backend/noop.h new file mode 100644 index 00000000..4198baad --- /dev/null +++ b/include/backend/noop.h @@ -0,0 +1,24 @@ +#ifndef BACKEND_NOOP_H +#define BACKEND_NOOP_H + +#include <wlr/backend/noop.h> +#include <wlr/backend/interface.h> + +struct wlr_noop_backend { + struct wlr_backend backend; + struct wl_display *display; + struct wl_list outputs; + bool started; +}; + +struct wlr_noop_output { + struct wlr_output wlr_output; + + struct wlr_noop_backend *backend; + struct wl_list link; +}; + +struct wlr_noop_backend *noop_backend_from_backend( + struct wlr_backend *wlr_backend); + +#endif diff --git a/include/backend/wayland.h b/include/backend/wayland.h index dbc309ca..c41d560a 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -30,7 +30,7 @@ struct wlr_wl_backend { struct wl_event_source *remote_display_src; struct wl_registry *registry; struct wl_compositor *compositor; - struct zxdg_shell_v6 *shell; + struct xdg_wm_base *xdg_wm_base; struct wl_shm *shm; struct wl_seat *seat; struct wl_pointer *pointer; @@ -47,8 +47,8 @@ struct wlr_wl_output { struct wl_surface *surface; struct wl_callback *frame_callback; - struct zxdg_surface_v6 *xdg_surface; - struct zxdg_toplevel_v6 *xdg_toplevel; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; struct wl_egl_window *egl_window; EGLSurface egl_surface; diff --git a/include/wlr/backend/meson.build b/include/wlr/backend/meson.build index 3d6f0e40..47de62d2 100644 --- a/include/wlr/backend/meson.build +++ b/include/wlr/backend/meson.build @@ -4,6 +4,7 @@ install_headers( 'interface.h', 'libinput.h', 'multi.h', + 'noop.h', 'session.h', 'wayland.h', subdir: 'wlr/backend', diff --git a/include/wlr/backend/noop.h b/include/wlr/backend/noop.h new file mode 100644 index 00000000..592b8f35 --- /dev/null +++ b/include/wlr/backend/noop.h @@ -0,0 +1,31 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_BACKEND_NOOP_H +#define WLR_BACKEND_NOOP_H + +#include <wlr/backend.h> +#include <wlr/types/wlr_output.h> + +/** + * Creates a noop backend. Noop backends do not have a framebuffer and are not + * capable of rendering anything. They are useful for when there's no real + * outputs connected; you can stash your views on a noop output until an output + * is connected. + */ +struct wlr_backend *wlr_noop_backend_create(struct wl_display *display); + +/** + * Create a new noop output. + */ +struct wlr_output *wlr_noop_add_output(struct wlr_backend *backend); + +bool wlr_backend_is_noop(struct wlr_backend *backend); +bool wlr_output_is_noop(struct wlr_output *output); + +#endif diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index 119ea247..9a47d1ce 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -1,6 +1,5 @@ #ifndef WLR_BACKEND_WAYLAND_H #define WLR_BACKEND_WAYLAND_H - #include <stdbool.h> #include <wayland-client.h> #include <wayland-server.h> @@ -16,8 +15,8 @@ * to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0 * default) */ -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote, - wlr_renderer_create_func_t create_renderer_func); +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, + const char *remote, wlr_renderer_create_func_t create_renderer_func); /** * Adds a new output to this backend. You may remove outputs by destroying them. @@ -42,4 +41,9 @@ bool wlr_input_device_is_wl(struct wlr_input_device *device); */ bool wlr_output_is_wl(struct wlr_output *output); +/** + * Sets the title of a wlr_output which is a Wayland window. + */ +void wlr_wl_output_set_title(struct wlr_output *output, const char *title); + #endif diff --git a/include/wlr/types/meson.build b/include/wlr/types/meson.build index f9075bea..86f128b6 100644 --- a/include/wlr/types/meson.build +++ b/include/wlr/types/meson.build @@ -3,6 +3,7 @@ install_headers( 'wlr_buffer.h', 'wlr_compositor.h', 'wlr_cursor.h', + 'wlr_data_control_v1.h', 'wlr_data_device.h', 'wlr_export_dmabuf_v1.h', 'wlr_foreign_toplevel_management_v1.h', diff --git a/include/wlr/types/wlr_data_control_v1.h b/include/wlr/types/wlr_data_control_v1.h new file mode 100644 index 00000000..50c96736 --- /dev/null +++ b/include/wlr/types/wlr_data_control_v1.h @@ -0,0 +1,48 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_DATA_CONTROL_V1_H +#define WLR_TYPES_WLR_DATA_CONTROL_V1_H + +#include <wayland-server.h> +#include <wlr/types/wlr_seat.h> + +struct wlr_data_control_manager_v1 { + struct wl_global *global; + struct wl_list resources; // wl_resource_get_link + struct wl_list devices; // wlr_data_control_device_v1::link + + struct { + struct wl_signal destroy; + struct wl_signal new_device; // wlr_data_control_device_v1 + } events; + + struct wl_listener display_destroy; +}; + +struct wlr_data_control_device_v1 { + struct wl_resource *resource; + struct wlr_data_control_manager_v1 *manager; + struct wl_list link; // wlr_data_control_manager_v1::devices + + struct wlr_seat *seat; + struct wl_resource *selection_offer_resource; // current selection offer + + struct wl_listener seat_destroy; + struct wl_listener seat_selection; +}; + +struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create( + struct wl_display *display); +void wlr_data_control_manager_v1_destroy( + struct wlr_data_control_manager_v1 *manager); + +void wlr_data_control_device_v1_destroy( + struct wlr_data_control_device_v1 *device); + +#endif diff --git a/include/wlr/types/wlr_relative_pointer_v1.h b/include/wlr/types/wlr_relative_pointer_v1.h index f9f91219..076fac56 100644 --- a/include/wlr/types/wlr_relative_pointer_v1.h +++ b/include/wlr/types/wlr_relative_pointer_v1.h @@ -11,19 +11,16 @@ #include <wayland-server.h> - /** * This protocol specifies a set of interfaces used for making clients able to * receive relative pointer events not obstructed by barriers (such as the * monitor edge or pointer constraints). */ - /** * A global interface used for getting the relative pointer object for a given * pointer. */ - struct wlr_relative_pointer_manager_v1 { struct wl_global *global; struct wl_list resources; // wl_resource_get_link() @@ -31,7 +28,7 @@ struct wlr_relative_pointer_manager_v1 { struct { struct wl_signal destroy; - struct wl_signal new_relative_pointer; //wlr_relative_pointer_v1 + struct wl_signal new_relative_pointer; // wlr_relative_pointer_v1 } events; struct wl_listener display_destroy_listener; @@ -39,17 +36,15 @@ struct wlr_relative_pointer_manager_v1 { void *data; }; - /** * A wp_relative_pointer object is an extension to the wl_pointer interface * used for emitting relative pointer events. It shares the same focus as * wl_pointer objects of the same seat and will only emit events when it has * focus. */ - struct wlr_relative_pointer_v1 { struct wl_resource *resource; - struct wl_resource *pointer; + struct wl_resource *pointer_resource; struct wlr_seat *seat; struct wl_list link; // wlr_relative_pointer_manager_v1::relative_pointers @@ -66,14 +61,15 @@ struct wlr_relative_pointer_v1 { struct wlr_relative_pointer_manager_v1 *wlr_relative_pointer_manager_v1_create( struct wl_display *display); void wlr_relative_pointer_manager_v1_destroy( - struct wlr_relative_pointer_manager_v1 *relative_pointer_manager); + struct wlr_relative_pointer_manager_v1 *manager); /** * Send a relative motion event to the seat with the same wl_pointer as relative_pointer */ -void wlr_relative_pointer_v1_send_relative_motion( - struct wlr_relative_pointer_v1 *relative_pointer, uint64_t time_msec, - double dx, double dy, double dx_unaccel, double dy_unaccel); +void wlr_relative_pointer_manager_v1_send_relative_motion( + struct wlr_relative_pointer_manager_v1 *manager, struct wlr_seat *seat, + uint64_t time_msec, double dx, double dy, + double dx_unaccel, double dy_unaccel); struct wlr_relative_pointer_v1 *wlr_relative_pointer_v1_from_resource( struct wl_resource *resource); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 1bca9ef3..14100fda 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -296,9 +296,14 @@ uint32_t wlr_xdg_toplevel_set_tiled(struct wlr_xdg_surface *surface, uint32_t tiled_edges); /** - * Request that this xdg surface closes. + * Request that this xdg toplevel closes. */ -void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface); +void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface); + +/** + * Request that this xdg popup closes. + **/ +void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface); /** * Get the geometry for this positioner based on the anchor rect, gravity, and diff --git a/meson_options.txt b/meson_options.txt index 19a6cad7..9dd1695c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,7 +3,7 @@ option('logind', type: 'feature', value: 'auto', description: 'Enable support fo option('logind-provider', type: 'combo', choices: ['systemd', 'elogind'], value: 'systemd', description: 'Provider of logind support library') option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library') option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') -option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') +option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications') option('x11-backend', type: 'feature', value: 'auto', description: 'Enable X11 backend') option('rootston', type: 'boolean', value: true, description: 'Build the rootston example compositor') option('examples', type: 'boolean', value: true, description: 'Build example applications') diff --git a/protocol/meson.build b/protocol/meson.build index 93820d57..6d915358 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -30,6 +30,7 @@ protocols = [ 'server-decoration.xml', 'text-input-unstable-v3.xml', 'virtual-keyboard-unstable-v1.xml', + 'wlr-data-control-unstable-v1.xml', 'wlr-export-dmabuf-unstable-v1.xml', 'wlr-foreign-toplevel-management-unstable-v1.xml', 'wlr-gamma-control-unstable-v1.xml', diff --git a/protocol/wlr-data-control-unstable-v1.xml b/protocol/wlr-data-control-unstable-v1.xml new file mode 100644 index 00000000..a5887550 --- /dev/null +++ b/protocol/wlr-data-control-unstable-v1.xml @@ -0,0 +1,224 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="wlr_data_control_unstable_v1"> + <copyright> + Copyright © 2018 Simon Ser + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + </copyright> + + <description summary="control data devices"> + This protocol allows a privileged client to control data devices. In + particular, the client will be able to manage the current selection and take + the role of a clipboard manager. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + </description> + + <interface name="zwlr_data_control_manager_v1" version="1"> + <description summary="manager to control data devices"> + This interface is a manager that allows creating per-seat data device + controls. + </description> + + <request name="create_data_source"> + <description summary="create a new data source"> + Create a new data source. + </description> + <arg name="id" type="new_id" interface="zwlr_data_control_source_v1" + summary="data source to create"/> + </request> + + <request name="get_data_device"> + <description summary="get a data device for a seat"> + Create a data device that can be used to manage a seat's selection. + </description> + <arg name="id" type="new_id" interface="zwlr_data_control_device_v1"/> + <arg name="seat" type="object" interface="wl_seat"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy the manager"> + All objects created by the manager will still remain valid, until their + appropriate destroy request has been called. + </description> + </request> + </interface> + + <interface name="zwlr_data_control_device_v1" version="1"> + <description summary="manage a data device for a seat"> + This interface allows a client to manage a seat's selection. + + When the seat is destroyed, this object becomes inert. + </description> + + <request name="set_selection"> + <description summary="copy data to the selection"> + All objects created by the device will still remain valid, until their + appropriate destroy request has been called. + </description> + <arg name="source" type="object" interface="zwlr_data_control_source_v1" + allow-null="true"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy this data device"> + Destroys the data device object. + </description> + </request> + + <event name="data_offer"> + <description summary="introduce a new wlr_data_control_offer"> + The data_offer event introduces a new wlr_data_control_offer object, + which will subsequently be used in the wlr_data_control_device.selection + event. Immediately following the wlr_data_control_device.data_offer + event, the new data_offer object will send out + wlr_data_control_offer.offer events to describe the MIME types it + offers. + + This event replaces the previous data offer, which should be destroyed + by the client. + </description> + <arg name="id" type="new_id" interface="zwlr_data_control_offer_v1"/> + </event> + + <event name="selection"> + <description summary="introduce a new wlr_data_control_offer"> + The selection event is sent out to notify the client of a new + wlr_data_control_offer for the selection for this device. The + wlr_data_control_device.data_offer and the wlr_data_control_offer.offer + events are sent out immediately before this event to introduce the data + offer object. The selection event is sent to a client when a new + selection is set. The wlr_data_control_offer is valid until a new + wlr_data_control_offer or NULL is received. The client must destroy the + previous selection wlr_data_control_offer, if any, upon receiving this + event. + </description> + <arg name="id" type="object" interface="zwlr_data_control_offer_v1" + allow-null="true"/> + </event> + + <event name="finished"> + <description summary="this data control is no longer valid"> + This data control object is no longer valid and should be destroyed by + the client. + </description> + </event> + </interface> + + <interface name="zwlr_data_control_source_v1" version="1"> + <description summary="offer to transfer data"> + The wlr_data_control_source object is the source side of a + wlr_data_control_offer. It is created by the source client in a data + transfer and provides a way to describe the offered data and a way to + respond to requests to transfer the data. + </description> + + <enum name="error"> + <entry name="invalid_offer" value="1" + summary="offer sent after wlr_data_control_device.set_selection"/> + </enum> + + <request name="offer"> + <description summary="add an offered MIME type"> + This request adds a MIME type to the set of MIME types advertised to + targets. Can be called several times to offer multiple types. + + Calling this after wlr_data_control_device.set_selection is a protocol + error. + </description> + <arg name="mime_type" type="string" + summary="MIME type offered by the data source"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy this source"> + Destroys the data source object. + </description> + </request> + + <event name="send"> + <description summary="send the data"> + Request for data from the client. Send the data as the specified MIME + type over the passed file descriptor, then close it. + </description> + <arg name="mime_type" type="string" summary="MIME type for the data"/> + <arg name="fd" type="fd" summary="file descriptor for the data"/> + </event> + + <event name="cancelled"> + <description summary="selection was cancelled"> + This data source is no longer valid. The data source has been replaced + by another data source. + + The client should clean up and destroy this data source. + </description> + </event> + </interface> + + <interface name="zwlr_data_control_offer_v1" version="1"> + <description summary="offer to transfer data"> + A wlr_data_control_offer represents a piece of data offered for transfer + by another client (the source client). The offer describes the different + MIME types that the data can be converted to and provides the mechanism + for transferring the data directly from the source client. + </description> + + <request name="receive"> + <description summary="request that the data is transferred"> + To transfer the offered data, the client issues this request and + indicates the MIME type it wants to receive. The transfer happens + through the passed file descriptor (typically created with the pipe + system call). The source client writes the data in the MIME type + representation requested and then closes the file descriptor. + + The receiving client reads from the read end of the pipe until EOF and + then closes its end, at which point the transfer is complete. + + This request may happen multiple times for different MIME types. + </description> + <arg name="mime_type" type="string" + summary="MIME type desired by receiver"/> + <arg name="fd" type="fd" summary="file descriptor for data transfer"/> + </request> + + <request name="destroy" type="destructor"> + <description summary="destroy this offer"> + Destroys the data offer object. + </description> + </request> + + <event name="offer"> + <description summary="advertise offered MIME type"> + Sent immediately after creating the wlr_data_control_offer object. + One event per offered MIME type. + </description> + <arg name="mime_type" type="string" summary="offered MIME type"/> + </event> + </interface> +</protocol> diff --git a/rootston/cursor.c b/rootston/cursor.c index 1fdf1dbb..b7ecc813 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -7,11 +7,7 @@ #include <wlr/util/edges.h> #include <wlr/util/log.h> #include <wlr/util/region.h> -#ifdef __linux__ #include <linux/input-event-codes.h> -#elif __FreeBSD__ -#include <dev/evdev/input-event-codes.h> -#endif #include "rootston/cursor.h" #include "rootston/desktop.h" #include "rootston/view.h" @@ -35,7 +31,8 @@ void roots_cursor_destroy(struct roots_cursor *cursor) { // TODO } -static void seat_view_deco_motion(struct roots_seat_view *view, double deco_sx, double deco_sy) { +static void seat_view_deco_motion(struct roots_seat_view *view, + double deco_sx, double deco_sy) { struct roots_cursor *cursor = view->seat->cursor; double sx = deco_sx; @@ -305,40 +302,18 @@ static void roots_cursor_press_button(struct roots_cursor *cursor, } } -static void notify_relative_motion(struct roots_seat *seat, uint64_t time_msec, - double dx, double dy, double dx_unaccel, double dy_unaccel) { - struct wlr_relative_pointer_manager_v1 *relative_pointer_manager = - seat->input->server->desktop->relative_pointer_manager; - - struct wlr_seat_client *client = seat->seat->pointer_state.focused_client; - if (client == NULL) { - return; - } - - struct wlr_relative_pointer_v1 *pointer; - wl_list_for_each(pointer, &relative_pointer_manager->relative_pointers, link) { - struct wlr_seat_client *relative_pointer_client = - wlr_seat_client_from_pointer_resource(pointer->pointer); - - if (seat->seat == pointer->seat && - client == relative_pointer_client) { - wlr_relative_pointer_v1_send_relative_motion(pointer, - time_msec, dx, dy, dx_unaccel, dy_unaccel); - } - - } -} - void roots_cursor_handle_motion(struct roots_cursor *cursor, struct wlr_event_pointer_motion *event) { double dx = event->delta_x; double dy = event->delta_y; - double unaccel_dx = event->unaccel_dx; - double unaccel_dy = event->unaccel_dy; + double dx_unaccel = event->unaccel_dx; + double dy_unaccel = event->unaccel_dy; - notify_relative_motion(cursor->seat, - (uint64_t)event->time_msec * 1000, dx, dy, unaccel_dx, unaccel_dy); + wlr_relative_pointer_manager_v1_send_relative_motion( + cursor->seat->input->server->desktop->relative_pointer_manager, + cursor->seat->seat, (uint64_t)event->time_msec * 1000, dx, dy, + dx_unaccel, dy_unaccel); if (cursor->active_constraint) { struct roots_view *view = cursor->pointer_view->view; @@ -381,9 +356,9 @@ void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, double dx = lx - cursor->cursor->x; double dy = ly - cursor->cursor->y; - - notify_relative_motion(cursor->seat, - (uint64_t)event->time_msec * 1000, dx, dy, dx, dy); + wlr_relative_pointer_manager_v1_send_relative_motion( + cursor->seat->input->server->desktop->relative_pointer_manager, + cursor->seat->seat, (uint64_t)event->time_msec * 1000, dx, dy, dx, dy); if (cursor->pointer_view) { struct roots_view *view = cursor->pointer_view->view; diff --git a/rootston/desktop.c b/rootston/desktop.c index 77a52571..d65266e5 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -7,24 +7,25 @@ #include <wlr/types/wlr_box.h> #include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> +#include <wlr/types/wlr_data_control_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h> -#include <wlr/types/wlr_gamma_control.h> #include <wlr/types/wlr_gamma_control_v1.h> +#include <wlr/types/wlr_gamma_control.h> +#include <wlr/types/wlr_gtk_primary_selection.h> #include <wlr/types/wlr_idle_inhibit_v1.h> #include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_input_inhibitor.h> #include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_pointer_constraints_v1.h> -#include <wlr/types/wlr_gtk_primary_selection.h> #include <wlr/types/wlr_server_decoration.h> +#include <wlr/types/wlr_tablet_v2.h> #include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xdg_output_v1.h> +#include <wlr/types/wlr_xdg_output_v1.h> #include <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xdg_shell.h> -#include <wlr/types/wlr_xdg_output_v1.h> -#include <wlr/types/wlr_tablet_v2.h> #include <wlr/util/log.h> #include "rootston/layers.h" #include "rootston/seat.h" @@ -1084,6 +1085,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server->wl_display); + wlr_data_control_manager_v1_create(server->wl_display); + return desktop; } diff --git a/rootston/main.c b/rootston/main.c index 7e25dab1..b14989fa 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -73,6 +73,8 @@ int main(int argc, char **argv) { wl_display_run(server.wl_display); #if WLR_HAS_XWAYLAND + // We need to shutdown Xwayland before disconnecting all clients, otherwise + // wlroots will restart it automatically. wlr_xwayland_destroy(server.desktop->xwayland); #endif wl_display_destroy_clients(server.wl_display); diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index da8909ba..918f90ab 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -248,9 +248,9 @@ static void close(struct roots_view *view) { struct wlr_xdg_surface *surface = view->xdg_surface; struct wlr_xdg_popup *popup = NULL; wl_list_for_each(popup, &surface->popups, link) { - wlr_xdg_surface_send_close(popup->base); + wlr_xdg_popup_destroy(popup->base); } - wlr_xdg_surface_send_close(surface); + wlr_xdg_toplevel_send_close(surface); } static void destroy(struct roots_view *view) { diff --git a/tinywl/Makefile b/tinywl/Makefile index 92d2a516..505666f0 100644 --- a/tinywl/Makefile +++ b/tinywl/Makefile @@ -20,8 +20,8 @@ tinywl: tinywl.c xdg-shell-protocol.h xdg-shell-protocol.c $(CC) $(CFLAGS) \ -g -Werror -I. \ -DWLR_USE_UNSTABLE \ - $(LIBS) \ - -o $@ $< + -o $@ $< \ + $(LIBS) clean: rm -f tinywl xdg-shell-protocol.h xdg-shell-protocol.c diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 069f6451..14a1d08b 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -13,7 +13,6 @@ #include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_keyboard.h> -#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output_layout.h> @@ -91,12 +90,6 @@ struct tinywl_keyboard { struct wl_listener key; }; -struct tinywl_pointer { - struct wl_list link; - struct tinywl_server *server; - struct wlr_input_device *device; -}; - static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) { /* Note: this function only deals with keyboard focus. */ if (view == NULL) { @@ -475,7 +468,7 @@ static void server_cursor_button(struct wl_listener *listener, void *data) { struct tinywl_server *server = wl_container_of(listener, server, cursor_button); struct wlr_event_pointer_button *event = data; - /* Notify the client with pointer focus that a button press has occured */ + /* Notify the client with pointer focus that a button press has occurred */ wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); double sx, sy; @@ -552,7 +545,7 @@ static void render_surface(struct wlr_surface *surface, * Those familiar with OpenGL are also familiar with the role of matricies * in graphics programming. We need to prepare a matrix to render the view * with. wlr_matrix_project_box is a helper which takes a box with a desired - * x, y coodrinates, width and height, and an output geometry, then + * x, y coordinates, width and height, and an output geometry, then * prepares an orthographic projection and multiplies the necessary * transforms to produce a model-view-projection matrix. * @@ -617,6 +610,14 @@ static void output_frame(struct wl_listener *listener, void *data) { render_surface, &rdata); } + /* Hardware cursors are rendered by the GPU on a separate plane, and can be + * moved around without re-rendering what's beneath them - which is more + * efficient. However, not all hardware supports hardware cursors. For this + * reason, wlroots provides a software fallback, which we ask it to render + * here. wlr_cursor handles configuring hardware vs software cursors for you, + * and this function is a no-op when hardware cursors are in use. */ + wlr_output_render_software_cursors(output->wlr_output, NULL); + /* Conclude rendering and swap the buffers, showing the final frame * on-screen. */ wlr_renderer_end(renderer); @@ -717,7 +718,7 @@ static void xdg_toplevel_request_move( * move, typically because the user clicked on their client-side * decorations. Note that a more sophisticated compositor should check the * provied serial against a list of button press serials sent to this - * client, to prevent the client from requesting this whenver they want. */ + * client, to prevent the client from requesting this whenever they want. */ struct tinywl_view *view = wl_container_of(listener, view, request_move); begin_interactive(view, TINYWL_CURSOR_MOVE, 0); } @@ -728,7 +729,7 @@ static void xdg_toplevel_request_resize( * resize, typically because the user clicked on their client-side * decorations. Note that a more sophisticated compositor should check the * provied serial against a list of button press serials sent to this - * client, to prevent the client from requesting this whenver they want. */ + * client, to prevent the client from requesting this whenever they want. */ struct wlr_xdg_toplevel_resize_event *event = data; struct tinywl_view *view = wl_container_of(listener, view, request_resize); begin_interactive(view, TINYWL_CURSOR_RESIZE, event->edges); @@ -810,13 +811,10 @@ int main(int argc, char *argv[]) { wlr_renderer_init_wl_display(server.renderer, server.wl_display); /* This creates some hands-off wlroots interfaces. The compositor is - * necessary for clients to allocate surfaces, dmabuf allows them to use - * opaque GPU handles for buffers to avoid copying pixels on the CPU, and - * the data device manager handles the clipboard. Each of these wlroots - * interfaces has room for you to dig your fingers in and play with their - * behavior if you want. */ + * necessary for clients to allocate surfaces and the data device manager + * handles the clipboard. Each of these wlroots interfaces has room for you + * to dig your fingers in and play with their behavior if you want. */ wlr_compositor_create(server.wl_display, server.renderer); - wlr_linux_dmabuf_v1_create(server.wl_display, server.renderer); wlr_data_device_manager_create(server.wl_display); /* Creates an output layout, which a wlroots utility for working with an diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c index f868ea37..cda755b1 100644 --- a/types/data_device/wlr_data_device.c +++ b/types/data_device/wlr_data_device.c @@ -122,6 +122,9 @@ static void seat_client_selection_source_destroy( wl_container_of(listener, seat, selection_source_destroy); struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client; + wl_list_remove(&seat->selection_source_destroy.link); + seat->selection_source = NULL; + if (seat_client && seat->keyboard_state.focused_surface) { struct wl_resource *resource; wl_resource_for_each(resource, &seat_client->data_devices) { @@ -129,8 +132,6 @@ static void seat_client_selection_source_destroy( } } - seat->selection_source = NULL; - wlr_signal_emit_safe(&seat->events.selection, seat); } diff --git a/types/meson.build b/types/meson.build index a1dc213f..0c108d75 100644 --- a/types/meson.build +++ b/types/meson.build @@ -27,6 +27,7 @@ lib_wlr_types = static_library( 'wlr_buffer.c', 'wlr_compositor.c', 'wlr_cursor.c', + 'wlr_data_control_v1.c', 'wlr_export_dmabuf_v1.c', 'wlr_foreign_toplevel_management_v1.c', 'wlr_fullscreen_shell_v1.c', diff --git a/types/tablet_v2/wlr_tablet_v2.c b/types/tablet_v2/wlr_tablet_v2.c index d0bc799d..13c82097 100644 --- a/types/tablet_v2/wlr_tablet_v2.c +++ b/types/tablet_v2/wlr_tablet_v2.c @@ -196,7 +196,7 @@ static void get_tablet_seat(struct wl_client *wl_client, struct wl_resource *res wl_list_insert(&manager->tablet_seats, &seat_client->client_link); wl_list_insert(&tablet_seat->clients, &seat_client->seat_link); - // We need to emit the devices allready on the seat + // We need to emit the devices already on the seat struct wlr_tablet_v2_tablet *tablet_pos; wl_list_for_each(tablet_pos, &tablet_seat->tablets, link) { add_tablet_client(seat_client, tablet_pos); diff --git a/types/tablet_v2/wlr_tablet_v2_tool.c b/types/tablet_v2/wlr_tablet_v2_tool.c index 81f13aa1..471673ae 100644 --- a/types/tablet_v2/wlr_tablet_v2_tool.c +++ b/types/tablet_v2/wlr_tablet_v2_tool.c @@ -124,17 +124,17 @@ void add_tablet_tool_client(struct wlr_tablet_seat_client_v2 *seat, // Send the expected events if (tool->wlr_tool->hardware_serial) { zwp_tablet_tool_v2_send_hardware_serial( - client->resource, + client->resource, tool->wlr_tool->hardware_serial >> 32, tool->wlr_tool->hardware_serial & 0xFFFFFFFF); } if (tool->wlr_tool->hardware_wacom) { zwp_tablet_tool_v2_send_hardware_id_wacom( - client->resource, + client->resource, tool->wlr_tool->hardware_wacom >> 32, tool->wlr_tool->hardware_wacom & 0xFFFFFFFF); } - zwp_tablet_tool_v2_send_type(client->resource, + zwp_tablet_tool_v2_send_type(client->resource, tablet_type_from_wlr_type(tool->wlr_tool->type)); if (tool->wlr_tool->tilt) { @@ -264,8 +264,10 @@ static ssize_t tablet_tool_button_update(struct wlr_tablet_v2_tablet_tool *tool, tool->pressed_serials[i] = -1; } else { i = -1; - wlr_log(WLR_ERROR, "You pressed more than %d tablet tool buttons. This is currently not supporte by wlroots. Please report this with a description of your tablet, since this is either a bug, or fancy hardware", - WLR_TABLET_V2_TOOL_BUTTONS_CAP); + wlr_log(WLR_ERROR, "You pressed more than %d tablet tool buttons. " + "This is currently not supported by wlroots. Please report this " + "with a description of your tablet, since this is either a " + "bug, or fancy hardware", WLR_TABLET_V2_TOOL_BUTTONS_CAP); } } if (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_RELEASED && found) { diff --git a/types/wlr_data_control_v1.c b/types/wlr_data_control_v1.c new file mode 100644 index 00000000..9812220c --- /dev/null +++ b/types/wlr_data_control_v1.c @@ -0,0 +1,419 @@ +#define _POSIX_C_SOURCE 200809L +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wlr/types/wlr_data_control_v1.h> +#include <wlr/types/wlr_data_device.h> +#include "util/signal.h" +#include "wlr-data-control-unstable-v1-protocol.h" + +#define DATA_CONTROL_MANAGER_VERSION 1 + +struct client_data_source { + struct wlr_data_source source; + struct wl_resource *resource; + bool finalized; +}; + +static const struct wlr_data_source_impl client_source_impl; + +static struct client_data_source * + client_data_source_from_source(struct wlr_data_source *wlr_source) { + assert(wlr_source->impl == &client_source_impl); + return (struct client_data_source *)wlr_source; +} + +static void client_source_send(struct wlr_data_source *wlr_source, + const char *mime_type, int fd) { + struct client_data_source *source = + client_data_source_from_source(wlr_source); + zwlr_data_control_source_v1_send_send(source->resource, mime_type, fd); + close(fd); +} + +static void client_source_cancel(struct wlr_data_source *wlr_source) { + struct client_data_source *source = + client_data_source_from_source(wlr_source); + zwlr_data_control_source_v1_send_cancelled(source->resource); + wlr_data_source_finish(wlr_source); + // Make the resource inert + wl_resource_set_user_data(source->resource, NULL); + free(source); +} + +static const struct wlr_data_source_impl client_source_impl = { + .send = client_source_send, + .cancel = client_source_cancel, +}; + +static const struct zwlr_data_control_source_v1_interface source_impl; + +static struct client_data_source *source_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_data_control_source_v1_interface, &source_impl)); + return wl_resource_get_user_data(resource); +} + +static void source_handle_offer(struct wl_client *client, + struct wl_resource *resource, const char *mime_type) { + struct client_data_source *source = source_from_resource(resource); + if (source == NULL) { + return; + } + + if (source->finalized) { + wl_resource_post_error(resource, + ZWLR_DATA_CONTROL_SOURCE_V1_ERROR_INVALID_OFFER, + "cannot mutate offer after set_selection"); + return; + } + + char *dup_mime_type = strdup(mime_type); + if (dup_mime_type == NULL) { + wl_resource_post_no_memory(resource); + return; + } + + char **p = wl_array_add(&source->source.mime_types, sizeof(char *)); + if (p == NULL) { + free(dup_mime_type); + wl_resource_post_no_memory(resource); + return; + } + + *p = dup_mime_type; +} + +static void source_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwlr_data_control_source_v1_interface source_impl = { + .offer = source_handle_offer, + .destroy = source_handle_destroy, +}; + +static void source_handle_resource_destroy(struct wl_resource *resource) { + struct client_data_source *source = source_from_resource(resource); + if (source == NULL) { + return; + } + wlr_data_source_cancel(&source->source); +} + + +static const struct zwlr_data_control_offer_v1_interface offer_impl; + +static struct wlr_data_control_device_v1 *control_from_offer_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_data_control_offer_v1_interface, &offer_impl)); + return wl_resource_get_user_data(resource); +} + +static void offer_handle_receive(struct wl_client *client, + struct wl_resource *resource, const char *mime_type, int fd) { + struct wlr_data_control_device_v1 *device = control_from_offer_resource(resource); + if (device == NULL || device->seat->selection_source == NULL) { + close(fd); + return; + } + wlr_data_source_send(device->seat->selection_source, mime_type, fd); +} + +static void offer_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwlr_data_control_offer_v1_interface offer_impl = { + .receive = offer_handle_receive, + .destroy = offer_handle_destroy, +}; + +static void offer_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_data_control_device_v1 *device = control_from_offer_resource(resource); + if (device != NULL) { + device->selection_offer_resource = NULL; + } +} + +static struct wl_resource *create_offer(struct wlr_data_control_device_v1 *device, + struct wlr_data_source *source) { + struct wl_client *client = wl_resource_get_client(device->resource); + uint32_t version = wl_resource_get_version(device->resource); + struct wl_resource *resource = wl_resource_create(client, + &zwlr_data_control_offer_v1_interface, version, 0); + if (resource == NULL) { + return NULL; + } + wl_resource_set_implementation(resource, &offer_impl, device, + offer_handle_resource_destroy); + + zwlr_data_control_device_v1_send_data_offer(device->resource, resource); + + char **p; + wl_array_for_each(p, &source->mime_types) { + zwlr_data_control_offer_v1_send_offer(resource, *p); + } + + return resource; +} + + +static const struct zwlr_data_control_device_v1_interface control_impl; + +static struct wlr_data_control_device_v1 *control_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_data_control_device_v1_interface, &control_impl)); + return wl_resource_get_user_data(resource); +} + +static void control_handle_set_selection(struct wl_client *client, + struct wl_resource *control_resource, + struct wl_resource *source_resource) { + struct wlr_data_control_device_v1 *device = + control_from_resource(control_resource); + struct client_data_source *source = source_from_resource(source_resource); + if (device == NULL) { + return; + } + + struct wlr_data_source *wlr_source = source ? &source->source : NULL; + struct wl_display *display = wl_client_get_display(client); + wlr_seat_set_selection(device->seat, wlr_source, + wl_display_next_serial(display)); +} + +static void control_handle_destroy(struct wl_client *client, + struct wl_resource *control_resource) { + wl_resource_destroy(control_resource); +} + +static const struct zwlr_data_control_device_v1_interface control_impl = { + .set_selection = control_handle_set_selection, + .destroy = control_handle_destroy, +}; + +static void control_send_selection(struct wlr_data_control_device_v1 *device) { + struct wlr_data_source *source = device->seat->selection_source; + + if (device->selection_offer_resource != NULL) { + // Make the offer inert + wl_resource_set_user_data(device->selection_offer_resource, NULL); + } + + device->selection_offer_resource = NULL; + if (source != NULL) { + device->selection_offer_resource = create_offer(device, source); + if (device->selection_offer_resource == NULL) { + wl_resource_post_no_memory(device->resource); + return; + } + } + + zwlr_data_control_device_v1_send_selection(device->resource, + device->selection_offer_resource); +} + +static void control_handle_resource_destroy(struct wl_resource *resource) { + struct wlr_data_control_device_v1 *device = control_from_resource(resource); + wlr_data_control_device_v1_destroy(device); +} + +static void control_handle_seat_destroy(struct wl_listener *listener, + void *data) { + struct wlr_data_control_device_v1 *device = + wl_container_of(listener, device, seat_destroy); + wlr_data_control_device_v1_destroy(device); +} + +static void control_handle_seat_selection(struct wl_listener *listener, + void *data) { + struct wlr_data_control_device_v1 *device = + wl_container_of(listener, device, seat_selection); + control_send_selection(device); +} + +void wlr_data_control_device_v1_destroy(struct wlr_data_control_device_v1 *device) { + if (device == NULL) { + return; + } + zwlr_data_control_device_v1_send_finished(device->resource); + // Make the resources inert + wl_resource_set_user_data(device->resource, NULL); + if (device->selection_offer_resource != NULL) { + wl_resource_set_user_data(device->selection_offer_resource, NULL); + } + wl_list_remove(&device->seat_destroy.link); + wl_list_remove(&device->seat_selection.link); + wl_list_remove(&device->link); + free(device); +} + + +static const struct zwlr_data_control_manager_v1_interface manager_impl; + +static struct wlr_data_control_manager_v1 *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_data_control_manager_v1_interface, &manager_impl)); + return wl_resource_get_user_data(resource); +} + +static void manager_handle_create_data_source(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id) { + struct client_data_source *source = + calloc(1, sizeof(struct client_data_source)); + if (source == NULL) { + wl_resource_post_no_memory(manager_resource); + return; + } + wlr_data_source_init(&source->source, &client_source_impl); + + uint32_t version = wl_resource_get_version(manager_resource); + source->resource = wl_resource_create(client, + &zwlr_data_control_source_v1_interface, version, id); + if (source->resource == NULL) { + wl_resource_post_no_memory(manager_resource); + free(source); + return; + } + wl_resource_set_implementation(source->resource, &source_impl, source, + source_handle_resource_destroy); +} + +static void manager_handle_get_data_device(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + struct wl_resource *seat_resource) { + struct wlr_data_control_manager_v1 *manager = + manager_from_resource(manager_resource); + struct wlr_seat_client *seat_client = + wlr_seat_client_from_resource(seat_resource); + + struct wlr_data_control_device_v1 *device = + calloc(1, sizeof(struct wlr_data_control_device_v1)); + if (device == NULL) { + wl_resource_post_no_memory(manager_resource); + return; + } + device->manager = manager; + device->seat = seat_client->seat; + + uint32_t version = wl_resource_get_version(manager_resource); + device->resource = wl_resource_create(client, + &zwlr_data_control_device_v1_interface, version, id); + if (device->resource == NULL) { + wl_resource_post_no_memory(manager_resource); + free(device); + return; + } + wl_resource_set_implementation(device->resource, &control_impl, device, + control_handle_resource_destroy); + struct wl_resource *resource = device->resource; + + device->seat_destroy.notify = control_handle_seat_destroy; + wl_signal_add(&device->seat->events.destroy, &device->seat_destroy); + + device->seat_selection.notify = control_handle_seat_selection; + wl_signal_add(&device->seat->events.selection, &device->seat_selection); + + wl_list_insert(&manager->devices, &device->link); + wlr_signal_emit_safe(&manager->events.new_device, device); + + // At this point maybe the compositor decided to destroy the device. If + // it's the case then the resource will be inert. + device = control_from_resource(resource); + if (device != NULL) { + control_send_selection(device); + } +} + +static void manager_handle_destroy(struct wl_client *client, + struct wl_resource *manager_resource) { + wl_resource_destroy(manager_resource); +} + +static const struct zwlr_data_control_manager_v1_interface manager_impl = { + .create_data_source = manager_handle_create_data_source, + .get_data_device = manager_handle_get_data_device, + .destroy = manager_handle_destroy, +}; + +static void manager_handle_resource_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + +static void manager_bind(struct wl_client *client, void *data, uint32_t version, + uint32_t id) { + struct wlr_data_control_manager_v1 *manager = data; + + struct wl_resource *resource = wl_resource_create(client, + &zwlr_data_control_manager_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &manager_impl, manager, + manager_handle_resource_destroy); + + wl_list_insert(&manager->resources, wl_resource_get_link(resource)); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_data_control_manager_v1 *manager = + wl_container_of(listener, manager, display_destroy); + wlr_data_control_manager_v1_destroy(manager); +} + +struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create( + struct wl_display *display) { + struct wlr_data_control_manager_v1 *manager = + calloc(1, sizeof(struct wlr_data_control_manager_v1)); + if (manager == NULL) { + return NULL; + } + wl_list_init(&manager->resources); + wl_list_init(&manager->devices); + wl_signal_init(&manager->events.destroy); + wl_signal_init(&manager->events.new_device); + + manager->global = wl_global_create(display, + &zwlr_data_control_manager_v1_interface, DATA_CONTROL_MANAGER_VERSION, + manager, manager_bind); + if (manager->global == NULL) { + free(manager); + return NULL; + } + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +} + +void wlr_data_control_manager_v1_destroy( + struct wlr_data_control_manager_v1 *manager) { + if (manager == NULL) { + return; + } + + wlr_signal_emit_safe(&manager->events.destroy, manager); + + struct wlr_data_control_device_v1 *device, *control_tmp; + wl_list_for_each_safe(device, control_tmp, &manager->devices, link) { + wl_resource_destroy(device->resource); + } + + struct wl_resource *resource, *resource_tmp; + wl_resource_for_each_safe(resource, resource_tmp, &manager->resources) { + wl_resource_destroy(resource); + } + + wl_list_remove(&manager->display_destroy.link); + free(manager); +} diff --git a/types/wlr_output.c b/types/wlr_output.c index 9a21196e..7cfbb085 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -173,8 +173,12 @@ bool wlr_output_set_custom_mode(struct wlr_output *output, int32_t width, void wlr_output_update_mode(struct wlr_output *output, struct wlr_output_mode *mode) { output->current_mode = mode; - wlr_output_update_custom_mode(output, mode->width, mode->height, - mode->refresh); + if (mode != NULL) { + wlr_output_update_custom_mode(output, mode->width, mode->height, + mode->refresh); + } else { + wlr_output_update_custom_mode(output, 0, 0, 0); + } } void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width, diff --git a/types/wlr_relative_pointer_v1.c b/types/wlr_relative_pointer_v1.c index a6e6e4b3..c4690087 100644 --- a/types/wlr_relative_pointer_v1.c +++ b/types/wlr_relative_pointer_v1.c @@ -42,6 +42,7 @@ static void relative_pointer_destroy(struct wlr_relative_pointer_v1 *relative_po wl_list_remove(&relative_pointer->link); wl_list_remove(&relative_pointer->seat_destroy.link); + wl_list_remove(&relative_pointer->pointer_destroy.link); wl_resource_set_user_data(relative_pointer->resource, NULL); free(relative_pointer); @@ -122,7 +123,7 @@ static void relative_pointer_manager_v1_handle_get_relative_pointer(struct wl_cl relative_pointer->resource = relative_pointer_resource; relative_pointer->seat = seat_client->seat; - relative_pointer->pointer = pointer; + relative_pointer->pointer_resource = pointer; wl_signal_init(&relative_pointer->events.destroy); @@ -139,7 +140,7 @@ static void relative_pointer_manager_v1_handle_get_relative_pointer(struct wl_cl &relative_pointer->seat_destroy); relative_pointer->seat_destroy.notify = relative_pointer_handle_seat_destroy; - wl_resource_add_destroy_listener(relative_pointer->pointer, + wl_resource_add_destroy_listener(relative_pointer->pointer_resource, &relative_pointer->pointer_destroy); relative_pointer->pointer_destroy.notify = relative_pointer_handle_pointer_destroy; @@ -246,18 +247,30 @@ void wlr_relative_pointer_manager_v1_destroy(struct wlr_relative_pointer_manager wl_global_destroy(manager->global); free(manager); - - wlr_log(WLR_DEBUG, "relative_pointer_v1 manager destroyed"); } -void wlr_relative_pointer_v1_send_relative_motion(struct wlr_relative_pointer_v1 *relative_pointer, +void wlr_relative_pointer_manager_v1_send_relative_motion( + struct wlr_relative_pointer_manager_v1 *manager, struct wlr_seat *seat, uint64_t time_msec, double dx, double dy, double dx_unaccel, double dy_unaccel) { - zwp_relative_pointer_v1_send_relative_motion(relative_pointer->resource, - (uint32_t)(time_msec >> 32), (uint32_t)time_msec, - wl_fixed_from_double(dx), wl_fixed_from_double(dy), - wl_fixed_from_double(dx_unaccel), wl_fixed_from_double(dy_unaccel)); + struct wlr_seat_client *focused = seat->pointer_state.focused_client; + if (focused == NULL) { + return; + } - wl_pointer_send_frame(relative_pointer->pointer); + struct wlr_relative_pointer_v1 *pointer; + wl_list_for_each(pointer, &manager->relative_pointers, link) { + struct wlr_seat_client *seat_client = + wlr_seat_client_from_pointer_resource(pointer->pointer_resource); + if (seat != pointer->seat || focused != seat_client) { + continue; + } + + zwp_relative_pointer_v1_send_relative_motion(pointer->resource, + (uint32_t)(time_msec >> 32), (uint32_t)time_msec, + wl_fixed_from_double(dx), wl_fixed_from_double(dy), + wl_fixed_from_double(dx_unaccel), wl_fixed_from_double(dy_unaccel)); + wl_pointer_send_frame(pointer->pointer_resource); + } } diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index 17edbe47..0e98155a 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -517,22 +517,16 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) { surface->client->ping_serial); } -void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface) { - switch (surface->role) { - case WLR_XDG_SURFACE_ROLE_NONE: - assert(0 && "not reached"); - break; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - if (surface->toplevel) { - xdg_toplevel_send_close(surface->toplevel->resource); - } - break; - case WLR_XDG_SURFACE_ROLE_POPUP: - if (surface->popup) { - xdg_popup_send_popup_done(surface->popup->resource); - } - break; - } +void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) { + assert(surface->toplevel); + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + xdg_toplevel_send_close(surface->toplevel->resource); +} + +void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface) { + assert(surface->popup); + assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + xdg_popup_send_popup_done(surface->popup->resource); } static void xdg_popup_get_position(struct wlr_xdg_popup *popup, |