aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.builds/freebsd.yml71
-rw-r--r--backend/backend.c17
-rw-r--r--backend/drm/drm.c17
-rw-r--r--backend/meson.build2
-rw-r--r--backend/noop/backend.c68
-rw-r--r--backend/noop/output.c75
-rw-r--r--backend/session/direct-freebsd.c2
-rw-r--r--backend/session/direct-ipc.c2
-rw-r--r--backend/wayland/backend.c30
-rw-r--r--backend/wayland/output.c37
-rw-r--r--backend/x11/input_device.c4
-rw-r--r--docs/env_vars.md2
-rw-r--r--examples/idle-inhibit.c4
-rw-r--r--examples/layer-shell.c4
-rw-r--r--examples/multi-pointer.c1
-rw-r--r--examples/pointer.c1
-rw-r--r--include/backend/noop.h24
-rw-r--r--include/backend/wayland.h6
-rw-r--r--include/wlr/backend/meson.build1
-rw-r--r--include/wlr/backend/noop.h31
-rw-r--r--include/wlr/backend/wayland.h10
-rw-r--r--include/wlr/types/meson.build1
-rw-r--r--include/wlr/types/wlr_data_control_v1.h48
-rw-r--r--include/wlr/types/wlr_relative_pointer_v1.h18
-rw-r--r--include/wlr/types/wlr_xdg_shell.h9
-rw-r--r--meson_options.txt2
-rw-r--r--protocol/meson.build1
-rw-r--r--protocol/wlr-data-control-unstable-v1.xml224
-rw-r--r--rootston/cursor.c47
-rw-r--r--rootston/desktop.c11
-rw-r--r--rootston/main.c2
-rw-r--r--rootston/xdg_shell.c4
-rw-r--r--tinywl/Makefile4
-rw-r--r--tinywl/tinywl.c32
-rw-r--r--types/data_device/wlr_data_device.c5
-rw-r--r--types/meson.build1
-rw-r--r--types/tablet_v2/wlr_tablet_v2.c2
-rw-r--r--types/tablet_v2/wlr_tablet_v2_tool.c12
-rw-r--r--types/wlr_data_control_v1.c419
-rw-r--r--types/wlr_output.c8
-rw-r--r--types/wlr_relative_pointer_v1.c33
-rw-r--r--types/xdg_shell/wlr_xdg_surface.c26
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,