aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md124
-rw-r--r--README.md2
-rw-r--r--backend/drm/drm.c3
-rw-r--r--backend/drm/util.c2
-rw-r--r--backend/libinput/backend.c2
-rw-r--r--backend/wayland/wl_seat.c18
-rw-r--r--backend/x11/input_device.c14
-rw-r--r--docs/env_vars.md20
-rw-r--r--include/backend/drm/properties.h4
-rw-r--r--include/types/wlr_data_device.h33
-rw-r--r--include/types/wlr_seat.h23
-rw-r--r--include/wlr/backend/session.h2
-rw-r--r--include/wlr/types/wlr_cursor.h2
-rw-r--r--include/wlr/types/wlr_data_device.h8
-rw-r--r--include/wlr/types/wlr_idle.h2
-rw-r--r--include/wlr/types/wlr_linux_dmabuf.h12
-rw-r--r--include/wlr/types/wlr_seat.h3
-rw-r--r--include/wlr/types/wlr_surface.h2
-rw-r--r--include/wlr/types/wlr_wl_shell.h2
-rw-r--r--include/wlr/types/wlr_xdg_shell.h4
-rw-r--r--include/wlr/types/wlr_xdg_shell_v6.h4
-rw-r--r--include/wlr/xwayland.h2
-rw-r--r--protocol/wlr-layer-shell-unstable-v1.xml2
-rw-r--r--rootston/output.c2
-rw-r--r--rootston/xdg_shell.c2
-rw-r--r--rootston/xdg_shell_v6.c2
-rw-r--r--types/data_device/wlr_data_device.c282
-rw-r--r--types/data_device/wlr_data_offer.c217
-rw-r--r--types/data_device/wlr_data_source.c291
-rw-r--r--types/data_device/wlr_drag.c481
-rw-r--r--types/meson.build13
-rw-r--r--types/seat/wlr_seat.c336
-rw-r--r--types/seat/wlr_seat_keyboard.c394
-rw-r--r--types/seat/wlr_seat_pointer.c338
-rw-r--r--types/seat/wlr_seat_touch.c361
-rw-r--r--types/wlr_compositor.c25
-rw-r--r--types/wlr_cursor.c94
-rw-r--r--types/wlr_data_device.c1203
-rw-r--r--types/wlr_linux_dmabuf.c64
-rw-r--r--types/wlr_matrix.c2
-rw-r--r--types/wlr_output.c47
-rw-r--r--types/wlr_seat.c1271
-rw-r--r--types/wlr_surface.c91
43 files changed, 3180 insertions, 2626 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fc5ccd9b..41f504bc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -171,7 +171,7 @@ Try to keep the use of macros to a minimum, especially if a function can do the
job. If you do need to use them, try to keep them close to where they're being
used and `#undef` them after.
-## Example
+### Example
```c
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
@@ -232,3 +232,125 @@ error_session:
return NULL;
}
```
+
+## Wayland protocol implementation
+
+Each protocol generally lives in a file with the same name, usually containing
+at leats one struct for each interface in the protocol. For instance,
+`xdg_shell` lives in `types/wlr_xdg_shell.h` and has a `wlr_xdg_surface` struct.
+
+### Globals
+
+Global interfaces generally have public constructors and destructors. Their
+struct has a field holding the `wl_global` itself, a list of resources clients
+created by binding to the global, a destroy signal and a `wl_display` destroy
+listener. Example:
+
+```c
+struct wlr_compositor {
+ struct wl_global *wl_global;
+ struct wl_list wl_resources;
+ …
+
+ struct wl_listener display_destroy;
+
+ struct {
+ struct wl_signal new_surface;
+ struct wl_signal destroy;
+ } events;
+};
+```
+
+When the destructor is called, it should emit the destroy signal, remove the
+display destroy listener, destroy the `wl_global`, destroy all bound resources
+and then destroy the struct.
+
+### Resources
+
+Resources are the representation of Wayland objects on the compositor side. They
+generally have an associated struct, called the _object struct_, stored in their
+`user_data` field.
+
+Object structs can be retrieved from resources via `wl_resource_get_data`. To
+prevent bad casts, a safe helper function checking the type of the resource is
+used:
+
+```c
+static const struct wl_surface_interface surface_impl;
+
+struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_surface_interface,
+ &surface_impl));
+ return wl_resource_get_user_data(resource);
+}
+```
+
+### Destroying resources
+
+Object structs should only be destroyed when their resource is destroyed, ie.
+in the resource destroy handler (set with `wl_resource_set_implementation`).
+Destructor requests should only call `wl_resource_destroy`.
+
+The compositor should not destroy resources on its own.
+
+### Inert resources
+
+Some resources can become inert in situations described in the protocol or when
+the compositor decides to get rid of them. All requests made to inert resources
+should be ignored, except the destructor. This is achieved by:
+
+1. When the resource becomes inert: destroy the object struct and call
+ `wl_resource_set_user_data(resource, NULL)`. Do not destroy the resource.
+2. For each request made to a resource that can be inert: add a NULL check to
+ ignore the request if the resource is inert.
+3. When the client calls the destructor request on the resource: call
+ `wl_resource_destroy(resource)` as usual.
+4. When the resource is destroyed, if the resource isn't inert, destroy the
+ object struct.
+
+Example:
+
+```c
+// Handles the destroy request
+static void subsurface_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+// Handles a regular request
+static void subsurface_set_position(struct wl_client *client,
+ struct wl_resource *resource, int32_t x, int32_t y) {
+ struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
+ if (subsurface == NULL) {
+ return;
+ }
+
+ …
+}
+
+// Destroys the wlr_subsurface struct
+static void subsurface_destroy(struct wlr_subsurface *subsurface) {
+ if (subsurface == NULL) {
+ return;
+ }
+
+ wl_resource_set_user_data(subsurface->resource, NULL);
+
+ …
+ free(subsurface);
+}
+
+// Resource destroy listener
+static void subsurface_handle_resource_destroy(struct wl_resource *resource) {
+ struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
+ subsurface_destroy(subsurface);
+}
+
+// Makes the resource inert
+static void subsurface_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_subsurface *subsurface =
+ wl_container_of(listener, subsurface, surface_destroy);
+ subsurface_destroy(subsurface);
+}
+```
diff --git a/README.md b/README.md
index d65949da..8ab2422e 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ code you were going to write anyway.
wlroots implements a huge variety of Wayland compositor features and implements
them *right*, so you can focus on the features that make your compositor
unique. By using wlroots, you get high performance, excellent hardware
-compatability, broad support for many wayland interfaces, and comfortable
+compatibility, broad support for many wayland interfaces, and comfortable
development tools - or any subset of these features you like, because all of
them work independently of one another and freely compose with anything you want
to implement yourself.
diff --git a/backend/drm/drm.c b/backend/drm/drm.c
index 70089e06..e8ed7316 100644
--- a/backend/drm/drm.c
+++ b/backend/drm/drm.c
@@ -32,7 +32,8 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
return false;
}
- if (getenv("WLR_DRM_NO_ATOMIC")) {
+ const char *no_atomic = getenv("WLR_DRM_NO_ATOMIC");
+ if (no_atomic && strcmp(no_atomic, "1") == 0) {
wlr_log(L_DEBUG, "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface");
drm->iface = &legacy_iface;
} else if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_ATOMIC, 1)) {
diff --git a/backend/drm/util.c b/backend/drm/util.c
index 41ba47d1..73669205 100644
--- a/backend/drm/util.c
+++ b/backend/drm/util.c
@@ -266,7 +266,7 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
continue;
}
- // Not compatable
+ // Not compatible
if (!(st->objs[st->res[i]] & (1 << i))) {
continue;
}
diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c
index 4fcd2fe4..f4d54c97 100644
--- a/backend/libinput/backend.c
+++ b/backend/libinput/backend.c
@@ -92,7 +92,7 @@ static bool backend_start(struct wlr_backend *_backend) {
wlr_log(L_ERROR, "Failed to create input event on event loop");
return false;
}
- wlr_log(L_DEBUG, "libinput sucessfully initialized");
+ wlr_log(L_DEBUG, "libinput successfully initialized");
return true;
}
diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c
index 454a2bb0..8191cb80 100644
--- a/backend/wayland/wl_seat.c
+++ b/backend/wayland/wl_seat.c
@@ -74,25 +74,11 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
}
struct wlr_output *wlr_output = &pointer->output->wlr_output;
-
- struct wlr_box box = {
- .x = wl_fixed_to_int(sx),
- .y = wl_fixed_to_int(sy),
- };
- wlr_box_transform(&box, wlr_output->transform, wlr_output->width,
- wlr_output->height, &box);
- box.x /= wlr_output->scale;
- box.y /= wlr_output->scale;
-
- int output_width, output_height;
- wlr_output_effective_resolution(&pointer->output->wlr_output,
- &output_width, &output_height);
-
struct wlr_event_pointer_motion_absolute event = {
.device = &pointer->input_device->wlr_input_device,
.time_msec = time,
- .x = (double)box.x / output_width,
- .y = (double)box.y / output_height,
+ .x = wl_fixed_to_double(sx) / wlr_output->width,
+ .y = wl_fixed_to_double(sy) / wlr_output->height,
};
wlr_signal_emit_safe(&pointer->wlr_pointer.events.motion_absolute, &event);
}
diff --git a/backend/x11/input_device.c b/backend/x11/input_device.c
index f8b87630..75cfa76e 100644
--- a/backend/x11/input_device.c
+++ b/backend/x11/input_device.c
@@ -32,21 +32,11 @@ static void x11_handle_pointer_position(struct wlr_x11_output *output,
int16_t x, int16_t y, xcb_timestamp_t time) {
struct wlr_x11_backend *x11 = output->x11;
struct wlr_output *wlr_output = &output->wlr_output;
-
- struct wlr_box box = { .x = x, .y = y };
- wlr_box_transform(&box, wlr_output->transform, wlr_output->width,
- wlr_output->height, &box);
- box.x /= wlr_output->scale;
- box.y /= wlr_output->scale;
-
- int output_width, output_height;
- wlr_output_effective_resolution(wlr_output, &output_width, &output_height);
-
struct wlr_event_pointer_motion_absolute event = {
.device = &output->pointer_dev,
.time_msec = time,
- .x = (double)box.x / output_width,
- .y = (double)box.y / output_height,
+ .x = (double)x / wlr_output->width,
+ .y = (double)y / wlr_output->height,
};
wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &event);
diff --git a/docs/env_vars.md b/docs/env_vars.md
new file mode 100644
index 00000000..5744701a
--- /dev/null
+++ b/docs/env_vars.md
@@ -0,0 +1,20 @@
+wlroots reads these environment variables
+
+wlroots specific
+----------------
+* *WLR_DRM_DEVICES*: specifies the DRM devices (as a colon separated list) instead of auto probing them. The first existing device in this list is considered the primary DRM device.
+* *WLR_DRM_NO_ATOMIC*: set to 1 to use legacy DRM interface instead of atomic mode setting
+* *WLR_LIBINPUT_NO_DEVICES*: set to 1 to not fail without any input devices
+* *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
+
+rootston specific
+------------------
+* *XKB_DEFAULT_RULES*, *XKB_DEFAULT_MODEL*, *XKB_DEFAULT_LAYOUT*, *XKB_DEFAULT_VARIANT*, *XKB_DEFAULT_OPTIONS*: xkb setup
+
+generic
+-------
+* *DISPLAY*: if set probe X11 backend in *wlr_backend_autocreate*
+* *WAYLAND_DISPLAY*, *_WAYLAND_DISPLAY*, *WAYLAND_SOCKET*: if set probe Wayland backend in *wlr_backend_autocreate*
+* *XCURSOR_PATH*: directory where xcursors are located
+* *XDG_RUNTIME_DIR*: used to store non persistent temporary files
diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h
index 1b3b2241..5b17e77e 100644
--- a/include/backend/drm/properties.h
+++ b/include/backend/drm/properties.h
@@ -24,7 +24,7 @@ union wlr_drm_connector_props {
union wlr_drm_crtc_props {
struct {
- // Neither of these are guranteed to exist
+ // Neither of these are guaranteed to exist
uint32_t rotation;
uint32_t scaling_mode;
@@ -41,7 +41,7 @@ union wlr_drm_crtc_props {
union wlr_drm_plane_props {
struct {
uint32_t type;
- uint32_t rotation; // Not guranteed to exist
+ uint32_t rotation; // Not guaranteed to exist
// atomic-modesetting only
diff --git a/include/types/wlr_data_device.h b/include/types/wlr_data_device.h
new file mode 100644
index 00000000..ee423f80
--- /dev/null
+++ b/include/types/wlr_data_device.h
@@ -0,0 +1,33 @@
+#ifndef TYPES_WLR_DATA_DEVICE_H
+#define TYPES_WLR_DATA_DEVICE_H
+
+#include <wayland-server.h>
+
+#define DATA_DEVICE_ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
+
+struct wlr_client_data_source {
+ struct wlr_data_source source;
+ struct wlr_data_source_impl impl;
+ struct wl_resource *resource;
+};
+
+struct wlr_data_offer *data_offer_create(struct wl_client *client,
+ struct wlr_data_source *source, uint32_t version);
+void data_offer_update_action(struct wlr_data_offer *offer);
+
+struct wlr_client_data_source *client_data_source_create(
+ struct wl_client *client, uint32_t version, uint32_t id,
+ struct wl_list *resource_list);
+struct wlr_client_data_source *client_data_source_from_resource(
+ struct wl_resource *resource);
+struct wlr_data_offer *data_source_send_offer(struct wlr_data_source *source,
+ struct wlr_seat_client *target);
+void data_source_notify_finish(struct wlr_data_source *source);
+
+bool seat_client_start_drag(struct wlr_seat_client *client,
+ struct wlr_data_source *source, struct wlr_surface *icon_surface,
+ struct wlr_surface *origin, uint32_t serial);
+
+#endif
diff --git a/include/types/wlr_seat.h b/include/types/wlr_seat.h
new file mode 100644
index 00000000..15f1dc38
--- /dev/null
+++ b/include/types/wlr_seat.h
@@ -0,0 +1,23 @@
+#ifndef TYPES_WLR_SEAT_H
+#define TYPES_WLR_SEAT_H
+
+#include <wayland-server.h>
+#include <wlr/types/wlr_seat.h>
+
+const struct wlr_pointer_grab_interface default_pointer_grab_impl;
+const struct wlr_keyboard_grab_interface default_keyboard_grab_impl;
+const struct wlr_touch_grab_interface default_touch_grab_impl;
+
+void seat_client_create_pointer(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+void seat_client_destroy_pointer(struct wl_resource *resource);
+
+void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+void seat_client_destroy_keyboard(struct wl_resource *resource);
+
+void seat_client_create_touch(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+void seat_client_destroy_touch(struct wl_resource *resource);
+
+#endif
diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h
index 7ff9691f..4d04b363 100644
--- a/include/wlr/backend/session.h
+++ b/include/wlr/backend/session.h
@@ -43,7 +43,7 @@ struct wlr_session {
* of the terminal (Xorg, another Wayland compositor, etc.).
*
* If logind support is not enabled, you must have CAP_SYS_ADMIN or be root.
- * It is safe to drop priviledges after this is called.
+ * It is safe to drop privileges after this is called.
*
* Returns NULL on error.
*/
diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h
index 1a9e0d38..998c6f0d 100644
--- a/include/wlr/types/wlr_cursor.h
+++ b/include/wlr/types/wlr_cursor.h
@@ -117,7 +117,7 @@ void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels,
/**
* Set the cursor surface. The surface can be committed to update the cursor
- * image. The surface position is substracted from the hotspot. A NULL surface
+ * image. The surface position is subtracted from the hotspot. A NULL surface
* commit hides the cursor.
*/
void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface,
diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h
index 6fb41c29..80d4bc8b 100644
--- a/include/wlr/types/wlr_data_device.h
+++ b/include/wlr/types/wlr_data_device.h
@@ -15,8 +15,16 @@ wlr_touch_grab_interface wlr_data_device_touch_drag_interface;
struct wlr_data_device_manager {
struct wl_global *global;
+ struct wl_list wl_resources;
+ struct wl_list data_sources;
struct wl_listener display_destroy;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ void *data;
};
struct wlr_data_offer {
diff --git a/include/wlr/types/wlr_idle.h b/include/wlr/types/wlr_idle.h
index 1744f07c..45f350be 100644
--- a/include/wlr/types/wlr_idle.h
+++ b/include/wlr/types/wlr_idle.h
@@ -7,7 +7,7 @@
/**
* Idle protocol is used to create timers which will notify the client when the
* compositor does not receive any input for a given time(in milliseconds). Also
- * the client will be notify when the timer receve an activity notify and already
+ * the client will be notified when the timer receives an activity notify and already
* was in idle state. Besides this, the client is able to simulate user activity
* which will reset the timers and at any time can destroy the timer.
*/
diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf.h
index 3fe8e1fc..531e68ab 100644
--- a/include/wlr/types/wlr_linux_dmabuf.h
+++ b/include/wlr/types/wlr_linux_dmabuf.h
@@ -25,8 +25,7 @@ struct wlr_dmabuf_buffer_attribs {
uint64_t modifier[WLR_LINUX_DMABUF_MAX_PLANES];
int fd[WLR_LINUX_DMABUF_MAX_PLANES];
/* set via params_create */
- int32_t width;
- int32_t height;
+ int32_t width, height;
uint32_t format;
uint32_t flags;
};
@@ -61,8 +60,15 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource(
/* the protocol interface */
struct wlr_linux_dmabuf {
struct wl_global *wl_global;
- struct wl_listener display_destroy;
struct wlr_renderer *renderer;
+ struct wl_list wl_resources;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ struct wl_listener display_destroy;
+ struct wl_listener renderer_destroy;
};
/**
diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h
index ff907f97..e1fa27bb 100644
--- a/include/wlr/types/wlr_seat.h
+++ b/include/wlr/types/wlr_seat.h
@@ -42,7 +42,6 @@ struct wlr_touch_point {
struct wl_listener surface_destroy;
struct wl_listener focus_surface_destroy;
- struct wl_listener resource_destroy;
struct {
struct wl_signal destroy;
@@ -138,7 +137,6 @@ struct wlr_seat_pointer_state {
uint32_t grab_time;
struct wl_listener surface_destroy;
- struct wl_listener resource_destroy;
};
// TODO: May be useful to be able to simulate keyboard input events
@@ -154,7 +152,6 @@ struct wlr_seat_keyboard_state {
struct wl_listener keyboard_repeat_info;
struct wl_listener surface_destroy;
- struct wl_listener resource_destroy;
struct wlr_seat_keyboard_grab *grab;
struct wlr_seat_keyboard_grab *default_grab;
diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h
index c6eb3c7d..d1127c86 100644
--- a/include/wlr/types/wlr_surface.h
+++ b/include/wlr/types/wlr_surface.h
@@ -171,7 +171,7 @@ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource);
/**
* Call `iterator` on each surface in the surface tree, with the surface's
- * positon relative to the root surface. The function is called from root to
+ * position relative to the root surface. The function is called from root to
* leaves (in rendering order).
*/
void wlr_surface_for_each_surface(struct wlr_surface *surface,
diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h
index 1b38b2e3..b60a0ddd 100644
--- a/include/wlr/types/wlr_wl_shell.h
+++ b/include/wlr/types/wlr_wl_shell.h
@@ -157,7 +157,7 @@ struct wlr_wl_surface *wlr_wl_shell_surface_from_wlr_surface(
/**
* Call `iterator` on each surface in the shell surface tree, with the surface's
- * positon relative to the root xdg-surface. The function is called from root to
+ * position relative to the root xdg-surface. The function is called from root to
* leaves (in rendering order).
*/
void wlr_wl_shell_surface_for_each_surface(struct wlr_wl_shell_surface *surface,
diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h
index ead4613a..22008563 100644
--- a/include/wlr/types/wlr_xdg_shell.h
+++ b/include/wlr/types/wlr_xdg_shell.h
@@ -128,7 +128,7 @@ struct wlr_xdg_surface_configure {
*
* When a surface has a role and is ready to be displayed, the `map` event is
* emitted. When a surface should no longer be displayed, the `unmap` event is
- * emitted. The `unmap` event is guaranted to be emitted before the `destroy`
+ * emitted. The `unmap` event is guaranteed to be emitted before the `destroy`
* event if the view is destroyed when mapped.
*/
struct wlr_xdg_surface {
@@ -314,7 +314,7 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface(
/**
* Call `iterator` on each surface in the xdg-surface tree, with the surface's
- * positon relative to the root xdg-surface. The function is called from root to
+ * position relative to the root xdg-surface. The function is called from root to
* leaves (in rendering order).
*/
void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface,
diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h
index a315c4d9..3d35520b 100644
--- a/include/wlr/types/wlr_xdg_shell_v6.h
+++ b/include/wlr/types/wlr_xdg_shell_v6.h
@@ -97,7 +97,7 @@ struct wlr_xdg_toplevel_v6_state {
*
* When a surface has a role and is ready to be displayed, the `map` event is
* emitted. When a surface should no longer be displayed, the `unmap` event is
- * emitted. The `unmap` event is guaranted to be emitted before the `destroy`
+ * emitted. The `unmap` event is guaranteed to be emitted before the `destroy`
* event if the view is destroyed when mapped.
*/
struct wlr_xdg_toplevel_v6 {
@@ -306,7 +306,7 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface(
/**
* Call `iterator` on each surface in the xdg-surface tree, with the surface's
- * positon relative to the root xdg-surface. The function is called from root to
+ * position relative to the root xdg-surface. The function is called from root to
* leaves (in rendering order).
*/
void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface,
diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h
index 11aedc37..b2c23667 100644
--- a/include/wlr/xwayland.h
+++ b/include/wlr/xwayland.h
@@ -81,7 +81,7 @@ struct wlr_xwayland_surface_size_hints {
*
* When a surface is ready to be displayed, the `map` event is emitted. When a
* surface should no longer be displayed, the `unmap` event is emitted. The
- * `unmap` event is guaranted to be emitted before the `destroy` event if the
+ * `unmap` event is guaranteed to be emitted before the `destroy` event if the
* view is destroyed when mapped.
*/
struct wlr_xwayland_surface {
diff --git a/protocol/wlr-layer-shell-unstable-v1.xml b/protocol/wlr-layer-shell-unstable-v1.xml
index 6a5d5d35..216e0d9f 100644
--- a/protocol/wlr-layer-shell-unstable-v1.xml
+++ b/protocol/wlr-layer-shell-unstable-v1.xml
@@ -140,7 +140,7 @@
how they should interact with surfaces that do. If set to zero, the
surface indicates that it would like to be moved to avoid occluding
surfaces with a positive excluzive zone. If set to -1, the surface
- indicates that it would not like to be moved to accomodate for other
+ indicates that it would not like to be moved to accommodate for other
surfaces, and the compositor should extend it all the way to the edges
it is anchored to.
diff --git a/rootston/output.c b/rootston/output.c
index 225b7213..d4c6d5a2 100644
--- a/rootston/output.c
+++ b/rootston/output.c
@@ -756,6 +756,8 @@ static void output_destroy(struct roots_output *output) {
wl_list_remove(&output->link);
wl_list_remove(&output->destroy.link);
+ wl_list_remove(&output->mode.link);
+ wl_list_remove(&output->transform.link);
wl_list_remove(&output->damage_frame.link);
wl_list_remove(&output->damage_destroy.link);
free(output);
diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c
index bd670a87..83a1caf0 100644
--- a/rootston/xdg_shell.c
+++ b/rootston/xdg_shell.c
@@ -18,6 +18,8 @@ static void popup_destroy(struct roots_view_child *child) {
}
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->new_popup.link);
+ wl_list_remove(&popup->map.link);
+ wl_list_remove(&popup->unmap.link);
view_child_finish(&popup->view_child);
free(popup);
}
diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c
index 39e8a4b7..5a829f5d 100644
--- a/rootston/xdg_shell_v6.c
+++ b/rootston/xdg_shell_v6.c
@@ -18,6 +18,8 @@ static void popup_destroy(struct roots_view_child *child) {
}
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->new_popup.link);
+ wl_list_remove(&popup->map.link);
+ wl_list_remove(&popup->unmap.link);
view_child_finish(&popup->view_child);
free(popup);
}
diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c
new file mode 100644
index 00000000..70ba3bfa
--- /dev/null
+++ b/types/data_device/wlr_data_device.c
@@ -0,0 +1,282 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+#define DATA_DEVICE_MANAGER_VERSION 3
+
+static const struct wl_data_device_interface data_device_impl;
+
+static struct wlr_seat_client *seat_client_from_data_device_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_device_interface,
+ &data_device_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void data_device_set_selection(struct wl_client *client,
+ struct wl_resource *device_resource,
+ struct wl_resource *source_resource, uint32_t serial) {
+ struct wlr_client_data_source *source = NULL;
+ if (source_resource != NULL) {
+ source = client_data_source_from_resource(source_resource);
+ }
+
+ struct wlr_seat_client *seat_client =
+ seat_client_from_data_device_resource(device_resource);
+
+ struct wlr_data_source *wlr_source = (struct wlr_data_source *)source;
+ wlr_seat_set_selection(seat_client->seat, wlr_source, serial);
+}
+
+static void data_device_start_drag(struct wl_client *client,
+ struct wl_resource *device_resource,
+ struct wl_resource *source_resource,
+ struct wl_resource *origin_resource, struct wl_resource *icon_resource,
+ uint32_t serial) {
+ struct wlr_seat_client *seat_client =
+ seat_client_from_data_device_resource(device_resource);
+ struct wlr_surface *origin = wlr_surface_from_resource(origin_resource);
+ struct wlr_data_source *source = NULL;
+ struct wlr_surface *icon = NULL;
+
+ if (source_resource) {
+ struct wlr_client_data_source *client_source =
+ client_data_source_from_resource(source_resource);
+ source = (struct wlr_data_source *)client_source;
+ }
+
+ if (icon_resource) {
+ icon = wlr_surface_from_resource(icon_resource);
+ }
+ if (icon) {
+ if (wlr_surface_set_role(icon, "wl_data_device-icon",
+ icon_resource, WL_DATA_DEVICE_ERROR_ROLE) < 0) {
+ return;
+ }
+ }
+
+ if (!seat_client_start_drag(seat_client, source, icon, origin, serial)) {
+ wl_resource_post_no_memory(device_resource);
+ return;
+ }
+
+ if (source) {
+ source->seat_client = seat_client;
+ }
+}
+
+static void data_device_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_data_device_interface data_device_impl = {
+ .start_drag = data_device_start_drag,
+ .set_selection = data_device_set_selection,
+ .release = data_device_release,
+};
+
+static void data_device_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+
+void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) {
+ if (wl_list_empty(&seat_client->data_devices)) {
+ return;
+ }
+
+ if (seat_client->seat->selection_source) {
+ struct wlr_data_offer *offer = data_source_send_offer(
+ seat_client->seat->selection_source, seat_client);
+ if (offer == NULL) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &seat_client->data_devices) {
+ wl_data_device_send_selection(resource, offer->resource);
+ }
+ } else {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &seat_client->data_devices) {
+ wl_data_device_send_selection(resource, NULL);
+ }
+ }
+}
+
+static void seat_client_selection_source_destroy(
+ struct wl_listener *listener, void *data) {
+ struct wlr_seat *seat =
+ wl_container_of(listener, seat, selection_source_destroy);
+ struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client;
+
+ if (seat_client && seat->keyboard_state.focused_surface) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &seat_client->data_devices) {
+ wl_data_device_send_selection(resource, NULL);
+ }
+ }
+
+ seat->selection_source = NULL;
+
+ wlr_signal_emit_safe(&seat->events.selection, seat);
+}
+
+void wlr_seat_set_selection(struct wlr_seat *seat,
+ struct wlr_data_source *source, uint32_t serial) {
+ if (seat->selection_source &&
+ seat->selection_serial - serial < UINT32_MAX / 2) {
+ return;
+ }
+
+ if (seat->selection_source) {
+ wl_list_remove(&seat->selection_source_destroy.link);
+ wlr_data_source_cancel(seat->selection_source);
+ seat->selection_source = NULL;
+ }
+
+ seat->selection_source = source;
+ seat->selection_serial = serial;
+
+ struct wlr_seat_client *focused_client =
+ seat->keyboard_state.focused_client;
+
+ if (focused_client) {
+ wlr_seat_client_send_selection(focused_client);
+ }
+
+ wlr_signal_emit_safe(&seat->events.selection, seat);
+
+ if (source) {
+ seat->selection_source_destroy.notify =
+ seat_client_selection_source_destroy;
+ wl_signal_add(&source->events.destroy,
+ &seat->selection_source_destroy);
+ }
+}
+
+
+static const struct wl_data_device_manager_interface data_device_manager_impl;
+
+static struct wlr_data_device_manager *data_device_manager_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_device_manager_interface,
+ &data_device_manager_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void data_device_manager_get_data_device(struct wl_client *client,
+ struct wl_resource *manager_resource, uint32_t id,
+ struct wl_resource *seat_resource) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+
+ struct wl_resource *resource = wl_resource_create(client,
+ &wl_data_device_interface, wl_resource_get_version(manager_resource),
+ id);
+ if (resource == NULL) {
+ wl_resource_post_no_memory(manager_resource);
+ return;
+ }
+ wl_resource_set_implementation(resource, &data_device_impl, seat_client,
+ &data_device_handle_resource_destroy);
+ wl_list_insert(&seat_client->data_devices, wl_resource_get_link(resource));
+}
+
+static void data_device_manager_create_data_source(struct wl_client *client,
+ struct wl_resource *manager_resource, uint32_t id) {
+ struct wlr_data_device_manager *manager =
+ data_device_manager_from_resource(manager_resource);
+
+ client_data_source_create(client, wl_resource_get_version(manager_resource),
+ id, &manager->data_sources);
+}
+
+static const struct wl_data_device_manager_interface
+ data_device_manager_impl = {
+ .create_data_source = data_device_manager_create_data_source,
+ .get_data_device = data_device_manager_get_data_device,
+};
+
+static void data_device_manager_handle_resource_destroy(
+ struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+static void data_device_manager_bind(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id) {
+ struct wlr_data_device_manager *manager = data;
+
+ struct wl_resource *resource = wl_resource_create(client,
+ &wl_data_device_manager_interface,
+ version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &data_device_manager_impl,
+ manager, data_device_manager_handle_resource_destroy);
+
+ wl_list_insert(&manager->wl_resources, wl_resource_get_link(resource));
+}
+
+void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) {
+ if (!manager) {
+ return;
+ }
+ wlr_signal_emit_safe(&manager->events.destroy, manager);
+ wl_list_remove(&manager->display_destroy.link);
+ wl_global_destroy(manager->global);
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &manager->wl_resources) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &manager->data_sources) {
+ wl_resource_destroy(resource);
+ }
+ free(manager);
+}
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_data_device_manager *manager =
+ wl_container_of(listener, manager, display_destroy);
+ wlr_data_device_manager_destroy(manager);
+}
+
+struct wlr_data_device_manager *wlr_data_device_manager_create(
+ struct wl_display *display) {
+ struct wlr_data_device_manager *manager =
+ calloc(1, sizeof(struct wlr_data_device_manager));
+ if (manager == NULL) {
+ wlr_log(L_ERROR, "could not create data device manager");
+ return NULL;
+ }
+
+ wl_list_init(&manager->wl_resources);
+ wl_list_init(&manager->data_sources);
+ wl_signal_init(&manager->events.destroy);
+
+ manager->global =
+ wl_global_create(display, &wl_data_device_manager_interface,
+ DATA_DEVICE_MANAGER_VERSION, manager, data_device_manager_bind);
+ if (!manager->global) {
+ wlr_log(L_ERROR, "could not create data device manager wl_global");
+ free(manager);
+ return NULL;
+ }
+
+ manager->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &manager->display_destroy);
+
+ return manager;
+}
diff --git a/types/data_device/wlr_data_offer.c b/types/data_device/wlr_data_offer.c
new file mode 100644
index 00000000..a5ea9183
--- /dev/null
+++ b/types/data_device/wlr_data_offer.c
@@ -0,0 +1,217 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+static const struct wl_data_offer_interface data_offer_impl;
+
+static struct wlr_data_offer *data_offer_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_offer_interface,
+ &data_offer_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) {
+ uint32_t offer_actions, preferred_action = 0;
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+ offer_actions = offer->actions;
+ preferred_action = offer->preferred_action;
+ } else {
+ offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ }
+
+ uint32_t source_actions;
+ if (offer->source->actions >= 0) {
+ source_actions = offer->source->actions;
+ } else {
+ source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ }
+
+ uint32_t available_actions = offer_actions & source_actions;
+ if (!available_actions) {
+ return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ }
+
+ if (offer->source->seat_client &&
+ offer->source->compositor_action & available_actions) {
+ return offer->source->compositor_action;
+ }
+
+ // If the dest side has a preferred DnD action, use it
+ if ((preferred_action & available_actions) != 0) {
+ return preferred_action;
+ }
+
+ // Use the first found action, in bit order
+ return 1 << (ffs(available_actions) - 1);
+}
+
+void data_offer_update_action(struct wlr_data_offer *offer) {
+ if (!offer->source) {
+ return;
+ }
+
+ uint32_t action = data_offer_choose_action(offer);
+ if (offer->source->current_dnd_action == action) {
+ return;
+ }
+
+ offer->source->current_dnd_action = action;
+
+ if (offer->in_ask) {
+ return;
+ }
+
+ wlr_data_source_dnd_action(offer->source, action);
+
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+ wl_data_offer_send_action(offer->resource, action);
+ }
+}
+
+static void data_offer_accept(struct wl_client *client,
+ struct wl_resource *resource, uint32_t serial, const char *mime_type) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (!offer->source || offer != offer->source->offer) {
+ return;
+ }
+
+ // TODO check that client is currently focused by the input device
+
+ wlr_data_source_accept(offer->source, serial, mime_type);
+}
+
+static void data_offer_receive(struct wl_client *client,
+ struct wl_resource *resource, const char *mime_type, int32_t fd) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (offer->source && offer == offer->source->offer) {
+ wlr_data_source_send(offer->source, mime_type, fd);
+ } else {
+ close(fd);
+ }
+}
+
+static void data_offer_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static void data_offer_finish(struct wl_client *client,
+ struct wl_resource *resource) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (!offer->source || offer->source->offer != offer) {
+ return;
+ }
+
+ data_source_notify_finish(offer->source);
+}
+
+static void data_offer_set_actions(struct wl_client *client,
+ struct wl_resource *resource, uint32_t actions,
+ uint32_t preferred_action) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (actions & ~DATA_DEVICE_ALL_ACTIONS) {
+ wl_resource_post_error(offer->resource,
+ WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
+ "invalid action mask %x", actions);
+ return;
+ }
+
+ if (preferred_action && (!(preferred_action & actions) ||
+ __builtin_popcount(preferred_action) > 1)) {
+ wl_resource_post_error(offer->resource,
+ WL_DATA_OFFER_ERROR_INVALID_ACTION,
+ "invalid action %x", preferred_action);
+ return;
+ }
+
+ offer->actions = actions;
+ offer->preferred_action = preferred_action;
+
+ data_offer_update_action(offer);
+}
+
+static void data_offer_handle_resource_destroy(struct wl_resource *resource) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (!offer->source) {
+ goto out;
+ }
+
+ wl_list_remove(&offer->source_destroy.link);
+
+ if (offer->source->offer != offer) {
+ goto out;
+ }
+
+ // If the drag destination has version < 3, wl_data_offer.finish
+ // won't be called, so do this here as a safety net, because
+ // we still want the version >= 3 drag source to be happy.
+ if (wl_resource_get_version(offer->resource) <
+ WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+ data_source_notify_finish(offer->source);
+ offer->source->offer = NULL;
+ } else if (offer->source->impl->dnd_finish) {
+ // source->cancel can free the source
+ offer->source->offer = NULL;
+ wlr_data_source_cancel(offer->source);
+ } else {
+ offer->source->offer = NULL;
+ }
+
+out:
+ free(offer);
+}
+
+static const struct wl_data_offer_interface data_offer_impl = {
+ .accept = data_offer_accept,
+ .receive = data_offer_receive,
+ .destroy = data_offer_destroy,
+ .finish = data_offer_finish,
+ .set_actions = data_offer_set_actions,
+};
+
+static void handle_offer_source_destroyed(struct wl_listener *listener,
+ void *data) {
+ struct wlr_data_offer *offer =
+ wl_container_of(listener, offer, source_destroy);
+
+ offer->source = NULL;
+}
+
+struct wlr_data_offer *data_offer_create(struct wl_client *client,
+ struct wlr_data_source *source, uint32_t version) {
+ struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer));
+ if (offer == NULL) {
+ return NULL;
+ }
+ offer->source = source;
+
+ offer->resource = wl_resource_create(client,
+ &wl_data_offer_interface, version, 0);
+ if (offer->resource == NULL) {
+ free(offer);
+ return NULL;
+ }
+ wl_resource_set_implementation(offer->resource, &data_offer_impl, offer,
+ data_offer_handle_resource_destroy);
+
+ offer->source_destroy.notify = handle_offer_source_destroyed;
+ wl_signal_add(&source->events.destroy, &offer->source_destroy);
+
+ return offer;
+}
diff --git a/types/data_device/wlr_data_source.c b/types/data_device/wlr_data_source.c
new file mode 100644
index 00000000..bf638f5a
--- /dev/null
+++ b/types/data_device/wlr_data_source.c
@@ -0,0 +1,291 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+void data_source_notify_finish(struct wlr_data_source *source) {
+ assert(source->offer);
+ if (source->actions < 0) {
+ return;
+ }
+
+ if (source->offer->in_ask) {
+ wlr_data_source_dnd_action(source, source->current_dnd_action);
+ }
+
+ source->offer = NULL;
+ wlr_data_source_dnd_finish(source);
+}
+
+struct wlr_data_offer *data_source_send_offer(struct wlr_data_source *source,
+ struct wlr_seat_client *target) {
+ if (wl_list_empty(&target->data_devices)) {
+ return NULL;
+ }
+
+ uint32_t version = wl_resource_get_version(
+ wl_resource_from_link(target->data_devices.next));
+
+ struct wlr_data_offer *offer =
+ data_offer_create(target->client, source, version);
+ if (offer == NULL) {
+ return NULL;
+ }
+
+ struct wl_resource *target_resource;
+ wl_resource_for_each(target_resource, &target->data_devices) {
+ wl_data_device_send_data_offer(target_resource, offer->resource);
+ }
+
+ char **p;
+ wl_array_for_each(p, &source->mime_types) {
+ wl_data_offer_send_offer(offer->resource, *p);
+ }
+
+ source->offer = offer;
+ source->accepted = false;
+ return offer;
+}
+
+void wlr_data_source_init(struct wlr_data_source *source,
+ const struct wlr_data_source_impl *impl) {
+ assert(impl->send);
+
+ source->impl = impl;
+ wl_array_init(&source->mime_types);
+ wl_signal_init(&source->events.destroy);
+ source->actions = -1;
+}
+
+void wlr_data_source_finish(struct wlr_data_source *source) {
+ if (source == NULL) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&source->events.destroy, source);
+
+ char **p;
+ wl_array_for_each(p, &source->mime_types) {
+ free(*p);
+ }
+ wl_array_release(&source->mime_types);
+}
+
+void wlr_data_source_send(struct wlr_data_source *source, const char *mime_type,
+ int32_t fd) {
+ source->impl->send(source, mime_type, fd);
+}
+
+void wlr_data_source_accept(struct wlr_data_source *source, uint32_t serial,
+ const char *mime_type) {
+ source->accepted = (mime_type != NULL);
+ if (source->impl->accept) {
+ source->impl->accept(source, serial, mime_type);
+ }
+}
+
+void wlr_data_source_cancel(struct wlr_data_source *source) {
+ if (source->impl->cancel) {
+ source->impl->cancel(source);
+ }
+}
+
+void wlr_data_source_dnd_drop(struct wlr_data_source *source) {
+ if (source->impl->dnd_drop) {
+ source->impl->dnd_drop(source);
+ }
+}
+
+void wlr_data_source_dnd_finish(struct wlr_data_source *source) {
+ if (source->impl->dnd_finish) {
+ source->impl->dnd_finish(source);
+ }
+}
+
+void wlr_data_source_dnd_action(struct wlr_data_source *source,
+ enum wl_data_device_manager_dnd_action action) {
+ source->current_dnd_action = action;
+ if (source->impl->dnd_action) {
+ source->impl->dnd_action(source, action);
+ }
+}
+
+
+static const struct wl_data_source_interface data_source_impl;
+
+struct wlr_client_data_source *client_data_source_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_source_interface,
+ &data_source_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void client_data_source_accept(struct wlr_data_source *wlr_source,
+ uint32_t serial, const char *mime_type);
+
+static struct wlr_client_data_source *client_data_source_from_wlr_data_source(
+ struct wlr_data_source *wlr_source) {
+ assert(wlr_source->impl->accept == client_data_source_accept);
+ return (struct wlr_client_data_source *)wlr_source;
+}
+
+static void client_data_source_accept(struct wlr_data_source *wlr_source,
+ uint32_t serial, const char *mime_type) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ wl_data_source_send_target(source->resource, mime_type);
+}
+
+static void client_data_source_send(struct wlr_data_source *wlr_source,
+ const char *mime_type, int32_t fd) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ wl_data_source_send_send(source->resource, mime_type, fd);
+ close(fd);
+}
+
+static void client_data_source_cancel(struct wlr_data_source *wlr_source) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ wl_data_source_send_cancelled(source->resource);
+}
+
+static void client_data_source_dnd_drop(struct wlr_data_source *wlr_source) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ assert(wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION);
+ wl_data_source_send_dnd_drop_performed(source->resource);
+}
+
+static void client_data_source_dnd_finish(struct wlr_data_source *wlr_source) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ assert(wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION);
+ wl_data_source_send_dnd_finished(source->resource);
+}
+
+static void client_data_source_dnd_action(struct wlr_data_source *wlr_source,
+ enum wl_data_device_manager_dnd_action action) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ assert(wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_ACTION_SINCE_VERSION);
+ wl_data_source_send_action(source->resource, action);
+}
+
+static void data_source_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static void data_source_set_actions(struct wl_client *client,
+ struct wl_resource *resource, uint32_t dnd_actions) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_resource(resource);
+
+ if (source->source.actions >= 0) {
+ wl_resource_post_error(source->resource,
+ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+ "cannot set actions more than once");
+ return;
+ }
+
+ if (dnd_actions & ~DATA_DEVICE_ALL_ACTIONS) {
+ wl_resource_post_error(source->resource,
+ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+ "invalid action mask %x", dnd_actions);
+ return;
+ }
+
+ if (source->source.seat_client) {
+ wl_resource_post_error(source->resource,
+ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+ "invalid action change after "
+ "wl_data_device.start_drag");
+ return;
+ }
+
+ source->source.actions = dnd_actions;
+}
+
+static void data_source_offer(struct wl_client *client,
+ struct wl_resource *resource, const char *mime_type) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_resource(resource);
+
+ char **p = wl_array_add(&source->source.mime_types, sizeof(*p));
+ if (p) {
+ *p = strdup(mime_type);
+ }
+ if (!p || !*p) {
+ if (p) {
+ source->source.mime_types.size -= sizeof(*p);
+ }
+ wl_resource_post_no_memory(resource);
+ }
+}
+
+static const struct wl_data_source_interface data_source_impl = {
+ .offer = data_source_offer,
+ .destroy = data_source_destroy,
+ .set_actions = data_source_set_actions,
+};
+
+static void data_source_handle_resource_destroy(struct wl_resource *resource) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_resource(resource);
+ wlr_data_source_finish(&source->source);
+ wl_list_remove(wl_resource_get_link(source->resource));
+ free(source);
+}
+
+struct wlr_client_data_source *client_data_source_create(
+ struct wl_client *client, uint32_t version, uint32_t id,
+ struct wl_list *resource_list) {
+ struct wlr_client_data_source *source =
+ calloc(1, sizeof(struct wlr_client_data_source));
+ if (source == NULL) {
+ return NULL;
+ }
+
+ source->resource = wl_resource_create(client, &wl_data_source_interface,
+ version, id);
+ if (source->resource == NULL) {
+ wl_resource_post_no_memory(source->resource);
+ free(source);
+ return NULL;
+ }
+ wl_resource_set_implementation(source->resource, &data_source_impl,
+ source, data_source_handle_resource_destroy);
+ wl_list_insert(resource_list, wl_resource_get_link(source->resource));
+
+ source->impl.accept = client_data_source_accept;
+ source->impl.send = client_data_source_send;
+ source->impl.cancel = client_data_source_cancel;
+
+ if (wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
+ source->impl.dnd_drop = client_data_source_dnd_drop;
+ }
+ if (wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
+ source->impl.dnd_finish = client_data_source_dnd_finish;
+ }
+ if (wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
+ source->impl.dnd_action = client_data_source_dnd_action;
+ }
+
+ wlr_data_source_init(&source->source, &source->impl);
+ return source;
+}
diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c
new file mode 100644
index 00000000..72a5bc41
--- /dev/null
+++ b/types/data_device/wlr_drag.c
@@ -0,0 +1,481 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+static void drag_handle_seat_client_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag *drag =
+ wl_container_of(listener, drag, seat_client_destroy);
+
+ drag->focus_client = NULL;
+ wl_list_remove(&drag->seat_client_destroy.link);
+}
+
+static void drag_set_focus(struct wlr_drag *drag,
+ struct wlr_surface *surface, double sx, double sy) {
+ if (drag->focus == surface) {
+ return;
+ }
+
+ if (drag->focus_client) {
+ wl_list_remove(&drag->seat_client_destroy.link);
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_leave(resource);
+ }
+
+ drag->focus_client = NULL;
+ drag->focus = NULL;
+ }
+
+ if (!surface || !surface->resource) {
+ return;
+ }
+
+ if (!drag->source &&
+ wl_resource_get_client(surface->resource) !=
+ wl_resource_get_client(drag->seat_client->wl_resource)) {
+ return;
+ }
+
+ if (drag->source && drag->source->offer) {
+ // unlink the offer from the source
+ wl_list_remove(&drag->source->offer->source_destroy.link);
+ drag->source->offer->source = NULL;
+ drag->source->offer = NULL;
+ }
+
+ struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client(
+ drag->seat_client->seat, wl_resource_get_client(surface->resource));
+ if (!focus_client) {
+ return;
+ }
+
+ struct wl_resource *offer_resource = NULL;
+ if (drag->source) {
+ drag->source->accepted = false;
+ struct wlr_data_offer *offer = data_source_send_offer(drag->source,
+ focus_client);
+ if (offer != NULL) {
+ data_offer_update_action(offer);
+
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
+ wl_data_offer_send_source_actions(offer->resource,
+ drag->source->actions);
+ }
+
+ offer_resource = offer->resource;
+ }
+ }
+
+ if (!wl_list_empty(&focus_client->data_devices)) {
+ uint32_t serial =
+ wl_display_next_serial(drag->seat_client->seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &focus_client->data_devices) {
+ wl_data_device_send_enter(resource, serial, surface->resource,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy),
+ offer_resource);
+ }
+ }
+
+ drag->focus = surface;
+ drag->focus_client = focus_client;
+ drag->seat_client_destroy.notify = drag_handle_seat_client_destroy;
+ wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy);
+
+ wlr_signal_emit_safe(&drag->events.focus, drag);
+}
+
+static void drag_end(struct wlr_drag *drag) {
+ if (!drag->cancelling) {
+ drag->cancelling = true;
+ if (drag->is_pointer_grab) {
+ wlr_seat_pointer_end_grab(drag->seat);
+ } else {
+ wlr_seat_touch_end_grab(drag->seat);
+ }
+ wlr_seat_keyboard_end_grab(drag->seat);
+
+ if (drag->source) {
+ wl_list_remove(&drag->source_destroy.link);
+ }
+
+ drag_set_focus(drag, NULL, 0, 0);
+
+ if (drag->icon) {
+ drag->icon->mapped = false;
+ wl_list_remove(&drag->icon_destroy.link);
+ wlr_signal_emit_safe(&drag->icon->events.map, drag->icon);
+ }
+
+ wlr_signal_emit_safe(&drag->events.destroy, drag);
+ free(drag);
+ }
+}
+
+static void drag_handle_pointer_enter(struct wlr_seat_pointer_grab *grab,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wlr_drag *drag = grab->data;
+ drag_set_focus(drag, surface, sx, sy);
+}
+
+static void drag_handle_pointer_motion(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, double sx, double sy) {
+ struct wlr_drag *drag = grab->data;
+ if (drag->focus != NULL && drag->focus_client != NULL) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx),
+ wl_fixed_from_double(sy));
+ }
+
+ struct wlr_drag_motion_event event = {
+ .drag = drag,
+ .time = time,
+ .sx = sx,
+ .sy = sy,
+ };
+ wlr_signal_emit_safe(&drag->events.motion, &event);
+ }
+}
+
+static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, uint32_t button, uint32_t state) {
+ struct wlr_drag *drag = grab->data;
+
+ if (drag->source &&
+ grab->seat->pointer_state.grab_button == button &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED) {
+ if (drag->focus_client && drag->source->current_dnd_action &&
+ drag->source->accepted) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_drop(resource);
+ }
+ wlr_data_source_dnd_drop(drag->source);
+
+ if (drag->source->offer != NULL) {
+ drag->source->offer->in_ask =
+ drag->source->current_dnd_action ==
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+ }
+
+ struct wlr_drag_drop_event event = {
+ .drag = drag,
+ .time = time,
+ };
+ wlr_signal_emit_safe(&drag->events.drop, &event);
+ } else if (drag->source->impl->dnd_finish) {
+ wlr_data_source_cancel(drag->source);
+ }
+ }
+
+ if (grab->seat->pointer_state.button_count == 0 &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED) {
+ drag_end(drag);
+ }
+
+ return 0;
+}
+
+static void drag_handle_pointer_axis(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, enum wlr_axis_orientation orientation, double value) {
+ // This space is intentionally left blank
+}
+
+static void drag_handle_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
+ struct wlr_drag *drag = grab->data;
+ drag_end(drag);
+}
+
+static const struct wlr_pointer_grab_interface
+ data_device_pointer_drag_interface = {
+ .enter = drag_handle_pointer_enter,
+ .motion = drag_handle_pointer_motion,
+ .button = drag_handle_pointer_button,
+ .axis = drag_handle_pointer_axis,
+ .cancel = drag_handle_pointer_cancel,
+};
+
+uint32_t drag_handle_touch_down(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ // eat the event
+ return 0;
+}
+
+static void drag_handle_touch_up(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ struct wlr_drag *drag = grab->data;
+ if (drag->grab_touch_id != point->touch_id) {
+ return;
+ }
+
+ if (drag->focus_client) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_drop(resource);
+ }
+ }
+
+ drag_end(drag);
+}
+
+static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ struct wlr_drag *drag = grab->data;
+ if (drag->focus && drag->focus_client) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_motion(resource, time,
+ wl_fixed_from_double(point->sx),
+ wl_fixed_from_double(point->sy));
+ }
+ }
+}
+
+static void drag_handle_touch_enter(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ struct wlr_drag *drag = grab->data;
+ drag_set_focus(drag, point->focus_surface, point->sx, point->sy);
+}
+
+static void drag_handle_touch_cancel(struct wlr_seat_touch_grab *grab) {
+ struct wlr_drag *drag = grab->data;
+ drag_end(drag);
+}
+
+static const struct wlr_touch_grab_interface
+ data_device_touch_drag_interface = {
+ .down = drag_handle_touch_down,
+ .up = drag_handle_touch_up,
+ .motion = drag_handle_touch_motion,
+ .enter = drag_handle_touch_enter,
+ .cancel = drag_handle_touch_cancel,
+};
+
+static void drag_handle_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ // nothing has keyboard focus during drags
+}
+
+static void drag_handle_keyboard_key(struct wlr_seat_keyboard_grab *grab,
+ uint32_t time, uint32_t key, uint32_t state) {
+ // no keyboard input during drags
+}
+
+static void drag_handle_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_keyboard_modifiers *modifiers) {
+ //struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard;
+ // TODO change the dnd action based on what modifier is pressed on the
+ // keyboard
+}
+
+static void drag_handle_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
+ struct wlr_drag *drag = grab->data;
+ drag_end(drag);
+}
+
+static const struct wlr_keyboard_grab_interface
+ data_device_keyboard_drag_interface = {
+ .enter = drag_handle_keyboard_enter,
+ .key = drag_handle_keyboard_key,
+ .modifiers = drag_handle_keyboard_modifiers,
+ .cancel = drag_handle_keyboard_cancel,
+};
+
+static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy);
+ drag->icon = NULL;
+}
+
+static void drag_handle_drag_source_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag *drag = wl_container_of(listener, drag, source_destroy);
+ drag_end(drag);
+}
+
+
+static void drag_icon_destroy(struct wlr_drag_icon *icon) {
+ if (!icon) {
+ return;
+ }
+ wlr_signal_emit_safe(&icon->events.destroy, icon);
+ wlr_surface_set_role_committed(icon->surface, NULL, NULL);
+ wl_list_remove(&icon->surface_destroy.link);
+ wl_list_remove(&icon->seat_client_destroy.link);
+ wl_list_remove(&icon->link);
+ free(icon);
+}
+
+static void drag_icon_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag_icon *icon =
+ wl_container_of(listener, icon, surface_destroy);
+ drag_icon_destroy(icon);
+}
+
+static void drag_icon_handle_surface_commit(struct wlr_surface *surface,
+ void *role_data) {
+ struct wlr_drag_icon *icon = role_data;
+ icon->sx += icon->surface->current->sx;
+ icon->sy += icon->surface->current->sy;
+}
+
+static void drag_icon_handle_seat_client_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag_icon *icon =
+ wl_container_of(listener, icon, seat_client_destroy);
+
+ drag_icon_destroy(icon);
+}
+
+static struct wlr_drag_icon *drag_icon_create(
+ struct wlr_surface *icon_surface, struct wlr_seat_client *client,
+ bool is_pointer, int32_t touch_id) {
+ struct wlr_drag_icon *icon = calloc(1, sizeof(struct wlr_drag_icon));
+ if (!icon) {
+ return NULL;
+ }
+
+ icon->surface = icon_surface;
+ icon->client = client;
+ icon->is_pointer = is_pointer;
+ icon->touch_id = touch_id;
+ icon->mapped = true;
+
+ wl_signal_init(&icon->events.map);
+ wl_signal_init(&icon->events.destroy);
+
+ wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy);
+ icon->surface_destroy.notify = drag_icon_handle_surface_destroy;
+
+ wlr_surface_set_role_committed(icon->surface,
+ drag_icon_handle_surface_commit, icon);
+
+ wl_signal_add(&client->events.destroy, &icon->seat_client_destroy);
+ icon->seat_client_destroy.notify = drag_icon_handle_seat_client_destroy;
+
+ wl_list_insert(&client->seat->drag_icons, &icon->link);
+ wlr_signal_emit_safe(&client->seat->events.new_drag_icon, icon);
+
+ return icon;
+}
+
+
+static void seat_handle_drag_source_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat *seat =
+ wl_container_of(listener, seat, drag_source_destroy);
+ wl_list_remove(&seat->drag_source_destroy.link);
+ seat->drag_source = NULL;
+}
+
+bool seat_client_start_drag(struct wlr_seat_client *client,
+ struct wlr_data_source *source, struct wlr_surface *icon_surface,
+ struct wlr_surface *origin, uint32_t serial) {
+ struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));
+ if (drag == NULL) {
+ return false;
+ }
+
+ wl_signal_init(&drag->events.focus);
+ wl_signal_init(&drag->events.motion);
+ wl_signal_init(&drag->events.drop);
+ wl_signal_init(&drag->events.destroy);
+
+ struct wlr_seat *seat = client->seat;
+ drag->seat = seat;
+
+ drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
+ seat->pointer_state.button_count == 1 &&
+ seat->pointer_state.grab_serial == serial &&
+ seat->pointer_state.focused_surface &&
+ seat->pointer_state.focused_surface == origin;
+
+ bool is_touch_grab = !wl_list_empty(&client->touches) &&
+ wlr_seat_touch_num_points(seat) == 1 &&
+ seat->touch_state.grab_serial == serial;
+
+ // set in the iteration
+ struct wlr_touch_point *point = NULL;
+ if (is_touch_grab) {
+ wl_list_for_each(point, &seat->touch_state.touch_points, link) {
+ is_touch_grab = point->surface && point->surface == origin;
+ break;
+ }
+ }
+
+ if (!drag->is_pointer_grab && !is_touch_grab) {
+ free(drag);
+ return true;
+ }
+
+ if (icon_surface) {
+ int32_t touch_id = (point ? point->touch_id : 0);
+ struct wlr_drag_icon *icon =
+ drag_icon_create(icon_surface, client, drag->is_pointer_grab,
+ touch_id);
+ if (!icon) {
+ free(drag);
+ return false;
+ }
+
+ drag->icon = icon;
+ drag->icon_destroy.notify = drag_handle_icon_destroy;
+ wl_signal_add(&icon->events.destroy, &drag->icon_destroy);
+ }
+
+ drag->source = source;
+ if (source != NULL) {
+ drag->source_destroy.notify = drag_handle_drag_source_destroy;
+ wl_signal_add(&source->events.destroy, &drag->source_destroy);
+ }
+
+ drag->seat_client = client;
+ drag->pointer_grab.data = drag;
+ drag->pointer_grab.interface = &data_device_pointer_drag_interface;
+
+ drag->touch_grab.data = drag;
+ drag->touch_grab.interface = &data_device_touch_drag_interface;
+ drag->grab_touch_id = seat->touch_state.grab_id;
+
+ drag->keyboard_grab.data = drag;
+ drag->keyboard_grab.interface = &data_device_keyboard_drag_interface;
+
+ wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab);
+
+ if (drag->is_pointer_grab) {
+ wlr_seat_pointer_clear_focus(seat);
+ wlr_seat_pointer_start_grab(seat, &drag->pointer_grab);
+ } else {
+ assert(point);
+ wlr_seat_touch_start_grab(seat, &drag->touch_grab);
+ drag_set_focus(drag, point->surface, point->sx, point->sy);
+ }
+
+ seat->drag = drag; // TODO: unset this thing somewhere
+ seat->drag_serial = serial;
+
+ seat->drag_source = source;
+ if (source != NULL) {
+ seat->drag_source_destroy.notify = seat_handle_drag_source_destroy;
+ wl_signal_add(&source->events.destroy, &seat->drag_source_destroy);
+ }
+
+ wlr_signal_emit_safe(&seat->events.start_drag, drag);
+
+ return true;
+}
diff --git a/types/meson.build b/types/meson.build
index 7e089d03..36db897e 100644
--- a/types/meson.build
+++ b/types/meson.build
@@ -1,14 +1,20 @@
lib_wlr_types = static_library(
'wlr_types',
files(
+ 'data_device/wlr_data_device.c',
+ 'data_device/wlr_data_offer.c',
+ 'data_device/wlr_data_source.c',
+ 'data_device/wlr_drag.c',
+ 'seat/wlr_seat_keyboard.c',
+ 'seat/wlr_seat_pointer.c',
+ 'seat/wlr_seat_touch.c',
+ 'seat/wlr_seat.c',
'wlr_box.c',
'wlr_compositor.c',
'wlr_cursor.c',
- 'wlr_data_device.c',
'wlr_gamma_control.c',
'wlr_idle_inhibit_v1.c',
'wlr_idle.c',
- 'wlr_idle_inhibit_v1.c',
'wlr_input_device.c',
'wlr_input_inhibitor.c',
'wlr_keyboard.c',
@@ -23,7 +29,6 @@ lib_wlr_types = static_library(
'wlr_primary_selection.c',
'wlr_region.c',
'wlr_screenshooter.c',
- 'wlr_seat.c',
'wlr_server_decoration.c',
'wlr_surface.c',
'wlr_tablet_pad.c',
@@ -31,9 +36,9 @@ lib_wlr_types = static_library(
'wlr_touch.c',
'wlr_wl_shell.c',
'wlr_xcursor_manager.c',
+ 'wlr_xdg_output.c',
'wlr_xdg_shell_v6.c',
'wlr_xdg_shell.c',
- 'wlr_xdg_output.c',
),
include_directories: wlr_inc,
dependencies: [pixman, xkbcommon, wayland_server, wlr_protos],
diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c
new file mode 100644
index 00000000..4a680157
--- /dev/null
+++ b/types/seat/wlr_seat.c
@@ -0,0 +1,336 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_primary_selection.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+#define SEAT_VERSION 6
+
+static void seat_handle_get_pointer(struct wl_client *client,
+ struct wl_resource *seat_resource, uint32_t id) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
+ wlr_log(L_ERROR, "Client sent get_pointer on seat without the "
+ "pointer capability");
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(seat_resource);
+ seat_client_create_pointer(seat_client, version, id);
+}
+
+static void seat_handle_get_keyboard(struct wl_client *client,
+ struct wl_resource *seat_resource, uint32_t id) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
+ wlr_log(L_ERROR, "Client sent get_keyboard on seat without the "
+ "keyboard capability");
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(seat_resource);
+ seat_client_create_keyboard(seat_client, version, id);
+}
+
+static void seat_handle_get_touch(struct wl_client *client,
+ struct wl_resource *seat_resource, uint32_t id) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
+ wlr_log(L_ERROR, "Client sent get_touch on seat without the "
+ "touch capability");
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(seat_resource);
+ seat_client_create_touch(seat_client, version, id);
+}
+
+static void seat_client_handle_resource_destroy(
+ struct wl_resource *seat_resource) {
+ struct wlr_seat_client *client =
+ wlr_seat_client_from_resource(seat_resource);
+ wlr_signal_emit_safe(&client->events.destroy, client);
+
+ if (client == client->seat->pointer_state.focused_client) {
+ client->seat->pointer_state.focused_client = NULL;
+ }
+ if (client == client->seat->keyboard_state.focused_client) {
+ client->seat->keyboard_state.focused_client = NULL;
+ }
+
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &client->pointers) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &client->touches) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &client->data_devices) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp,
+ &client->primary_selection_devices) {
+ wl_resource_destroy(resource);
+ }
+
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static void seat_handle_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_seat_interface seat_impl = {
+ .get_pointer = seat_handle_get_pointer,
+ .get_keyboard = seat_handle_get_keyboard,
+ .get_touch = seat_handle_get_touch,
+ .release = seat_handle_release,
+};
+
+static void seat_handle_bind(struct wl_client *client, void *_wlr_seat,
+ uint32_t version, uint32_t id) {
+ struct wlr_seat *wlr_seat = _wlr_seat;
+ assert(client && wlr_seat);
+
+ struct wlr_seat_client *seat_client =
+ calloc(1, sizeof(struct wlr_seat_client));
+ if (seat_client == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ seat_client->wl_resource =
+ wl_resource_create(client, &wl_seat_interface, version, id);
+ if (seat_client->wl_resource == NULL) {
+ free(seat_client);
+ wl_client_post_no_memory(client);
+ return;
+ }
+ seat_client->client = client;
+ seat_client->seat = wlr_seat;
+ wl_list_init(&seat_client->pointers);
+ wl_list_init(&seat_client->keyboards);
+ wl_list_init(&seat_client->touches);
+ wl_list_init(&seat_client->data_devices);
+ wl_list_init(&seat_client->primary_selection_devices);
+ wl_resource_set_implementation(seat_client->wl_resource, &seat_impl,
+ seat_client, seat_client_handle_resource_destroy);
+ wl_list_insert(&wlr_seat->clients, &seat_client->link);
+ if (version >= WL_SEAT_NAME_SINCE_VERSION) {
+ wl_seat_send_name(seat_client->wl_resource, wlr_seat->name);
+ }
+ wl_seat_send_capabilities(seat_client->wl_resource, wlr_seat->capabilities);
+ wl_signal_init(&seat_client->events.destroy);
+}
+
+void wlr_seat_destroy(struct wlr_seat *seat) {
+ if (!seat) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&seat->events.destroy, seat);
+
+ wl_list_remove(&seat->display_destroy.link);
+
+ if (seat->selection_source) {
+ wl_list_remove(&seat->selection_source_destroy.link);
+ wlr_data_source_cancel(seat->selection_source);
+ seat->selection_source = NULL;
+ }
+ if (seat->primary_selection_source) {
+ seat->primary_selection_source->cancel(seat->primary_selection_source);
+ seat->primary_selection_source = NULL;
+ wl_list_remove(&seat->primary_selection_source_destroy.link);
+ }
+
+ struct wlr_seat_client *client, *tmp;
+ wl_list_for_each_safe(client, tmp, &seat->clients, link) {
+ // will destroy other resources as well
+ wl_resource_destroy(client->wl_resource);
+ }
+
+ wl_global_destroy(seat->wl_global);
+ free(seat->pointer_state.default_grab);
+ free(seat->keyboard_state.default_grab);
+ free(seat->touch_state.default_grab);
+ free(seat->name);
+ free(seat);
+}
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_seat *seat =
+ wl_container_of(listener, seat, display_destroy);
+ wlr_seat_destroy(seat);
+}
+
+struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
+ struct wlr_seat *seat = calloc(1, sizeof(struct wlr_seat));
+ if (!seat) {
+ return NULL;
+ }
+
+ // pointer state
+ seat->pointer_state.seat = seat;
+ wl_list_init(&seat->pointer_state.surface_destroy.link);
+
+ struct wlr_seat_pointer_grab *pointer_grab =
+ calloc(1, sizeof(struct wlr_seat_pointer_grab));
+ if (!pointer_grab) {
+ free(seat);
+ return NULL;
+ }
+ pointer_grab->interface = &default_pointer_grab_impl;
+ pointer_grab->seat = seat;
+ seat->pointer_state.default_grab = pointer_grab;
+ seat->pointer_state.grab = pointer_grab;
+
+ // keyboard state
+ struct wlr_seat_keyboard_grab *keyboard_grab =
+ calloc(1, sizeof(struct wlr_seat_keyboard_grab));
+ if (!keyboard_grab) {
+ free(pointer_grab);
+ free(seat);
+ return NULL;
+ }
+ keyboard_grab->interface = &default_keyboard_grab_impl;
+ keyboard_grab->seat = seat;
+ seat->keyboard_state.default_grab = keyboard_grab;
+ seat->keyboard_state.grab = keyboard_grab;
+
+ seat->keyboard_state.seat = seat;
+ wl_list_init(&seat->keyboard_state.surface_destroy.link);
+
+ // touch state
+ struct wlr_seat_touch_grab *touch_grab =
+ calloc(1, sizeof(struct wlr_seat_touch_grab));
+ if (!touch_grab) {
+ free(pointer_grab);
+ free(keyboard_grab);
+ free(seat);
+ return NULL;
+ }
+ touch_grab->interface = &default_touch_grab_impl;
+ touch_grab->seat = seat;
+ seat->touch_state.default_grab = touch_grab;
+ seat->touch_state.grab = touch_grab;
+
+ seat->touch_state.seat = seat;
+ wl_list_init(&seat->touch_state.touch_points);
+
+ seat->wl_global = wl_global_create(display, &wl_seat_interface,
+ SEAT_VERSION, seat, seat_handle_bind);
+ if (seat->wl_global == NULL) {
+ free(touch_grab);
+ free(pointer_grab);
+ free(keyboard_grab);
+ free(seat);
+ return NULL;
+ }
+ seat->display = display;
+ seat->name = strdup(name);
+ wl_list_init(&seat->clients);
+ wl_list_init(&seat->drag_icons);
+
+ wl_signal_init(&seat->events.start_drag);
+ wl_signal_init(&seat->events.new_drag_icon);
+
+ wl_signal_init(&seat->events.request_set_cursor);
+
+ wl_signal_init(&seat->events.selection);
+ wl_signal_init(&seat->events.primary_selection);
+
+ wl_signal_init(&seat->events.pointer_grab_begin);
+ wl_signal_init(&seat->events.pointer_grab_end);
+
+ wl_signal_init(&seat->events.keyboard_grab_begin);
+ wl_signal_init(&seat->events.keyboard_grab_end);
+
+ wl_signal_init(&seat->events.touch_grab_begin);
+ wl_signal_init(&seat->events.touch_grab_end);
+
+ wl_signal_init(&seat->events.destroy);
+
+ seat->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &seat->display_destroy);
+
+ return seat;
+}
+
+struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat,
+ struct wl_client *wl_client) {
+ struct wlr_seat_client *seat_client;
+ wl_list_for_each(seat_client, &wlr_seat->clients, link) {
+ if (seat_client->client == wl_client) {
+ return seat_client;
+ }
+ }
+ return NULL;
+}
+
+void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
+ uint32_t capabilities) {
+ wlr_seat->capabilities = capabilities;
+
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &wlr_seat->clients, link) {
+ // Make resources inert if necessary
+ if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &client->pointers) {
+ seat_client_destroy_pointer(resource);
+ }
+ }
+ if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) {
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
+ seat_client_destroy_keyboard(resource);
+ }
+ }
+ if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0) {
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &client->touches) {
+ seat_client_destroy_touch(resource);
+ }
+ }
+
+ wl_seat_send_capabilities(client->wl_resource, capabilities);
+ }
+}
+
+void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) {
+ free(wlr_seat->name);
+ wlr_seat->name = strdup(name);
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &wlr_seat->clients, link) {
+ wl_seat_send_name(client->wl_resource, name);
+ }
+}
+
+struct wlr_seat_client *wlr_seat_client_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_seat_interface,
+ &seat_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
+ // TODO
+ //return serial == seat->pointer_state.grab_serial ||
+ // serial == seat->touch_state.grab_serial;
+ return true;
+}
diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c
new file mode 100644
index 00000000..77fda68f
--- /dev/null
+++ b/types/seat/wlr_seat_keyboard.c
@@ -0,0 +1,394 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_primary_selection.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
+}
+
+static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab,
+ uint32_t time, uint32_t key, uint32_t state) {
+ wlr_seat_keyboard_send_key(grab->seat, time, key, state);
+}
+
+static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_keyboard_modifiers *modifiers) {
+ wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
+}
+
+static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
+ // cannot be cancelled
+}
+
+const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = {
+ .enter = default_keyboard_enter,
+ .key = default_keyboard_key,
+ .modifiers = default_keyboard_modifiers,
+ .cancel = default_keyboard_cancel,
+};
+
+
+static void keyboard_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_keyboard_interface keyboard_impl = {
+ .release = keyboard_release,
+};
+
+static struct wlr_seat_client *seat_client_from_keyboard_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_keyboard_interface,
+ &keyboard_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void keyboard_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+ seat_client_destroy_keyboard(resource);
+}
+
+
+void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time,
+ uint32_t key, uint32_t state) {
+ struct wlr_seat_client *client = wlr_seat->keyboard_state.focused_client;
+ if (!client) {
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (seat_client_from_keyboard_resource(resource) == NULL) {
+ continue;
+ }
+
+ wl_keyboard_send_key(resource, serial, time, key, state);
+ }
+}
+
+static void seat_client_send_keymap(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard);
+
+static void handle_keyboard_keymap(struct wl_listener *listener, void *data) {
+ struct wlr_seat_keyboard_state *state =
+ wl_container_of(listener, state, keyboard_keymap);
+ struct wlr_seat_client *client;
+ struct wlr_keyboard *keyboard = data;
+ if (keyboard == state->keyboard) {
+ wl_list_for_each(client, &state->seat->clients, link) {
+ seat_client_send_keymap(client, state->keyboard);
+ }
+ }
+}
+
+static void seat_client_send_repeat_info(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard);
+
+static void handle_keyboard_repeat_info(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat_keyboard_state *state =
+ wl_container_of(listener, state, keyboard_repeat_info);
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &state->seat->clients, link) {
+ seat_client_send_repeat_info(client, state->keyboard);
+ }
+}
+
+static void handle_keyboard_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_seat_keyboard_state *state =
+ wl_container_of(listener, state, keyboard_destroy);
+ state->keyboard = NULL;
+}
+
+void wlr_seat_set_keyboard(struct wlr_seat *seat,
+ struct wlr_input_device *device) {
+ // TODO call this on device key event before the event reaches the
+ // compositor and set a pending keyboard and then send the new keyboard
+ // state on the next keyboard notify event.
+ struct wlr_keyboard *keyboard = (device ? device->keyboard : NULL);
+ if (seat->keyboard_state.keyboard == keyboard) {
+ return;
+ }
+
+ if (seat->keyboard_state.keyboard) {
+ wl_list_remove(&seat->keyboard_state.keyboard_destroy.link);
+ wl_list_remove(&seat->keyboard_state.keyboard_keymap.link);
+ wl_list_remove(&seat->keyboard_state.keyboard_repeat_info.link);
+ seat->keyboard_state.keyboard = NULL;
+ }
+
+ if (keyboard) {
+ assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
+ seat->keyboard_state.keyboard = keyboard;
+
+ wl_signal_add(&device->events.destroy,
+ &seat->keyboard_state.keyboard_destroy);
+ seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy;
+ wl_signal_add(&device->keyboard->events.keymap,
+ &seat->keyboard_state.keyboard_keymap);
+ seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap;
+ wl_signal_add(&device->keyboard->events.repeat_info,
+ &seat->keyboard_state.keyboard_repeat_info);
+ seat->keyboard_state.keyboard_repeat_info.notify =
+ handle_keyboard_repeat_info;
+
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &seat->clients, link) {
+ seat_client_send_keymap(client, keyboard);
+ seat_client_send_repeat_info(client, keyboard);
+ }
+
+ wlr_seat_keyboard_send_modifiers(seat, &keyboard->modifiers);
+ } else {
+ seat->keyboard_state.keyboard = NULL;
+ }
+}
+
+struct wlr_keyboard *wlr_seat_get_keyboard(struct wlr_seat *seat) {
+ return seat->keyboard_state.keyboard;
+}
+
+void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat,
+ struct wlr_seat_keyboard_grab *grab) {
+ grab->seat = wlr_seat;
+ wlr_seat->keyboard_state.grab = grab;
+
+ wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_begin, grab);
+}
+
+void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) {
+ struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab;
+
+ if (grab != wlr_seat->keyboard_state.default_grab) {
+ wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab;
+ wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_end, grab);
+ if (grab->interface->cancel) {
+ grab->interface->cancel(grab);
+ }
+ }
+}
+
+static void seat_keyboard_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat_keyboard_state *state = wl_container_of(
+ listener, state, surface_destroy);
+ wl_list_remove(&state->surface_destroy.link);
+ wl_list_init(&state->surface_destroy.link);
+ wlr_seat_keyboard_clear_focus(state->seat);
+}
+
+void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
+ struct wlr_keyboard_modifiers *modifiers) {
+ struct wlr_seat_client *client = seat->keyboard_state.focused_client;
+ if (client == NULL) {
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (seat_client_from_keyboard_resource(resource) == NULL) {
+ continue;
+ }
+
+ if (modifiers == NULL) {
+ wl_keyboard_send_modifiers(resource, serial, 0, 0, 0, 0);
+ } else {
+ wl_keyboard_send_modifiers(resource, serial,
+ modifiers->depressed, modifiers->latched,
+ modifiers->locked, modifiers->group);
+ }
+ }
+}
+
+void wlr_seat_keyboard_enter(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ if (seat->keyboard_state.focused_surface == surface) {
+ // this surface already got an enter notify
+ return;
+ }
+
+ struct wlr_seat_client *client = NULL;
+
+ if (surface) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ client = wlr_seat_client_for_wl_client(seat, wl_client);
+ }
+
+ struct wlr_seat_client *focused_client =
+ seat->keyboard_state.focused_client;
+ struct wlr_surface *focused_surface =
+ seat->keyboard_state.focused_surface;
+
+ // leave the previously entered surface
+ if (focused_client != NULL && focused_surface != NULL) {
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &focused_client->keyboards) {
+ if (seat_client_from_keyboard_resource(resource) == NULL) {
+ continue;
+ }
+ wl_keyboard_send_leave(resource, serial, focused_surface->resource);
+ }
+ }
+
+ // enter the current surface
+ if (client != NULL) {
+ struct wl_array keys;
+ wl_array_init(&keys);
+ for (size_t i = 0; i < num_keycodes; ++i) {
+ uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
+ if (!p) {
+ wlr_log(L_ERROR, "Cannot allocate memory, skipping keycode: %d\n",
+ keycodes[i]);
+ continue;
+ }
+ *p = keycodes[i];
+ }
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (seat_client_from_keyboard_resource(resource) == NULL) {
+ continue;
+ }
+ wl_keyboard_send_enter(resource, serial, surface->resource, &keys);
+ }
+ wl_array_release(&keys);
+
+ wlr_seat_client_send_selection(client);
+ wlr_seat_client_send_primary_selection(client);
+ }
+
+ // reinitialize the focus destroy events
+ wl_list_remove(&seat->keyboard_state.surface_destroy.link);
+ wl_list_init(&seat->keyboard_state.surface_destroy.link);
+ if (surface) {
+ wl_signal_add(&surface->events.destroy,
+ &seat->keyboard_state.surface_destroy);
+ seat->keyboard_state.surface_destroy.notify =
+ seat_keyboard_handle_surface_destroy;
+ }
+
+ seat->keyboard_state.focused_client = client;
+ seat->keyboard_state.focused_surface = surface;
+
+ if (client != NULL) {
+ // tell new client about any modifier change last,
+ // as it targets seat->keyboard_state.focused_client
+ wlr_seat_keyboard_send_modifiers(seat, modifiers);
+ }
+}
+
+void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
+ grab->interface->enter(grab, surface, keycodes, num_keycodes, modifiers);
+}
+
+void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) {
+ // TODO respect grabs here?
+ wlr_seat_keyboard_enter(seat, NULL, NULL, 0, NULL);
+}
+
+bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat) {
+ return seat->keyboard_state.grab->interface != &default_keyboard_grab_impl;
+}
+
+void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat,
+ struct wlr_keyboard_modifiers *modifiers) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
+ grab->interface->modifiers(grab, modifiers);
+}
+
+void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,
+ uint32_t key, uint32_t state) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
+ grab->interface->key(grab, time, key, state);
+}
+
+
+static void seat_client_send_keymap(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard) {
+ if (!keyboard) {
+ return;
+ }
+
+ // TODO: We should probably lift all of the keys set by the other
+ // keyboard
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (seat_client_from_keyboard_resource(resource) == NULL) {
+ continue;
+ }
+
+ wl_keyboard_send_keymap(resource,
+ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd,
+ keyboard->keymap_size);
+ }
+}
+
+static void seat_client_send_repeat_info(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard) {
+ if (!keyboard) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (seat_client_from_keyboard_resource(resource) == NULL) {
+ continue;
+ }
+
+ if (wl_resource_get_version(resource) >=
+ WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
+ wl_keyboard_send_repeat_info(resource,
+ keyboard->repeat_info.rate, keyboard->repeat_info.delay);
+ }
+ }
+}
+
+void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(seat_client->client,
+ &wl_keyboard_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(seat_client->client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &keyboard_impl, seat_client,
+ keyboard_handle_resource_destroy);
+ wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource));
+
+ struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard;
+ seat_client_send_keymap(seat_client, keyboard);
+ seat_client_send_repeat_info(seat_client, keyboard);
+
+ // TODO possibly handle the case where this keyboard needs an enter
+ // right away
+}
+
+void seat_client_destroy_keyboard(struct wl_resource *resource) {
+ struct wlr_seat_client *seat_client =
+ seat_client_from_keyboard_resource(resource);
+ if (seat_client == NULL) {
+ return;
+ }
+ wl_resource_set_user_data(resource, NULL);
+}
diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c
new file mode 100644
index 00000000..4a0bcef1
--- /dev/null
+++ b/types/seat/wlr_seat_pointer.c
@@ -0,0 +1,338 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static void default_pointer_enter(struct wlr_seat_pointer_grab *grab,
+ struct wlr_surface *surface, double sx, double sy) {
+ wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
+}
+
+static void default_pointer_motion(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, double sx, double sy) {
+ wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
+}
+
+static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, uint32_t button, uint32_t state) {
+ return wlr_seat_pointer_send_button(grab->seat, time, button, state);
+}
+
+static void default_pointer_axis(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, enum wlr_axis_orientation orientation, double value) {
+ wlr_seat_pointer_send_axis(grab->seat, time, orientation, value);
+}
+
+static void default_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
+ // cannot be cancelled
+}
+
+const struct wlr_pointer_grab_interface default_pointer_grab_impl = {
+ .enter = default_pointer_enter,
+ .motion = default_pointer_motion,
+ .button = default_pointer_button,
+ .axis = default_pointer_axis,
+ .cancel = default_pointer_cancel,
+};
+
+
+static void pointer_send_frame(struct wl_resource *resource) {
+ if (wl_resource_get_version(resource) >=
+ WL_POINTER_FRAME_SINCE_VERSION) {
+ wl_pointer_send_frame(resource);
+ }
+}
+
+static const struct wl_pointer_interface pointer_impl;
+
+static struct wlr_seat_client *seat_client_from_pointer_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_pointer_interface,
+ &pointer_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void pointer_set_cursor(struct wl_client *client,
+ struct wl_resource *pointer_resource, uint32_t serial,
+ struct wl_resource *surface_resource,
+ int32_t hotspot_x, int32_t hotspot_y) {
+ struct wlr_seat_client *seat_client =
+ seat_client_from_pointer_resource(pointer_resource);
+ if (seat_client == NULL) {
+ return;
+ }
+
+ struct wlr_surface *surface = NULL;
+ if (surface_resource != NULL) {
+ surface = wlr_surface_from_resource(surface_resource);
+ if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource,
+ WL_POINTER_ERROR_ROLE) < 0) {
+ return;
+ }
+ }
+
+ struct wlr_seat_pointer_request_set_cursor_event event = {
+ .seat_client = seat_client,
+ .surface = surface,
+ .serial = serial,
+ .hotspot_x = hotspot_x,
+ .hotspot_y = hotspot_y,
+ };
+ wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, &event);
+}
+
+static void pointer_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_pointer_interface pointer_impl = {
+ .set_cursor = pointer_set_cursor,
+ .release = pointer_release,
+};
+
+static void pointer_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+ seat_client_destroy_pointer(resource);
+}
+
+
+bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat,
+ struct wlr_surface *surface) {
+ return surface == wlr_seat->pointer_state.focused_surface;
+}
+
+static void seat_pointer_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat_pointer_state *state =
+ wl_container_of(listener, state, surface_destroy);
+ wl_list_remove(&state->surface_destroy.link);
+ wl_list_init(&state->surface_destroy.link);
+ wlr_seat_pointer_clear_focus(state->seat);
+}
+
+void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
+ struct wlr_surface *surface, double sx, double sy) {
+ if (wlr_seat->pointer_state.focused_surface == surface) {
+ // this surface already got an enter notify
+ return;
+ }
+
+ struct wlr_seat_client *client = NULL;
+ if (surface) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ client = wlr_seat_client_for_wl_client(wlr_seat, wl_client);
+ }
+
+ struct wlr_seat_client *focused_client =
+ wlr_seat->pointer_state.focused_client;
+ struct wlr_surface *focused_surface =
+ wlr_seat->pointer_state.focused_surface;
+
+ // leave the previously entered surface
+ if (focused_client != NULL && focused_surface != NULL) {
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &focused_client->pointers) {
+ if (seat_client_from_pointer_resource(resource) == NULL) {
+ continue;
+ }
+
+ wl_pointer_send_leave(resource, serial, focused_surface->resource);
+ pointer_send_frame(resource);
+ }
+ }
+
+ // enter the current surface
+ if (client != NULL && surface != NULL) {
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ if (seat_client_from_pointer_resource(resource) == NULL) {
+ continue;
+ }
+
+ wl_pointer_send_enter(resource, serial, surface->resource,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ pointer_send_frame(resource);
+ }
+ }
+
+ // reinitialize the focus destroy events
+ wl_list_remove(&wlr_seat->pointer_state.surface_destroy.link);
+ wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
+ if (surface != NULL) {
+ wl_signal_add(&surface->events.destroy,
+ &wlr_seat->pointer_state.surface_destroy);
+ wlr_seat->pointer_state.surface_destroy.notify =
+ seat_pointer_handle_surface_destroy;
+ }
+
+ wlr_seat->pointer_state.focused_client = client;
+ wlr_seat->pointer_state.focused_surface = surface;
+
+ // TODO: send focus change event
+}
+
+void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) {
+ wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0);
+}
+
+void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
+ double sx, double sy) {
+ struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
+ if (client == NULL) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ if (seat_client_from_pointer_resource(resource) == NULL) {
+ continue;
+ }
+
+ wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx),
+ wl_fixed_from_double(sy));
+ pointer_send_frame(resource);
+ }
+}
+
+uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
+ uint32_t button, uint32_t state) {
+ struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
+ if (client == NULL) {
+ return 0;
+ }
+
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ if (seat_client_from_pointer_resource(resource) == NULL) {
+ continue;
+ }
+
+ wl_pointer_send_button(resource, serial, time, button, state);
+ pointer_send_frame(resource);
+ }
+ return serial;
+}
+
+void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
+ enum wlr_axis_orientation orientation, double value) {
+ struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
+ if (client == NULL) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ if (seat_client_from_pointer_resource(resource) == NULL) {
+ continue;
+ }
+
+ if (value) {
+ wl_pointer_send_axis(resource, time, orientation,
+ wl_fixed_from_double(value));
+ } else if (wl_resource_get_version(resource) >=
+ WL_POINTER_AXIS_STOP_SINCE_VERSION) {
+ wl_pointer_send_axis_stop(resource, time, orientation);
+ }
+ pointer_send_frame(resource);
+ }
+}
+
+void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
+ struct wlr_seat_pointer_grab *grab) {
+ assert(wlr_seat);
+ grab->seat = wlr_seat;
+ wlr_seat->pointer_state.grab = grab;
+
+ wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab);
+}
+
+void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) {
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ if (grab != wlr_seat->pointer_state.default_grab) {
+ wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab;
+ wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_end, grab);
+ if (grab->interface->cancel) {
+ grab->interface->cancel(grab);
+ }
+ }
+}
+
+void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ grab->interface->enter(grab, surface, sx, sy);
+}
+
+void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time,
+ double sx, double sy) {
+ clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ grab->interface->motion(grab, time, sx, sy);
+}
+
+uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat,
+ uint32_t time, uint32_t button, uint32_t state) {
+ clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ if (wlr_seat->pointer_state.button_count == 0) {
+ wlr_seat->pointer_state.grab_button = button;
+ wlr_seat->pointer_state.grab_time = time;
+ }
+ wlr_seat->pointer_state.button_count++;
+ } else {
+ wlr_seat->pointer_state.button_count--;
+ }
+
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ uint32_t serial = grab->interface->button(grab, time, button, state);
+
+ if (serial && wlr_seat->pointer_state.button_count == 1) {
+ wlr_seat->pointer_state.grab_serial = serial;
+ }
+
+ return serial;
+}
+
+void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,
+ enum wlr_axis_orientation orientation, double value) {
+ clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ grab->interface->axis(grab, time, orientation, value);
+}
+
+bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) {
+ return seat->pointer_state.grab->interface != &default_pointer_grab_impl;
+}
+
+
+void seat_client_create_pointer(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(seat_client->client,
+ &wl_pointer_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(seat_client->client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &pointer_impl, seat_client,
+ &pointer_handle_resource_destroy);
+ wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource));
+}
+
+void seat_client_destroy_pointer(struct wl_resource *resource) {
+ struct wlr_seat_client *seat_client =
+ seat_client_from_pointer_resource(resource);
+ if (seat_client == NULL) {
+ return;
+ }
+ wl_resource_set_user_data(resource, NULL);
+}
diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c
new file mode 100644
index 00000000..489882ba
--- /dev/null
+++ b/types/seat/wlr_seat_touch.c
@@ -0,0 +1,361 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ return wlr_seat_touch_send_down(grab->seat, point->surface, time,
+ point->touch_id, point->sx, point->sy);
+}
+
+static void default_touch_up(struct wlr_seat_touch_grab *grab, uint32_t time,
+ struct wlr_touch_point *point) {
+ wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
+}
+
+static void default_touch_motion(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ if (!point->focus_surface || point->focus_surface == point->surface) {
+ wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx,
+ point->sy);
+ }
+}
+
+static void default_touch_enter(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ // not handled by default
+}
+
+static void default_touch_cancel(struct wlr_seat_touch_grab *grab) {
+ // cannot be cancelled
+}
+
+const struct wlr_touch_grab_interface default_touch_grab_impl = {
+ .down = default_touch_down,
+ .up = default_touch_up,
+ .motion = default_touch_motion,
+ .enter = default_touch_enter,
+ .cancel = default_touch_cancel,
+};
+
+
+static void touch_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_touch_interface touch_impl = {
+ .release = touch_release,
+};
+
+static void touch_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+ seat_client_destroy_touch(resource);
+}
+
+static struct wlr_seat_client *seat_client_from_touch_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_touch_interface,
+ &touch_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+
+void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat,
+ struct wlr_seat_touch_grab *grab) {
+ grab->seat = wlr_seat;
+ wlr_seat->touch_state.grab = grab;
+
+ wlr_signal_emit_safe(&wlr_seat->events.touch_grab_begin, grab);
+}
+
+void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) {
+ struct wlr_seat_touch_grab *grab = wlr_seat->touch_state.grab;
+
+ if (grab != wlr_seat->touch_state.default_grab) {
+ wlr_seat->touch_state.grab = wlr_seat->touch_state.default_grab;
+ wlr_signal_emit_safe(&wlr_seat->events.touch_grab_end, grab);
+ if (grab->interface->cancel) {
+ grab->interface->cancel(grab);
+ }
+ }
+}
+
+static void touch_point_clear_focus(struct wlr_touch_point *point) {
+ if (point->focus_surface) {
+ wl_list_remove(&point->focus_surface_destroy.link);
+ point->focus_client = NULL;
+ point->focus_surface = NULL;
+ }
+}
+
+static void touch_point_destroy(struct wlr_touch_point *point) {
+ wlr_signal_emit_safe(&point->events.destroy, point);
+
+ touch_point_clear_focus(point);
+ wl_list_remove(&point->surface_destroy.link);
+ wl_list_remove(&point->link);
+ free(point);
+}
+
+static void touch_point_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_touch_point *point =
+ wl_container_of(listener, point, surface_destroy);
+ touch_point_destroy(point);
+}
+
+static struct wlr_touch_point *touch_point_create(
+ struct wlr_seat *seat, int32_t touch_id,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ struct wlr_seat_client *client =
+ wlr_seat_client_for_wl_client(seat, wl_client);
+
+ if (client == NULL || wl_list_empty(&client->touches)) {
+ // touch points are not valid without a connected client with touch
+ return NULL;
+ }
+
+ struct wlr_touch_point *point = calloc(1, sizeof(struct wlr_touch_point));
+ if (!point) {
+ return NULL;
+ }
+
+ point->touch_id = touch_id;
+ point->surface = surface;
+ point->client = client;
+
+ point->sx = sx;
+ point->sy = sy;
+
+ wl_signal_init(&point->events.destroy);
+
+ wl_signal_add(&surface->events.destroy, &point->surface_destroy);
+ point->surface_destroy.notify = touch_point_handle_surface_destroy;
+
+ wl_list_insert(&seat->touch_state.touch_points, &point->link);
+
+ return point;
+}
+
+struct wlr_touch_point *wlr_seat_touch_get_point(
+ struct wlr_seat *seat, int32_t touch_id) {
+ struct wlr_touch_point *point = NULL;
+ wl_list_for_each(point, &seat->touch_state.touch_points, link) {
+ if (point->touch_id == touch_id) {
+ return point;
+ }
+ }
+
+ return NULL;
+}
+
+uint32_t wlr_seat_touch_notify_down(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ struct wlr_touch_point *point =
+ touch_point_create(seat, touch_id, surface, sx, sy);
+ if (!point) {
+ wlr_log(L_ERROR, "could not create touch point");
+ return 0;
+ }
+
+ uint32_t serial = grab->interface->down(grab, time, point);
+
+ if (serial && wlr_seat_touch_num_points(seat) == 1) {
+ seat->touch_state.grab_serial = serial;
+ seat->touch_state.grab_id = touch_id;
+ }
+
+ return serial;
+}
+
+void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ return;
+ }
+
+ grab->interface->up(grab, time, point);
+
+ touch_point_destroy(point);
+}
+
+void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id, double sx, double sy) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ return;
+ }
+
+ point->sx = sx;
+ point->sy = sy;
+
+ grab->interface->motion(grab, time, point);
+}
+
+static void handle_point_focus_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_touch_point *point =
+ wl_container_of(listener, point, focus_surface_destroy);
+ touch_point_clear_focus(point);
+}
+
+static void touch_point_set_focus(struct wlr_touch_point *point,
+ struct wlr_surface *surface, double sx, double sy) {
+ if (point->focus_surface == surface) {
+ return;
+ }
+
+ touch_point_clear_focus(point);
+
+ if (surface && surface->resource) {
+ struct wlr_seat_client *client =
+ wlr_seat_client_for_wl_client(point->client->seat,
+ wl_resource_get_client(surface->resource));
+
+ if (client && !wl_list_empty(&client->touches)) {
+ wl_signal_add(&surface->events.destroy, &point->focus_surface_destroy);
+ point->focus_surface_destroy.notify = handle_point_focus_destroy;
+ point->focus_surface = surface;
+ point->focus_client = client;
+ point->sx = sx;
+ point->sy = sy;
+ }
+ }
+}
+
+void wlr_seat_touch_point_focus(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ assert(surface);
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch point focus for unknown touch point");
+ return;
+ }
+ struct wlr_surface *focus = point->focus_surface;
+ touch_point_set_focus(point, surface, sx, sy);
+
+ if (focus != point->focus_surface) {
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ grab->interface->enter(grab, time, point);
+ }
+}
+
+void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch point focus for unknown touch point");
+ return;
+ }
+
+ touch_point_clear_focus(point);
+}
+
+uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch down for unknown touch point");
+ return 0;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &point->client->touches) {
+ if (seat_client_from_touch_resource(resource) == NULL) {
+ continue;
+ }
+ wl_touch_send_down(resource, serial, time, surface->resource,
+ touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ wl_touch_send_frame(resource);
+ }
+
+ return serial;
+}
+
+void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_id) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch up for unknown touch point");
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &point->client->touches) {
+ if (seat_client_from_touch_resource(resource) == NULL) {
+ continue;
+ }
+ wl_touch_send_up(resource, serial, time, touch_id);
+ wl_touch_send_frame(resource);
+ }
+}
+
+void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id,
+ double sx, double sy) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch motion for unknown touch point");
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &point->client->touches) {
+ if (seat_client_from_touch_resource(resource) == NULL) {
+ continue;
+ }
+ wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx),
+ wl_fixed_from_double(sy));
+ wl_touch_send_frame(resource);
+ }
+}
+
+int wlr_seat_touch_num_points(struct wlr_seat *seat) {
+ return wl_list_length(&seat->touch_state.touch_points);
+}
+
+bool wlr_seat_touch_has_grab(struct wlr_seat *seat) {
+ return seat->touch_state.grab->interface != &default_touch_grab_impl;
+}
+
+
+void seat_client_create_touch(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(seat_client->client,
+ &wl_touch_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(seat_client->client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &touch_impl, seat_client,
+ &touch_handle_resource_destroy);
+ wl_list_insert(&seat_client->touches, wl_resource_get_link(resource));
+}
+
+void seat_client_destroy_touch(struct wl_resource *resource) {
+ struct wlr_seat_client *seat_client =
+ seat_client_from_touch_resource(resource);
+ if (seat_client == NULL) {
+ return;
+ }
+ wl_resource_set_user_data(resource, NULL);
+}
diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c
index f10d891c..e4fd41dc 100644
--- a/types/wlr_compositor.c
+++ b/types/wlr_compositor.c
@@ -7,6 +7,9 @@
#include <wlr/util/log.h>
#include "util/signal.h"
+#define COMPOSITOR_VERSION 4
+#define SUBCOMPOSITOR_VERSION 1
+
static const char *subsurface_role = "wl_subsurface";
bool wlr_surface_is_subsurface(struct wlr_surface *surface) {
@@ -105,7 +108,8 @@ static void subcompositor_bind(struct wl_client *client, void *data,
static void subcompositor_init(struct wlr_subcompositor *subcompositor,
struct wl_display *display) {
subcompositor->wl_global = wl_global_create(display,
- &wl_subcompositor_interface, 1, subcompositor, subcompositor_bind);
+ &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION, subcompositor,
+ subcompositor_bind);
if (subcompositor->wl_global == NULL) {
wlr_log_errno(L_ERROR, "Could not allocate subcompositor global");
return;
@@ -136,7 +140,7 @@ static struct wlr_compositor *compositor_from_resource(
return wl_resource_get_user_data(resource);
}
-static void wl_compositor_create_surface(struct wl_client *client,
+static void compositor_create_surface(struct wl_client *client,
struct wl_resource *resource, uint32_t id) {
struct wlr_compositor *compositor = compositor_from_resource(resource);
@@ -150,7 +154,7 @@ static void wl_compositor_create_surface(struct wl_client *client,
wlr_signal_emit_safe(&compositor->events.new_surface, surface);
}
-static void wl_compositor_create_region(struct wl_client *client,
+static void compositor_create_region(struct wl_client *client,
struct wl_resource *resource, uint32_t id) {
struct wlr_compositor *compositor = compositor_from_resource(resource);
@@ -158,15 +162,15 @@ static void wl_compositor_create_region(struct wl_client *client,
}
static const struct wl_compositor_interface compositor_impl = {
- .create_surface = wl_compositor_create_surface,
- .create_region = wl_compositor_create_region,
+ .create_surface = compositor_create_surface,
+ .create_region = compositor_create_region,
};
static void compositor_resource_destroy(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
}
-static void wl_compositor_bind(struct wl_client *wl_client, void *data,
+static void compositor_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
struct wlr_compositor *compositor = data;
assert(wl_client && compositor);
@@ -218,14 +222,13 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
return NULL;
}
- struct wl_global *compositor_global = wl_global_create(display,
- &wl_compositor_interface, 4, compositor, wl_compositor_bind);
- if (!compositor_global) {
- wlr_log_errno(L_ERROR, "Could not allocate compositor global");
+ compositor->wl_global = wl_global_create(display, &wl_compositor_interface,
+ COMPOSITOR_VERSION, compositor, compositor_bind);
+ if (!compositor->wl_global) {
free(compositor);
+ wlr_log_errno(L_ERROR, "Could not allocate compositor global");
return NULL;
}
- compositor->wl_global = compositor_global;
compositor->renderer = renderer;
wl_list_init(&compositor->wl_resources);
diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c
index aec7b013..9a31fca2 100644
--- a/types/wlr_cursor.c
+++ b/types/wlr_cursor.c
@@ -330,11 +330,75 @@ static void handle_pointer_motion(struct wl_listener *listener, void *data) {
wlr_signal_emit_safe(&device->cursor->events.motion, event);
}
+static void apply_output_transform(double *x, double *y,
+ enum wl_output_transform transform) {
+ double dx = *x, dy = *y;
+ double width = 1.0, height = 1.0;
+
+ switch (transform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ dx = *x;
+ dy = *y;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ dx = *y;
+ dy = width - *x;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ dx = width - *x;
+ dy = height - *y;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ dx = height - *y;
+ dy = *x;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ dx = width - *x;
+ dy = *y;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ dx = height - *y;
+ dy = width - *x;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ dx = *x;
+ dy = height - *y;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ dx = *y;
+ dy = *x;
+ break;
+ }
+ *x = dx;
+ *y = dy;
+}
+
+
+static struct wlr_output *get_mapped_output(struct wlr_cursor_device *cursor_device) {
+ if (cursor_device->mapped_output) {
+ return cursor_device->mapped_output;
+ }
+
+ struct wlr_cursor *cursor = cursor_device->cursor;
+ assert(cursor);
+ if (cursor->state->mapped_output) {
+ return cursor->state->mapped_output;
+ }
+ return NULL;
+}
+
+
static void handle_pointer_motion_absolute(struct wl_listener *listener,
void *data) {
struct wlr_event_pointer_motion_absolute *event = data;
struct wlr_cursor_device *device =
wl_container_of(listener, device, motion_absolute);
+
+ struct wlr_output *output =
+ get_mapped_output(device);
+ if (output) {
+ apply_output_transform(&event->x, &event->y, output->transform);
+ }
wlr_signal_emit_safe(&device->cursor->events.motion_absolute, event);
}
@@ -362,6 +426,12 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
struct wlr_event_touch_down *event = data;
struct wlr_cursor_device *device;
device = wl_container_of(listener, device, touch_down);
+
+ struct wlr_output *output =
+ get_mapped_output(device);
+ if (output) {
+ apply_output_transform(&event->x, &event->y, output->transform);
+ }
wlr_signal_emit_safe(&device->cursor->events.touch_down, event);
}
@@ -369,6 +439,12 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct wlr_event_touch_motion *event = data;
struct wlr_cursor_device *device;
device = wl_container_of(listener, device, touch_motion);
+
+ struct wlr_output *output =
+ get_mapped_output(device);
+ if (output) {
+ apply_output_transform(&event->x, &event->y, output->transform);
+ }
wlr_signal_emit_safe(&device->cursor->events.touch_motion, event);
}
@@ -383,6 +459,12 @@ static void handle_tablet_tool_tip(struct wl_listener *listener, void *data) {
struct wlr_event_tablet_tool_tip *event = data;
struct wlr_cursor_device *device;
device = wl_container_of(listener, device, tablet_tool_tip);
+
+ struct wlr_output *output =
+ get_mapped_output(device);
+ if (output) {
+ apply_output_transform(&event->x, &event->y, output->transform);
+ }
wlr_signal_emit_safe(&device->cursor->events.tablet_tool_tip, event);
}
@@ -390,6 +472,12 @@ static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) {
struct wlr_event_tablet_tool_axis *event = data;
struct wlr_cursor_device *device;
device = wl_container_of(listener, device, tablet_tool_axis);
+
+ struct wlr_output *output =
+ get_mapped_output(device);
+ if (output) {
+ apply_output_transform(&event->x, &event->y, output->transform);
+ }
wlr_signal_emit_safe(&device->cursor->events.tablet_tool_axis, event);
}
@@ -406,6 +494,12 @@ static void handle_tablet_tool_proximity(struct wl_listener *listener,
struct wlr_event_tablet_tool_proximity *event = data;
struct wlr_cursor_device *device;
device = wl_container_of(listener, device, tablet_tool_proximity);
+
+ struct wlr_output *output =
+ get_mapped_output(device);
+ if (output) {
+ apply_output_transform(&event->x, &event->y, output->transform);
+ }
wlr_signal_emit_safe(&device->cursor->events.tablet_tool_proximity, event);
}
diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c
deleted file mode 100644
index 23e54809..00000000
--- a/types/wlr_data_device.c
+++ /dev/null
@@ -1,1203 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <wayland-server.h>
-#include <wlr/types/wlr_data_device.h>
-#include <wlr/types/wlr_seat.h>
-#include <wlr/util/log.h>
-#include "util/signal.h"
-
-#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
- WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
-
-static const struct wl_data_offer_interface data_offer_impl;
-
-static struct wlr_data_offer *data_offer_from_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_data_offer_interface,
- &data_offer_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static const struct wl_data_source_interface data_source_impl;
-
-static struct client_data_source *client_data_source_from_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_data_source_interface,
- &data_source_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) {
- uint32_t offer_actions, preferred_action = 0;
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- offer_actions = offer->actions;
- preferred_action = offer->preferred_action;
- } else {
- offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
-
- uint32_t source_actions;
- if (offer->source->actions >= 0) {
- source_actions = offer->source->actions;
- } else {
- source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
-
- uint32_t available_actions = offer_actions & source_actions;
- if (!available_actions) {
- return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- }
-
- if (offer->source->seat_client &&
- offer->source->compositor_action & available_actions) {
- return offer->source->compositor_action;
- }
-
- // If the dest side has a preferred DnD action, use it
- if ((preferred_action & available_actions) != 0) {
- return preferred_action;
- }
-
- // Use the first found action, in bit order
- return 1 << (ffs(available_actions) - 1);
-}
-
-static void data_offer_update_action(struct wlr_data_offer *offer) {
- if (!offer->source) {
- return;
- }
-
- uint32_t action = data_offer_choose_action(offer);
- if (offer->source->current_dnd_action == action) {
- return;
- }
-
- offer->source->current_dnd_action = action;
-
- if (offer->in_ask) {
- return;
- }
-
- wlr_data_source_dnd_action(offer->source, action);
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- wl_data_offer_send_action(offer->resource, action);
- }
-}
-
-static void data_offer_accept(struct wl_client *client,
- struct wl_resource *resource, uint32_t serial, const char *mime_type) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (!offer->source || offer != offer->source->offer) {
- return;
- }
-
- // TODO check that client is currently focused by the input device
-
- wlr_data_source_accept(offer->source, serial, mime_type);
-}
-
-static void data_offer_receive(struct wl_client *client,
- struct wl_resource *resource, const char *mime_type, int32_t fd) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (offer->source && offer == offer->source->offer) {
- wlr_data_source_send(offer->source, mime_type, fd);
- } else {
- close(fd);
- }
-}
-static void data_offer_destroy(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static void data_source_notify_finish(struct wlr_data_source *source) {
- assert(source->offer);
- if (source->actions < 0) {
- return;
- }
-
- if (source->offer->in_ask) {
- wlr_data_source_dnd_action(source, source->current_dnd_action);
- }
-
- source->offer = NULL;
- wlr_data_source_dnd_finish(source);
-}
-
-static void data_offer_finish(struct wl_client *client,
- struct wl_resource *resource) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (!offer->source || offer->source->offer != offer) {
- return;
- }
-
- data_source_notify_finish(offer->source);
-}
-
-static void data_offer_set_actions(struct wl_client *client,
- struct wl_resource *resource, uint32_t actions,
- uint32_t preferred_action) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (actions & ~ALL_ACTIONS) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
- "invalid action mask %x", actions);
- return;
- }
-
- if (preferred_action && (!(preferred_action & actions) ||
- __builtin_popcount(preferred_action) > 1)) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_ACTION,
- "invalid action %x", preferred_action);
- return;
- }
-
- offer->actions = actions;
- offer->preferred_action = preferred_action;
-
- data_offer_update_action(offer);
-}
-
-static void data_offer_resource_destroy(struct wl_resource *resource) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (!offer->source) {
- goto out;
- }
-
- wl_list_remove(&offer->source_destroy.link);
-
- if (offer->source->offer != offer) {
- goto out;
- }
-
- // If the drag destination has version < 3, wl_data_offer.finish
- // won't be called, so do this here as a safety net, because
- // we still want the version >= 3 drag source to be happy.
- if (wl_resource_get_version(offer->resource) <
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- data_source_notify_finish(offer->source);
- offer->source->offer = NULL;
- } else if (offer->source->impl->dnd_finish) {
- // source->cancel can free the source
- offer->source->offer = NULL;
- wlr_data_source_cancel(offer->source);
- } else {
- offer->source->offer = NULL;
- }
-
-out:
- free(offer);
-}
-
-static const struct wl_data_offer_interface data_offer_impl = {
- .accept = data_offer_accept,
- .receive = data_offer_receive,
- .destroy = data_offer_destroy,
- .finish = data_offer_finish,
- .set_actions = data_offer_set_actions,
-};
-
-static void handle_offer_source_destroyed(struct wl_listener *listener,
- void *data) {
- struct wlr_data_offer *offer =
- wl_container_of(listener, offer, source_destroy);
-
- offer->source = NULL;
-}
-
-static struct wlr_data_offer *data_source_send_offer(
- struct wlr_data_source *source,
- struct wlr_seat_client *target) {
- if (wl_list_empty(&target->data_devices)) {
- return NULL;
- }
-
- struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer));
- if (offer == NULL) {
- return NULL;
- }
-
- uint32_t version = wl_resource_get_version(
- wl_resource_from_link(target->data_devices.next));
- offer->resource = wl_resource_create(target->client,
- &wl_data_offer_interface, version, 0);
- if (offer->resource == NULL) {
- free(offer);
- return NULL;
- }
- wl_resource_set_implementation(offer->resource, &data_offer_impl, offer,
- data_offer_resource_destroy);
-
- offer->source_destroy.notify = handle_offer_source_destroyed;
- wl_signal_add(&source->events.destroy, &offer->source_destroy);
-
- struct wl_resource *target_resource;
- wl_resource_for_each(target_resource, &target->data_devices) {
- wl_data_device_send_data_offer(target_resource, offer->resource);
- }
-
- char **p;
- wl_array_for_each(p, &source->mime_types) {
- wl_data_offer_send_offer(offer->resource, *p);
- }
-
- offer->source = source;
- source->offer = offer;
- source->accepted = false;
-
- return offer;
-}
-
-void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) {
- if (wl_list_empty(&seat_client->data_devices)) {
- return;
- }
-
- if (seat_client->seat->selection_source) {
- struct wlr_data_offer *offer = data_source_send_offer(
- seat_client->seat->selection_source, seat_client);
- if (offer == NULL) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &seat_client->data_devices) {
- wl_data_device_send_selection(resource, offer->resource);
- }
- } else {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &seat_client->data_devices) {
- wl_data_device_send_selection(resource, NULL);
- }
- }
-}
-
-static void seat_client_selection_source_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_seat *seat =
- wl_container_of(listener, seat, selection_source_destroy);
- struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client;
-
- if (seat_client && seat->keyboard_state.focused_surface) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &seat_client->data_devices) {
- wl_data_device_send_selection(resource, NULL);
- }
- }
-
- seat->selection_source = NULL;
-
- wlr_signal_emit_safe(&seat->events.selection, seat);
-}
-
-void wlr_seat_set_selection(struct wlr_seat *seat,
- struct wlr_data_source *source, uint32_t serial) {
- if (seat->selection_source &&
- seat->selection_serial - serial < UINT32_MAX / 2) {
- return;
- }
-
- if (seat->selection_source) {
- wl_list_remove(&seat->selection_source_destroy.link);
- wlr_data_source_cancel(seat->selection_source);
- seat->selection_source = NULL;
- }
-
- seat->selection_source = source;
- seat->selection_serial = serial;
-
- struct wlr_seat_client *focused_client =
- seat->keyboard_state.focused_client;
-
- if (focused_client) {
- wlr_seat_client_send_selection(focused_client);
- }
-
- wlr_signal_emit_safe(&seat->events.selection, seat);
-
- if (source) {
- seat->selection_source_destroy.notify =
- seat_client_selection_source_destroy;
- wl_signal_add(&source->events.destroy,
- &seat->selection_source_destroy);
- }
-}
-
-static const struct wl_data_device_interface data_device_impl;
-
-static struct wlr_seat_client *seat_client_from_data_device_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_data_device_interface,
- &data_device_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static void data_device_set_selection(struct wl_client *client,
- struct wl_resource *device_resource,
- struct wl_resource *source_resource, uint32_t serial) {
- struct client_data_source *source = NULL;
- if (source_resource != NULL) {
- source = client_data_source_from_resource(source_resource);
- }
-
- struct wlr_seat_client *seat_client =
- seat_client_from_data_device_resource(device_resource);
-
- struct wlr_data_source *wlr_source = (struct wlr_data_source *)source;
- wlr_seat_set_selection(seat_client->seat, wlr_source, serial);
-}
-
-static void data_device_release(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static void handle_drag_seat_client_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag *drag =
- wl_container_of(listener, drag, seat_client_destroy);
-
- drag->focus_client = NULL;
- wl_list_remove(&drag->seat_client_destroy.link);
-}
-
-static void drag_set_focus(struct wlr_drag *drag,
- struct wlr_surface *surface, double sx, double sy) {
- if (drag->focus == surface) {
- return;
- }
-
- if (drag->focus_client) {
- wl_list_remove(&drag->seat_client_destroy.link);
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_leave(resource);
- }
-
- drag->focus_client = NULL;
- drag->focus = NULL;
- }
-
- if (!surface || !surface->resource) {
- return;
- }
-
- if (!drag->source &&
- wl_resource_get_client(surface->resource) !=
- wl_resource_get_client(drag->seat_client->wl_resource)) {
- return;
- }
-
- if (drag->source && drag->source->offer) {
- // unlink the offer from the source
- wl_list_remove(&drag->source->offer->source_destroy.link);
- drag->source->offer->source = NULL;
- drag->source->offer = NULL;
- }
-
- struct wlr_seat_client *focus_client =
- wlr_seat_client_for_wl_client(drag->seat_client->seat,
- wl_resource_get_client(surface->resource));
- if (!focus_client) {
- return;
- }
-
- struct wl_resource *offer_resource = NULL;
- if (drag->source) {
- drag->source->accepted = false;
- struct wlr_data_offer *offer = data_source_send_offer(drag->source,
- focus_client);
- if (offer != NULL) {
- data_offer_update_action(offer);
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
- wl_data_offer_send_source_actions(offer->resource,
- drag->source->actions);
- }
-
- offer_resource = offer->resource;
- }
- }
-
- if (!wl_list_empty(&focus_client->data_devices)) {
- uint32_t serial =
- wl_display_next_serial(drag->seat_client->seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &focus_client->data_devices) {
- wl_data_device_send_enter(resource, serial, surface->resource,
- wl_fixed_from_double(sx), wl_fixed_from_double(sy),
- offer_resource);
- }
- }
-
- drag->focus = surface;
- drag->focus_client = focus_client;
- drag->seat_client_destroy.notify = handle_drag_seat_client_destroy;
- wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy);
-
- wlr_signal_emit_safe(&drag->events.focus, drag);
-}
-
-static void drag_end(struct wlr_drag *drag) {
- if (!drag->cancelling) {
- drag->cancelling = true;
- if (drag->is_pointer_grab) {
- wlr_seat_pointer_end_grab(drag->seat);
- } else {
- wlr_seat_touch_end_grab(drag->seat);
- }
- wlr_seat_keyboard_end_grab(drag->seat);
-
- if (drag->source) {
- wl_list_remove(&drag->source_destroy.link);
- }
-
- drag_set_focus(drag, NULL, 0, 0);
-
- if (drag->icon) {
- drag->icon->mapped = false;
- wl_list_remove(&drag->icon_destroy.link);
- wlr_signal_emit_safe(&drag->icon->events.map, drag->icon);
- }
-
- wlr_signal_emit_safe(&drag->events.destroy, drag);
- free(drag);
- }
-}
-
-static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab,
- struct wlr_surface *surface, double sx, double sy) {
- struct wlr_drag *drag = grab->data;
- drag_set_focus(drag, surface, sx, sy);
-}
-
-static void pointer_drag_motion(struct wlr_seat_pointer_grab *grab,
- uint32_t time, double sx, double sy) {
- struct wlr_drag *drag = grab->data;
- if (drag->focus != NULL && drag->focus_client != NULL) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx),
- wl_fixed_from_double(sy));
- }
-
- struct wlr_drag_motion_event event = {
- .drag = drag,
- .time = time,
- .sx = sx,
- .sy = sy,
- };
- wlr_signal_emit_safe(&drag->events.motion, &event);
- }
-}
-
-static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab,
- uint32_t time, uint32_t button, uint32_t state) {
- struct wlr_drag *drag = grab->data;
-
- if (drag->source &&
- grab->seat->pointer_state.grab_button == button &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- if (drag->focus_client && drag->source->current_dnd_action &&
- drag->source->accepted) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_drop(resource);
- }
- wlr_data_source_dnd_drop(drag->source);
-
- if (drag->source->offer != NULL) {
- drag->source->offer->in_ask =
- drag->source->current_dnd_action ==
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
- }
-
- struct wlr_drag_drop_event event = {
- .drag = drag,
- .time = time,
- };
- wlr_signal_emit_safe(&drag->events.drop, &event);
- } else if (drag->source->impl->dnd_finish) {
- wlr_data_source_cancel(drag->source);
- }
- }
-
- if (grab->seat->pointer_state.button_count == 0 &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- drag_end(drag);
- }
-
- return 0;
-}
-
-static void pointer_drag_axis(struct wlr_seat_pointer_grab *grab, uint32_t time,
- enum wlr_axis_orientation orientation, double value) {
- // This space is intentionally left blank
-}
-
-static void pointer_drag_cancel(struct wlr_seat_pointer_grab *grab) {
- struct wlr_drag *drag = grab->data;
- drag_end(drag);
-}
-
-static const struct wlr_pointer_grab_interface
- data_device_pointer_drag_interface = {
- .enter = pointer_drag_enter,
- .motion = pointer_drag_motion,
- .button = pointer_drag_button,
- .axis = pointer_drag_axis,
- .cancel = pointer_drag_cancel,
-};
-
-uint32_t touch_drag_down(struct wlr_seat_touch_grab *grab,
- uint32_t time, struct wlr_touch_point *point) {
- // eat the event
- return 0;
-}
-
-static void touch_drag_up(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- struct wlr_drag *drag = grab->data;
- if (drag->grab_touch_id != point->touch_id) {
- return;
- }
-
- if (drag->focus_client) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_drop(resource);
- }
- }
-
- drag_end(drag);
-}
-
-static void touch_drag_motion(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- struct wlr_drag *drag = grab->data;
- if (drag->focus && drag->focus_client) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_motion(resource, time,
- wl_fixed_from_double(point->sx),
- wl_fixed_from_double(point->sy));
- }
- }
-}
-
-static void touch_drag_enter(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- struct wlr_drag *drag = grab->data;
- drag_set_focus(drag, point->focus_surface, point->sx, point->sy);
-}
-
-static void touch_drag_cancel(struct wlr_seat_touch_grab *grab) {
- struct wlr_drag *drag = grab->data;
- drag_end(drag);
-}
-
-static const struct wlr_touch_grab_interface
- data_device_touch_drag_interface = {
- .down = touch_drag_down,
- .up = touch_drag_up,
- .motion = touch_drag_motion,
- .enter = touch_drag_enter,
- .cancel = touch_drag_cancel,
-};
-
-static void keyboard_drag_enter(struct wlr_seat_keyboard_grab *grab,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- // nothing has keyboard focus during drags
-}
-
-static void keyboard_drag_key(struct wlr_seat_keyboard_grab *grab,
- uint32_t time, uint32_t key, uint32_t state) {
- // no keyboard input during drags
-}
-
-static void keyboard_drag_modifiers(struct wlr_seat_keyboard_grab *grab,
- struct wlr_keyboard_modifiers *modifiers) {
- //struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard;
- // TODO change the dnd action based on what modifier is pressed on the
- // keyboard
-}
-
-static void keyboard_drag_cancel(struct wlr_seat_keyboard_grab *grab) {
- struct wlr_drag *drag = grab->data;
- drag_end(drag);
-}
-
-static const struct wlr_keyboard_grab_interface
- data_device_keyboard_drag_interface = {
- .enter = keyboard_drag_enter,
- .key = keyboard_drag_key,
- .modifiers = keyboard_drag_modifiers,
- .cancel = keyboard_drag_cancel,
-};
-
-static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) {
- struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy);
- drag->icon = NULL;
-}
-
-static void drag_handle_drag_source_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag *drag = wl_container_of(listener, drag, source_destroy);
- drag_end(drag);
-}
-
-static void drag_icon_destroy(struct wlr_drag_icon *icon) {
- if (!icon) {
- return;
- }
- wlr_signal_emit_safe(&icon->events.destroy, icon);
- wlr_surface_set_role_committed(icon->surface, NULL, NULL);
- wl_list_remove(&icon->surface_destroy.link);
- wl_list_remove(&icon->seat_client_destroy.link);
- wl_list_remove(&icon->link);
- free(icon);
-}
-
-static void handle_drag_icon_surface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag_icon *icon =
- wl_container_of(listener, icon, surface_destroy);
- drag_icon_destroy(icon);
-}
-
-static void handle_drag_icon_surface_commit(struct wlr_surface *surface,
- void *role_data) {
- struct wlr_drag_icon *icon = role_data;
- icon->sx += icon->surface->current->sx;
- icon->sy += icon->surface->current->sy;
-}
-
-static void handle_drag_icon_seat_client_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag_icon *icon =
- wl_container_of(listener, icon, seat_client_destroy);
-
- drag_icon_destroy(icon);
-}
-
-static struct wlr_drag_icon *drag_icon_create(
- struct wlr_surface *icon_surface, struct wlr_seat_client *client,
- bool is_pointer, int32_t touch_id) {
- struct wlr_drag_icon *icon = calloc(1, sizeof(struct wlr_drag_icon));
- if (!icon) {
- return NULL;
- }
-
- icon->surface = icon_surface;
- icon->client = client;
- icon->is_pointer = is_pointer;
- icon->touch_id = touch_id;
- icon->mapped = true;
-
- wl_signal_init(&icon->events.map);
- wl_signal_init(&icon->events.destroy);
-
- wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy);
- icon->surface_destroy.notify = handle_drag_icon_surface_destroy;
-
- wlr_surface_set_role_committed(icon->surface,
- handle_drag_icon_surface_commit, icon);
-
- wl_signal_add(&client->events.destroy, &icon->seat_client_destroy);
- icon->seat_client_destroy.notify = handle_drag_icon_seat_client_destroy;
-
- wl_list_insert(&client->seat->drag_icons, &icon->link);
- wlr_signal_emit_safe(&client->seat->events.new_drag_icon, icon);
-
- return icon;
-}
-
-static void seat_handle_drag_source_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_seat *seat =
- wl_container_of(listener, seat, drag_source_destroy);
- wl_list_remove(&seat->drag_source_destroy.link);
- seat->drag_source = NULL;
-}
-
-static bool seat_client_start_drag(struct wlr_seat_client *client,
- struct wlr_data_source *source, struct wlr_surface *icon_surface,
- struct wlr_surface *origin, uint32_t serial) {
- struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));
- if (drag == NULL) {
- return false;
- }
-
- wl_signal_init(&drag->events.focus);
- wl_signal_init(&drag->events.motion);
- wl_signal_init(&drag->events.drop);
- wl_signal_init(&drag->events.destroy);
-
- struct wlr_seat *seat = client->seat;
- drag->seat = seat;
-
- drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
- seat->pointer_state.button_count == 1 &&
- seat->pointer_state.grab_serial == serial &&
- seat->pointer_state.focused_surface &&
- seat->pointer_state.focused_surface == origin;
-
- bool is_touch_grab = !wl_list_empty(&client->touches) &&
- wlr_seat_touch_num_points(seat) == 1 &&
- seat->touch_state.grab_serial == serial;
-
- // set in the iteration
- struct wlr_touch_point *point = NULL;
- if (is_touch_grab) {
- wl_list_for_each(point, &seat->touch_state.touch_points, link) {
- is_touch_grab = point->surface && point->surface == origin;
- break;
- }
- }
-
- if (!drag->is_pointer_grab && !is_touch_grab) {
- free(drag);
- return true;
- }
-
- if (icon_surface) {
- int32_t touch_id = (point ? point->touch_id : 0);
- struct wlr_drag_icon *icon =
- drag_icon_create(icon_surface, client, drag->is_pointer_grab,
- touch_id);
- if (!icon) {
- free(drag);
- return false;
- }
-
- drag->icon = icon;
- drag->icon_destroy.notify = drag_handle_icon_destroy;
- wl_signal_add(&icon->events.destroy, &drag->icon_destroy);
- }
-
- drag->source = source;
- if (source != NULL) {
- drag->source_destroy.notify = drag_handle_drag_source_destroy;
- wl_signal_add(&source->events.destroy, &drag->source_destroy);
- }
-
- drag->seat_client = client;
- drag->pointer_grab.data = drag;
- drag->pointer_grab.interface = &data_device_pointer_drag_interface;
-
- drag->touch_grab.data = drag;
- drag->touch_grab.interface = &data_device_touch_drag_interface;
- drag->grab_touch_id = seat->touch_state.grab_id;
-
- drag->keyboard_grab.data = drag;
- drag->keyboard_grab.interface = &data_device_keyboard_drag_interface;
-
- wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab);
-
- if (drag->is_pointer_grab) {
- wlr_seat_pointer_clear_focus(seat);
- wlr_seat_pointer_start_grab(seat, &drag->pointer_grab);
- } else {
- assert(point);
- wlr_seat_touch_start_grab(seat, &drag->touch_grab);
- drag_set_focus(drag, point->surface, point->sx, point->sy);
- }
-
- seat->drag = drag; // TODO: unset this thing somewhere
- seat->drag_serial = serial;
-
- seat->drag_source = source;
- if (source != NULL) {
- seat->drag_source_destroy.notify = seat_handle_drag_source_destroy;
- wl_signal_add(&source->events.destroy, &seat->drag_source_destroy);
- }
-
- wlr_signal_emit_safe(&seat->events.start_drag, drag);
-
- return true;
-}
-
-static void data_device_start_drag(struct wl_client *client,
- struct wl_resource *device_resource,
- struct wl_resource *source_resource,
- struct wl_resource *origin_resource, struct wl_resource *icon_resource,
- uint32_t serial) {
- struct wlr_seat_client *seat_client =
- seat_client_from_data_device_resource(device_resource);
- struct wlr_surface *origin = wlr_surface_from_resource(origin_resource);
- struct wlr_data_source *source = NULL;
- struct wlr_surface *icon = NULL;
-
- if (source_resource) {
- struct client_data_source *client_source =
- client_data_source_from_resource(source_resource);
- source = (struct wlr_data_source *)client_source;
- }
-
- if (icon_resource) {
- icon = wlr_surface_from_resource(icon_resource);
- }
- if (icon) {
- if (wlr_surface_set_role(icon, "wl_data_device-icon",
- icon_resource, WL_DATA_DEVICE_ERROR_ROLE) < 0) {
- return;
- }
- }
-
- if (!seat_client_start_drag(seat_client, source, icon, origin, serial)) {
- wl_resource_post_no_memory(device_resource);
- return;
- }
-
- if (source) {
- source->seat_client = seat_client;
- }
-}
-
-static const struct wl_data_device_interface data_device_impl = {
- .start_drag = data_device_start_drag,
- .set_selection = data_device_set_selection,
- .release = data_device_release,
-};
-
-static void data_device_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-
-struct client_data_source {
- struct wlr_data_source source;
- struct wlr_data_source_impl impl;
- struct wl_resource *resource;
-};
-
-static void client_data_source_accept(struct wlr_data_source *wlr_source,
- uint32_t serial, const char *mime_type);
-
-static struct client_data_source *client_data_source_from_wlr_data_source(
- struct wlr_data_source *wlr_source) {
- assert(wlr_source->impl->accept == client_data_source_accept);
- return (struct client_data_source *)wlr_source;
-}
-
-static void client_data_source_accept(struct wlr_data_source *wlr_source,
- uint32_t serial, const char *mime_type) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- wl_data_source_send_target(source->resource, mime_type);
-}
-
-static void client_data_source_send(struct wlr_data_source *wlr_source,
- const char *mime_type, int32_t fd) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- wl_data_source_send_send(source->resource, mime_type, fd);
- close(fd);
-}
-
-static void client_data_source_cancel(struct wlr_data_source *wlr_source) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- wl_data_source_send_cancelled(source->resource);
-}
-
-static void client_data_source_dnd_drop(struct wlr_data_source *wlr_source) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- assert(wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION);
- wl_data_source_send_dnd_drop_performed(source->resource);
-}
-
-static void client_data_source_dnd_finish(struct wlr_data_source *wlr_source) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- assert(wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION);
- wl_data_source_send_dnd_finished(source->resource);
-}
-
-static void client_data_source_dnd_action(struct wlr_data_source *wlr_source,
- enum wl_data_device_manager_dnd_action action) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- assert(wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION);
- wl_data_source_send_action(source->resource, action);
-}
-
-static void data_source_destroy(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static struct client_data_source *client_data_source_create(
- struct wl_resource *source_resource) {
- struct client_data_source *source =
- calloc(1, sizeof(struct client_data_source));
- if (source == NULL) {
- return NULL;
- }
-
- source->resource = source_resource;
-
- source->impl.accept = client_data_source_accept;
- source->impl.send = client_data_source_send;
- source->impl.cancel = client_data_source_cancel;
-
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
- source->impl.dnd_drop = client_data_source_dnd_drop;
- }
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
- source->impl.dnd_finish = client_data_source_dnd_finish;
- }
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
- source->impl.dnd_action = client_data_source_dnd_action;
- }
-
- wlr_data_source_init(&source->source, &source->impl);
- return source;
-}
-
-static void data_source_set_actions(struct wl_client *client,
- struct wl_resource *resource, uint32_t dnd_actions) {
- struct client_data_source *source =
- client_data_source_from_resource(resource);
-
- if (source->source.actions >= 0) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "cannot set actions more than once");
- return;
- }
-
- if (dnd_actions & ~ALL_ACTIONS) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "invalid action mask %x", dnd_actions);
- return;
- }
-
- if (source->source.seat_client) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "invalid action change after "
- "wl_data_device.start_drag");
- return;
- }
-
- source->source.actions = dnd_actions;
-}
-
-static void data_source_offer(struct wl_client *client,
- struct wl_resource *resource, const char *mime_type) {
- struct client_data_source *source =
- client_data_source_from_resource(resource);
-
- char **p = wl_array_add(&source->source.mime_types, sizeof(*p));
- if (p) {
- *p = strdup(mime_type);
- }
- if (!p || !*p) {
- if (p) {
- source->source.mime_types.size -= sizeof(*p);
- }
- wl_resource_post_no_memory(resource);
- }
-}
-
-static const struct wl_data_source_interface data_source_impl = {
- .offer = data_source_offer,
- .destroy = data_source_destroy,
- .set_actions = data_source_set_actions,
-};
-
-static void data_source_resource_handle_destroy(struct wl_resource *resource) {
- struct client_data_source *source =
- client_data_source_from_resource(resource);
- wlr_data_source_finish(&source->source);
- free(source);
-}
-
-void wlr_data_source_init(struct wlr_data_source *source,
- const struct wlr_data_source_impl *impl) {
- assert(impl->send);
-
- source->impl = impl;
- wl_array_init(&source->mime_types);
- wl_signal_init(&source->events.destroy);
- source->actions = -1;
-}
-
-void wlr_data_source_finish(struct wlr_data_source *source) {
- if (source == NULL) {
- return;
- }
-
- wlr_signal_emit_safe(&source->events.destroy, source);
-
- char **p;
- wl_array_for_each(p, &source->mime_types) {
- free(*p);
- }
- wl_array_release(&source->mime_types);
-}
-
-void wlr_data_source_send(struct wlr_data_source *source, const char *mime_type,
- int32_t fd) {
- source->impl->send(source, mime_type, fd);
-}
-
-void wlr_data_source_accept(struct wlr_data_source *source, uint32_t serial,
- const char *mime_type) {
- source->accepted = (mime_type != NULL);
- if (source->impl->accept) {
- source->impl->accept(source, serial, mime_type);
- }
-}
-
-void wlr_data_source_cancel(struct wlr_data_source *source) {
- if (source->impl->cancel) {
- source->impl->cancel(source);
- }
-}
-
-void wlr_data_source_dnd_drop(struct wlr_data_source *source) {
- if (source->impl->dnd_drop) {
- source->impl->dnd_drop(source);
- }
-}
-
-void wlr_data_source_dnd_finish(struct wlr_data_source *source) {
- if (source->impl->dnd_finish) {
- source->impl->dnd_finish(source);
- }
-}
-
-void wlr_data_source_dnd_action(struct wlr_data_source *source,
- enum wl_data_device_manager_dnd_action action) {
- source->current_dnd_action = action;
- if (source->impl->dnd_action) {
- source->impl->dnd_action(source, action);
- }
-}
-
-
-void data_device_manager_get_data_device(struct wl_client *client,
- struct wl_resource *manager_resource, uint32_t id,
- struct wl_resource *seat_resource) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_data_device_interface, wl_resource_get_version(manager_resource),
- id);
- if (resource == NULL) {
- wl_resource_post_no_memory(manager_resource);
- return;
- }
- wl_resource_set_implementation(resource, &data_device_impl, seat_client,
- &data_device_destroy);
- wl_list_insert(&seat_client->data_devices, wl_resource_get_link(resource));
-}
-
-static void data_device_manager_create_data_source(struct wl_client *client,
- struct wl_resource *resource, uint32_t id) {
- struct wl_resource *source_resource = wl_resource_create(client,
- &wl_data_source_interface, wl_resource_get_version(resource), id);
- if (source_resource == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- struct client_data_source *source =
- client_data_source_create(source_resource);
- if (source == NULL) {
- wl_resource_destroy(source_resource);
- wl_resource_post_no_memory(resource);
- return;
- }
-
- wl_resource_set_implementation(source_resource, &data_source_impl,
- source, data_source_resource_handle_destroy);
-}
-
-static const struct wl_data_device_manager_interface
- data_device_manager_impl = {
- .create_data_source = data_device_manager_create_data_source,
- .get_data_device = data_device_manager_get_data_device,
-};
-
-static void data_device_manager_bind(struct wl_client *client,
- void *data, uint32_t version, uint32_t id) {
- struct wl_resource *resource = wl_resource_create(client,
- &wl_data_device_manager_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &data_device_manager_impl,
- NULL, NULL);
-}
-
-void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) {
- if (!manager) {
- return;
- }
- wl_list_remove(&manager->display_destroy.link);
- // TODO: free wl_resources
- wl_global_destroy(manager->global);
- free(manager);
-}
-
-static void handle_display_destroy(struct wl_listener *listener, void *data) {
- struct wlr_data_device_manager *manager =
- wl_container_of(listener, manager, display_destroy);
- wlr_data_device_manager_destroy(manager);
-}
-
-struct wlr_data_device_manager *wlr_data_device_manager_create(
- struct wl_display *display) {
- struct wlr_data_device_manager *manager =
- calloc(1, sizeof(struct wlr_data_device_manager));
- if (manager == NULL) {
- wlr_log(L_ERROR, "could not create data device manager");
- return NULL;
- }
-
- manager->global =
- wl_global_create(display, &wl_data_device_manager_interface,
- 3, NULL, data_device_manager_bind);
- if (!manager->global) {
- wlr_log(L_ERROR, "could not create data device manager wl global");
- free(manager);
- return NULL;
- }
-
- manager->display_destroy.notify = handle_display_destroy;
- wl_display_add_destroy_listener(display, &manager->display_destroy);
-
- return manager;
-}
diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c
index f190be24..9bcd473f 100644
--- a/types/wlr_linux_dmabuf.c
+++ b/types/wlr_linux_dmabuf.c
@@ -7,26 +7,29 @@
#include <wlr/types/wlr_linux_dmabuf.h>
#include <wlr/util/log.h>
#include "linux-dmabuf-unstable-v1-protocol.h"
+#include "util/signal.h"
-static void wl_buffer_destroy(struct wl_client *client,
+#define LINUX_DMABUF_VERSION 3
+
+static void buffer_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
-static const struct wl_buffer_interface wl_buffer_impl = {
- wl_buffer_destroy,
+static const struct wl_buffer_interface buffer_impl = {
+ .destroy = buffer_handle_destroy,
};
bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) {
if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
- &wl_buffer_impl)) {
+ &buffer_impl)) {
return false;
}
struct wlr_dmabuf_buffer *buffer =
wl_resource_get_user_data(buffer_resource);
if (buffer && buffer->buffer_resource && !buffer->params_resource &&
- buffer->buffer_resource == buffer_resource) {
+ buffer->buffer_resource == buffer_resource) {
return true;
}
@@ -36,7 +39,7 @@ bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) {
struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource(
struct wl_resource *buffer_resource) {
assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
- &wl_buffer_impl));
+ &buffer_impl));
struct wlr_dmabuf_buffer *buffer =
wl_resource_get_user_data(buffer_resource);
@@ -103,11 +106,9 @@ static void params_add(struct wl_client *client,
buffer->attributes.n_planes++;
}
-static void handle_buffer_destroy(struct wl_resource *buffer_resource)
-{
+static void buffer_handle_resource_destroy(struct wl_resource *buffer_resource) {
struct wlr_dmabuf_buffer *buffer =
wlr_dmabuf_buffer_from_buffer_resource(buffer_resource);
-
linux_dmabuf_buffer_destroy(buffer);
}
@@ -144,7 +145,7 @@ static void params_create_common(struct wl_client *client,
if ((buffer->attributes.fd[3] >= 0 || buffer->attributes.fd[2] >= 0) &&
(buffer->attributes.fd[2] == -1 || buffer->attributes.fd[1] == -1)) {
- wl_resource_post_error (params_resource,
+ wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"gap in dmabuf planes");
goto err_out;
@@ -229,7 +230,7 @@ static void params_create_common(struct wl_client *client,
}
wl_resource_set_implementation(buffer->buffer_resource,
- &wl_buffer_impl, buffer, handle_buffer_destroy);
+ &buffer_impl, buffer, buffer_handle_resource_destroy);
/* send 'created' event when the request is not for an immediate
* import, that is buffer_id is zero */
@@ -324,8 +325,7 @@ static void linux_dmabuf_create_params(struct wl_client *client,
buffer->renderer = linux_dmabuf->renderer;
buffer->params_resource = wl_resource_create(client,
- &zwp_linux_buffer_params_v1_interface,
- version, params_id);
+ &zwp_linux_buffer_params_v1_interface, version, params_id);
if (!buffer->params_resource) {
goto err_free;
}
@@ -400,6 +400,10 @@ static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf *linux_dmabuf,
free(formats);
}
+static void linux_dmabuf_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
static void linux_dmabuf_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct wlr_linux_dmabuf *linux_dmabuf = data;
@@ -410,21 +414,29 @@ static void linux_dmabuf_bind(struct wl_client *client, void *data,
wl_client_post_no_memory(client);
return;
}
-
wl_resource_set_implementation(resource, &linux_dmabuf_impl,
- linux_dmabuf, NULL);
- if (version < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
- return;
- }
+ linux_dmabuf, linux_dmabuf_resource_destroy);
+ wl_list_insert(&linux_dmabuf->wl_resources, wl_resource_get_link(resource));
- linux_dmabuf_send_modifiers(linux_dmabuf, resource);
+ if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
+ linux_dmabuf_send_modifiers(linux_dmabuf, resource);
+ }
}
void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) {
if (!linux_dmabuf) {
return;
}
+
+ wlr_signal_emit_safe(&linux_dmabuf->events.destroy, linux_dmabuf);
+
wl_list_remove(&linux_dmabuf->display_destroy.link);
+ wl_list_remove(&linux_dmabuf->renderer_destroy.link);
+
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &linux_dmabuf->wl_resources) {
+ wl_resource_destroy(resource);
+ }
wl_global_destroy(linux_dmabuf->wl_global);
free(linux_dmabuf);
@@ -436,6 +448,12 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
wlr_linux_dmabuf_destroy(linux_dmabuf);
}
+static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_linux_dmabuf *linux_dmabuf =
+ wl_container_of(listener, linux_dmabuf, renderer_destroy);
+ wlr_linux_dmabuf_destroy(linux_dmabuf);
+}
+
struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display,
struct wlr_renderer *renderer) {
struct wlr_linux_dmabuf *linux_dmabuf =
@@ -446,9 +464,12 @@ struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display,
}
linux_dmabuf->renderer = renderer;
+ wl_list_init(&linux_dmabuf->wl_resources);
+ wl_signal_init(&linux_dmabuf->events.destroy);
+
linux_dmabuf->wl_global =
wl_global_create(display, &zwp_linux_dmabuf_v1_interface,
- 3, linux_dmabuf, linux_dmabuf_bind);
+ LINUX_DMABUF_VERSION, linux_dmabuf, linux_dmabuf_bind);
if (!linux_dmabuf->wl_global) {
wlr_log(L_ERROR, "could not create linux dmabuf v1 wl global");
free(linux_dmabuf);
@@ -458,5 +479,8 @@ struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display,
linux_dmabuf->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &linux_dmabuf->display_destroy);
+ linux_dmabuf->renderer_destroy.notify = handle_renderer_destroy;
+ wl_signal_add(&renderer->events.destroy, &linux_dmabuf->renderer_destroy);
+
return linux_dmabuf;
}
diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c
index 6eb47ca8..2c896313 100644
--- a/types/wlr_matrix.c
+++ b/types/wlr_matrix.c
@@ -117,7 +117,7 @@ void wlr_matrix_transform(float mat[static 9],
wlr_matrix_multiply(mat, mat, transforms[transform]);
}
-// Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied
+// Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied
void wlr_matrix_projection(float mat[static 9], int width, int height,
enum wl_output_transform transform) {
memset(mat, 0, sizeof(*mat) * 9);
diff --git a/types/wlr_output.c b/types/wlr_output.c
index 36779d67..0973fbc7 100644
--- a/types/wlr_output.c
+++ b/types/wlr_output.c
@@ -7,15 +7,17 @@
#include <wayland-server.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/wlr_renderer.h>
-#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_box.h>
+#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include "util/signal.h"
-static void wl_output_send_to_resource(struct wl_resource *resource) {
+#define OUTPUT_VERSION 3
+
+static void output_send_to_resource(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource);
const uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_GEOMETRY_SINCE_VERSION) {
@@ -70,42 +72,33 @@ static void output_send_current_mode_to_resource(
}
}
-static void wl_output_destroy(struct wl_resource *resource) {
- struct wlr_output *output = wlr_output_from_resource(resource);
- struct wl_resource *_resource;
- wl_resource_for_each(_resource, &output->wl_resources) {
- if (_resource == resource) {
- struct wl_list *link = wl_resource_get_link(_resource);
- wl_list_remove(link);
- break;
- }
- }
+static void output_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
}
-static void wl_output_release(struct wl_client *client,
+static void output_handle_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
-static struct wl_output_interface wl_output_impl = {
- .release = wl_output_release,
+static const struct wl_output_interface output_impl = {
+ .release = output_handle_release,
};
static void wl_output_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
struct wlr_output *wlr_output = data;
- struct wl_resource *wl_resource = wl_resource_create(wl_client,
+ struct wl_resource *resource = wl_resource_create(wl_client,
&wl_output_interface, version, id);
- if (wl_resource == NULL) {
+ if (resource == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
- wl_resource_set_implementation(wl_resource, &wl_output_impl, wlr_output,
- wl_output_destroy);
- wl_list_insert(&wlr_output->wl_resources,
- wl_resource_get_link(wl_resource));
- wl_output_send_to_resource(wl_resource);
+ wl_resource_set_implementation(resource, &output_impl, wlr_output,
+ output_handle_resource_destroy);
+ wl_list_insert(&wlr_output->wl_resources, wl_resource_get_link(resource));
+ output_send_to_resource(resource);
}
void wlr_output_create_global(struct wlr_output *output) {
@@ -113,7 +106,7 @@ void wlr_output_create_global(struct wlr_output *output) {
return;
}
struct wl_global *wl_global = wl_global_create(output->display,
- &wl_output_interface, 3, output, wl_output_bind);
+ &wl_output_interface, OUTPUT_VERSION, output, wl_output_bind);
output->wl_global = wl_global;
}
@@ -205,7 +198,7 @@ void wlr_output_set_transform(struct wlr_output *output,
// TODO: only send geometry and done
struct wl_resource *resource;
wl_resource_for_each(resource, &output->wl_resources) {
- wl_output_send_to_resource(resource);
+ output_send_to_resource(resource);
}
wlr_signal_emit_safe(&output->events.transform, output);
@@ -223,7 +216,7 @@ void wlr_output_set_position(struct wlr_output *output, int32_t lx,
// TODO: only send geometry and done
struct wl_resource *resource;
wl_resource_for_each(resource, &output->wl_resources) {
- wl_output_send_to_resource(resource);
+ output_send_to_resource(resource);
}
}
@@ -237,7 +230,7 @@ void wlr_output_set_scale(struct wlr_output *output, float scale) {
// TODO: only send mode and done
struct wl_resource *resource;
wl_resource_for_each(resource, &output->wl_resources) {
- wl_output_send_to_resource(resource);
+ output_send_to_resource(resource);
}
wlr_signal_emit_safe(&output->events.scale, output);
@@ -652,7 +645,7 @@ void wlr_output_set_fullscreen_surface(struct wlr_output *output,
struct wlr_output *wlr_output_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &wl_output_interface,
- &wl_output_impl));
+ &output_impl));
return wl_resource_get_user_data(resource);
}
diff --git a/types/wlr_seat.c b/types/wlr_seat.c
deleted file mode 100644
index f77a492d..00000000
--- a/types/wlr_seat.c
+++ /dev/null
@@ -1,1271 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <wayland-server.h>
-#include <wlr/types/wlr_data_device.h>
-#include <wlr/types/wlr_input_device.h>
-#include <wlr/types/wlr_primary_selection.h>
-#include <wlr/types/wlr_seat.h>
-#include <wlr/util/log.h>
-#include "util/signal.h"
-
-static void resource_destroy(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static void pointer_send_frame(struct wl_resource *resource) {
- if (wl_resource_get_version(resource) >=
- WL_POINTER_FRAME_SINCE_VERSION) {
- wl_pointer_send_frame(resource);
- }
-}
-
-static const struct wl_pointer_interface wl_pointer_impl;
-
-static struct wlr_seat_client *seat_client_from_pointer_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_pointer_interface,
- &wl_pointer_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static void wl_pointer_set_cursor(struct wl_client *client,
- struct wl_resource *pointer_resource, uint32_t serial,
- struct wl_resource *surface_resource,
- int32_t hotspot_x, int32_t hotspot_y) {
- struct wlr_seat_client *seat_client =
- seat_client_from_pointer_resource(pointer_resource);
- struct wlr_surface *surface = NULL;
- if (surface_resource != NULL) {
- surface = wlr_surface_from_resource(surface_resource);
-
- if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource,
- WL_POINTER_ERROR_ROLE) < 0) {
- return;
- }
- }
-
- struct wlr_seat_pointer_request_set_cursor_event *event =
- calloc(1, sizeof(struct wlr_seat_pointer_request_set_cursor_event));
- if (event == NULL) {
- return;
- }
- event->seat_client = seat_client;
- event->surface = surface;
- event->serial = serial;
- event->hotspot_x = hotspot_x;
- event->hotspot_y = hotspot_y;
-
- wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, event);
-
- free(event);
-}
-
-static const struct wl_pointer_interface wl_pointer_impl = {
- .set_cursor = wl_pointer_set_cursor,
- .release = resource_destroy,
-};
-
-static void wl_pointer_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void wl_seat_get_pointer(struct wl_client *client,
- struct wl_resource *seat_resource, uint32_t id) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
- if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
- return;
- }
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_pointer_interface, wl_resource_get_version(seat_resource), id);
- if (resource == NULL) {
- wl_resource_post_no_memory(seat_resource);
- return;
- }
- wl_resource_set_implementation(resource, &wl_pointer_impl, seat_client,
- &wl_pointer_destroy);
- wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource));
-}
-
-static const struct wl_keyboard_interface wl_keyboard_impl = {
- .release = resource_destroy,
-};
-
-static void wl_keyboard_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void seat_client_send_keymap(struct wlr_seat_client *client,
- struct wlr_keyboard *keyboard) {
- if (!keyboard) {
- return;
- }
-
- // TODO: We should probably lift all of the keys set by the other
- // keyboard
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- wl_keyboard_send_keymap(resource,
- WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd,
- keyboard->keymap_size);
- }
-}
-
-static void seat_client_send_repeat_info(struct wlr_seat_client *client,
- struct wlr_keyboard *keyboard) {
- if (!keyboard) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- if (wl_resource_get_version(resource) >=
- WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
- wl_keyboard_send_repeat_info(resource,
- keyboard->repeat_info.rate, keyboard->repeat_info.delay);
- }
- }
-}
-
-static void wl_seat_get_keyboard(struct wl_client *client,
- struct wl_resource *seat_resource, uint32_t id) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
- if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
- return;
- }
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_keyboard_interface, wl_resource_get_version(seat_resource), id);
- if (resource == NULL) {
- wl_resource_post_no_memory(seat_resource);
- return;
- }
- wl_resource_set_implementation(resource, &wl_keyboard_impl, seat_client,
- &wl_keyboard_destroy);
- wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource));
-
- struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard;
- seat_client_send_keymap(seat_client, keyboard);
- seat_client_send_repeat_info(seat_client, keyboard);
-
- // TODO possibly handle the case where this keyboard needs an enter
- // right away
-}
-
-static const struct wl_touch_interface wl_touch_impl = {
- .release = resource_destroy,
-};
-
-static void wl_touch_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void wl_seat_get_touch(struct wl_client *client,
- struct wl_resource *seat_resource, uint32_t id) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
- if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
- return;
- }
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_touch_interface, wl_resource_get_version(seat_resource), id);
- if (resource == NULL) {
- wl_resource_post_no_memory(seat_resource);
- return;
- }
- wl_resource_set_implementation(resource, &wl_touch_impl, seat_client,
- &wl_touch_destroy);
- wl_list_insert(&seat_client->touches, wl_resource_get_link(resource));
-}
-
-static void seat_client_resource_destroy(struct wl_resource *seat_resource) {
- struct wlr_seat_client *client =
- wlr_seat_client_from_resource(seat_resource);
- wlr_signal_emit_safe(&client->events.destroy, client);
-
- if (client == client->seat->pointer_state.focused_client) {
- client->seat->pointer_state.focused_client = NULL;
- }
- if (client == client->seat->keyboard_state.focused_client) {
- client->seat->keyboard_state.focused_client = NULL;
- }
-
- struct wl_resource *resource, *tmp;
- wl_resource_for_each_safe(resource, tmp, &client->pointers) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->touches) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->data_devices) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->primary_selection_devices) {
- wl_resource_destroy(resource);
- }
-
- wl_list_remove(&client->link);
- free(client);
-}
-
-struct wl_seat_interface wl_seat_impl = {
- .get_pointer = wl_seat_get_pointer,
- .get_keyboard = wl_seat_get_keyboard,
- .get_touch = wl_seat_get_touch,
- .release = resource_destroy,
-};
-
-static void wl_seat_bind(struct wl_client *client, void *_wlr_seat,
- uint32_t version, uint32_t id) {
- struct wlr_seat *wlr_seat = _wlr_seat;
- assert(client && wlr_seat);
-
- struct wlr_seat_client *seat_client =
- calloc(1, sizeof(struct wlr_seat_client));
- if (seat_client == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
- seat_client->wl_resource =
- wl_resource_create(client, &wl_seat_interface, version, id);
- if (seat_client->wl_resource == NULL) {
- free(seat_client);
- wl_client_post_no_memory(client);
- return;
- }
- seat_client->client = client;
- seat_client->seat = wlr_seat;
- wl_list_init(&seat_client->pointers);
- wl_list_init(&seat_client->keyboards);
- wl_list_init(&seat_client->touches);
- wl_list_init(&seat_client->data_devices);
- wl_list_init(&seat_client->primary_selection_devices);
- wl_resource_set_implementation(seat_client->wl_resource, &wl_seat_impl,
- seat_client, seat_client_resource_destroy);
- wl_list_insert(&wlr_seat->clients, &seat_client->link);
- if (version >= WL_SEAT_NAME_SINCE_VERSION) {
- wl_seat_send_name(seat_client->wl_resource, wlr_seat->name);
- }
- wl_seat_send_capabilities(seat_client->wl_resource, wlr_seat->capabilities);
- wl_signal_init(&seat_client->events.destroy);
-}
-
-static void default_pointer_enter(struct wlr_seat_pointer_grab *grab,
- struct wlr_surface *surface, double sx, double sy) {
- wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
-}
-
-static void default_pointer_motion(struct wlr_seat_pointer_grab *grab,
- uint32_t time, double sx, double sy) {
- wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
-}
-
-static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab,
- uint32_t time, uint32_t button, uint32_t state) {
- return wlr_seat_pointer_send_button(grab->seat, time, button, state);
-}
-
-static void default_pointer_axis(struct wlr_seat_pointer_grab *grab,
- uint32_t time, enum wlr_axis_orientation orientation, double value) {
- wlr_seat_pointer_send_axis(grab->seat, time, orientation, value);
-}
-
-static void default_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
- // cannot be cancelled
-}
-
-static const struct wlr_pointer_grab_interface default_pointer_grab_impl = {
- .enter = default_pointer_enter,
- .motion = default_pointer_motion,
- .button = default_pointer_button,
- .axis = default_pointer_axis,
- .cancel = default_pointer_cancel,
-};
-
-static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
-}
-
-static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab,
- uint32_t time, uint32_t key, uint32_t state) {
- wlr_seat_keyboard_send_key(grab->seat, time, key, state);
-}
-
-static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
- struct wlr_keyboard_modifiers *modifiers) {
- wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
-}
-
-static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
- // cannot be cancelled
-}
-
-static const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = {
- .enter = default_keyboard_enter,
- .key = default_keyboard_key,
- .modifiers = default_keyboard_modifiers,
- .cancel = default_keyboard_cancel,
-};
-
-static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- return wlr_seat_touch_send_down(grab->seat, point->surface, time,
- point->touch_id, point->sx, point->sy);
-}
-
-static void default_touch_up(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
-}
-
-static void default_touch_motion(struct wlr_seat_touch_grab *grab,
- uint32_t time, struct wlr_touch_point *point) {
- if (!point->focus_surface || point->focus_surface == point->surface) {
- wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx,
- point->sy);
- }
-}
-
-static void default_touch_enter(struct wlr_seat_touch_grab *grab,
- uint32_t time, struct wlr_touch_point *point) {
- // not handled by default
-}
-
-static void default_touch_cancel(struct wlr_seat_touch_grab *grab) {
- // cannot be cancelled
-}
-
-static const struct wlr_touch_grab_interface default_touch_grab_impl = {
- .down = default_touch_down,
- .up = default_touch_up,
- .motion = default_touch_motion,
- .enter = default_touch_enter,
- .cancel = default_touch_cancel,
-};
-
-
-void wlr_seat_destroy(struct wlr_seat *seat) {
- if (!seat) {
- return;
- }
-
- wlr_signal_emit_safe(&seat->events.destroy, seat);
-
- wl_list_remove(&seat->display_destroy.link);
-
- if (seat->selection_source) {
- wl_list_remove(&seat->selection_source_destroy.link);
- wlr_data_source_cancel(seat->selection_source);
- seat->selection_source = NULL;
- }
- if (seat->primary_selection_source) {
- seat->primary_selection_source->cancel(seat->primary_selection_source);
- seat->primary_selection_source = NULL;
- wl_list_remove(&seat->primary_selection_source_destroy.link);
- }
-
- struct wlr_seat_client *client, *tmp;
- wl_list_for_each_safe(client, tmp, &seat->clients, link) {
- // will destroy other resources as well
- wl_resource_destroy(client->wl_resource);
- }
-
- wl_global_destroy(seat->wl_global);
- free(seat->pointer_state.default_grab);
- free(seat->keyboard_state.default_grab);
- free(seat->touch_state.default_grab);
- free(seat->name);
- free(seat);
-}
-
-static void handle_display_destroy(struct wl_listener *listener, void *data) {
- struct wlr_seat *seat =
- wl_container_of(listener, seat, display_destroy);
- wlr_seat_destroy(seat);
-}
-
-struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
- struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat));
- if (!wlr_seat) {
- return NULL;
- }
-
- // pointer state
- wlr_seat->pointer_state.seat = wlr_seat;
- wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
- wl_list_init(&wlr_seat->pointer_state.resource_destroy.link);
-
- struct wlr_seat_pointer_grab *pointer_grab =
- calloc(1, sizeof(struct wlr_seat_pointer_grab));
- if (!pointer_grab) {
- free(wlr_seat);
- return NULL;
- }
- pointer_grab->interface = &default_pointer_grab_impl;
- pointer_grab->seat = wlr_seat;
- wlr_seat->pointer_state.default_grab = pointer_grab;
- wlr_seat->pointer_state.grab = pointer_grab;
-
- // keyboard state
- struct wlr_seat_keyboard_grab *keyboard_grab =
- calloc(1, sizeof(struct wlr_seat_keyboard_grab));
- if (!keyboard_grab) {
- free(pointer_grab);
- free(wlr_seat);
- return NULL;
- }
- keyboard_grab->interface = &default_keyboard_grab_impl;
- keyboard_grab->seat = wlr_seat;
- wlr_seat->keyboard_state.default_grab = keyboard_grab;
- wlr_seat->keyboard_state.grab = keyboard_grab;
-
- wlr_seat->keyboard_state.seat = wlr_seat;
- wl_list_init(&wlr_seat->keyboard_state.resource_destroy.link);
- wl_list_init(
- &wlr_seat->keyboard_state.surface_destroy.link);
-
- // touch state
- struct wlr_seat_touch_grab *touch_grab =
- calloc(1, sizeof(struct wlr_seat_touch_grab));
- if (!touch_grab) {
- free(pointer_grab);
- free(keyboard_grab);
- free(wlr_seat);
- return NULL;
- }
- touch_grab->interface = &default_touch_grab_impl;
- touch_grab->seat = wlr_seat;
- wlr_seat->touch_state.default_grab = touch_grab;
- wlr_seat->touch_state.grab = touch_grab;
-
- wlr_seat->touch_state.seat = wlr_seat;
- wl_list_init(&wlr_seat->touch_state.touch_points);
-
- struct wl_global *wl_global = wl_global_create(display,
- &wl_seat_interface, 6, wlr_seat, wl_seat_bind);
- if (!wl_global) {
- free(wlr_seat);
- return NULL;
- }
- wlr_seat->wl_global = wl_global;
- wlr_seat->display = display;
- wlr_seat->name = strdup(name);
- wl_list_init(&wlr_seat->clients);
- wl_list_init(&wlr_seat->drag_icons);
-
- wl_signal_init(&wlr_seat->events.start_drag);
- wl_signal_init(&wlr_seat->events.new_drag_icon);
-
- wl_signal_init(&wlr_seat->events.request_set_cursor);
-
- wl_signal_init(&wlr_seat->events.selection);
- wl_signal_init(&wlr_seat->events.primary_selection);
-
- wl_signal_init(&wlr_seat->events.pointer_grab_begin);
- wl_signal_init(&wlr_seat->events.pointer_grab_end);
-
- wl_signal_init(&wlr_seat->events.keyboard_grab_begin);
- wl_signal_init(&wlr_seat->events.keyboard_grab_end);
-
- wl_signal_init(&wlr_seat->events.touch_grab_begin);
- wl_signal_init(&wlr_seat->events.touch_grab_end);
-
- wl_signal_init(&wlr_seat->events.destroy);
-
- wlr_seat->display_destroy.notify = handle_display_destroy;
- wl_display_add_destroy_listener(display, &wlr_seat->display_destroy);
-
- return wlr_seat;
-}
-
-struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat,
- struct wl_client *wl_client) {
- assert(wlr_seat);
- struct wlr_seat_client *seat_client;
- wl_list_for_each(seat_client, &wlr_seat->clients, link) {
- if (seat_client->client == wl_client) {
- return seat_client;
- }
- }
- return NULL;
-}
-
-void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
- uint32_t capabilities) {
- wlr_seat->capabilities = capabilities;
- struct wlr_seat_client *client;
- wl_list_for_each(client, &wlr_seat->clients, link) {
- wl_seat_send_capabilities(client->wl_resource, capabilities);
- }
-}
-
-void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) {
- free(wlr_seat->name);
- wlr_seat->name = strdup(name);
- struct wlr_seat_client *client;
- wl_list_for_each(client, &wlr_seat->clients, link) {
- wl_seat_send_name(client->wl_resource, name);
- }
-}
-
-bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat,
- struct wlr_surface *surface) {
- return surface == wlr_seat->pointer_state.focused_surface;
-}
-
-static void pointer_surface_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_pointer_state *state = wl_container_of(
- listener, state, surface_destroy);
- wl_list_remove(&state->surface_destroy.link);
- wl_list_init(&state->surface_destroy.link);
- wlr_seat_pointer_clear_focus(state->seat);
-}
-
-static void pointer_resource_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_pointer_state *state = wl_container_of(
- listener, state, resource_destroy);
- wl_list_remove(&state->resource_destroy.link);
- wl_list_init(&state->resource_destroy.link);
- wlr_seat_pointer_clear_focus(state->seat);
-}
-
-void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
- struct wlr_surface *surface, double sx, double sy) {
- assert(wlr_seat);
-
- if (wlr_seat->pointer_state.focused_surface == surface) {
- // this surface already got an enter notify
- return;
- }
-
- struct wlr_seat_client *client = NULL;
- if (surface) {
- struct wl_client *wl_client = wl_resource_get_client(surface->resource);
- client = wlr_seat_client_for_wl_client(wlr_seat, wl_client);
- }
-
- struct wlr_seat_client *focused_client =
- wlr_seat->pointer_state.focused_client;
- struct wlr_surface *focused_surface =
- wlr_seat->pointer_state.focused_surface;
-
- // leave the previously entered surface
- if (focused_client != NULL && focused_surface != NULL) {
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &focused_client->pointers) {
- wl_pointer_send_leave(resource, serial, focused_surface->resource);
- pointer_send_frame(resource);
- }
- }
-
- // enter the current surface
- if (client != NULL && surface != NULL) {
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- wl_pointer_send_enter(resource, serial, surface->resource,
- wl_fixed_from_double(sx), wl_fixed_from_double(sy));
- pointer_send_frame(resource);
- }
- }
-
- // reinitialize the focus destroy events
- wl_list_remove(&wlr_seat->pointer_state.surface_destroy.link);
- wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
- wl_list_remove(&wlr_seat->pointer_state.resource_destroy.link);
- wl_list_init(&wlr_seat->pointer_state.resource_destroy.link);
- if (surface != NULL) {
- wl_signal_add(&surface->events.destroy,
- &wlr_seat->pointer_state.surface_destroy);
- wl_resource_add_destroy_listener(surface->resource,
- &wlr_seat->pointer_state.resource_destroy);
- wlr_seat->pointer_state.resource_destroy.notify =
- pointer_resource_destroy_notify;
- wlr_seat->pointer_state.surface_destroy.notify =
- pointer_surface_destroy_notify;
- }
-
- wlr_seat->pointer_state.focused_client = client;
- wlr_seat->pointer_state.focused_surface = surface;
-
- // TODO: send focus change event
-}
-
-void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) {
- wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0);
-}
-
-void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
- double sx, double sy) {
- struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
- if (client == NULL) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx),
- wl_fixed_from_double(sy));
- pointer_send_frame(resource);
- }
-}
-
-uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
- uint32_t button, uint32_t state) {
- struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
- if (client == NULL) {
- return 0;
- }
-
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- wl_pointer_send_button(resource, serial, time, button, state);
- pointer_send_frame(resource);
- }
- return serial;
-}
-
-void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
- enum wlr_axis_orientation orientation, double value) {
- struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
- if (client == NULL) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- if (value) {
- wl_pointer_send_axis(resource, time, orientation,
- wl_fixed_from_double(value));
- } else if (wl_resource_get_version(resource) >=
- WL_POINTER_AXIS_STOP_SINCE_VERSION) {
- wl_pointer_send_axis_stop(resource, time, orientation);
- }
- pointer_send_frame(resource);
- }
-}
-
-void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
- struct wlr_seat_pointer_grab *grab) {
- assert(wlr_seat);
- grab->seat = wlr_seat;
- assert(grab->seat);
- wlr_seat->pointer_state.grab = grab;
-
- wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab);
-}
-
-void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) {
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- if (grab != wlr_seat->pointer_state.default_grab) {
- wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab;
- wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_end, grab);
- if (grab->interface->cancel) {
- grab->interface->cancel(grab);
- }
- }
-}
-
-void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat,
- struct wlr_surface *surface, double sx, double sy) {
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- grab->interface->enter(grab, surface, sx, sy);
-}
-
-void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time,
- double sx, double sy) {
- clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- grab->interface->motion(grab, time, sx, sy);
-}
-
-uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat,
- uint32_t time, uint32_t button, uint32_t state) {
- clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- if (wlr_seat->pointer_state.button_count == 0) {
- wlr_seat->pointer_state.grab_button = button;
- wlr_seat->pointer_state.grab_time = time;
- }
- wlr_seat->pointer_state.button_count++;
- } else {
- wlr_seat->pointer_state.button_count--;
- }
-
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- uint32_t serial = grab->interface->button(grab, time, button, state);
-
- if (serial && wlr_seat->pointer_state.button_count == 1) {
- wlr_seat->pointer_state.grab_serial = serial;
- }
-
- return serial;
-}
-
-void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,
- enum wlr_axis_orientation orientation, double value) {
- clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- grab->interface->axis(grab, time, orientation, value);
-}
-
-bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) {
- return seat->pointer_state.grab->interface != &default_pointer_grab_impl;
-}
-
-void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time,
- uint32_t key, uint32_t state) {
- struct wlr_seat_client *client = wlr_seat->keyboard_state.focused_client;
- if (!client) {
- return;
- }
-
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- wl_keyboard_send_key(resource, serial, time, key, state);
- }
-}
-
-static void handle_keyboard_keymap(struct wl_listener *listener, void *data) {
- struct wlr_seat_keyboard_state *state =
- wl_container_of(listener, state, keyboard_keymap);
- struct wlr_seat_client *client;
- struct wlr_keyboard *keyboard = data;
- if (keyboard == state->keyboard) {
- wl_list_for_each(client, &state->seat->clients, link) {
- seat_client_send_keymap(client, state->keyboard);
- }
- }
-}
-
-static void handle_keyboard_repeat_info(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_keyboard_state *state =
- wl_container_of(listener, state, keyboard_repeat_info);
- struct wlr_seat_client *client;
- wl_list_for_each(client, &state->seat->clients, link) {
- seat_client_send_repeat_info(client, state->keyboard);
- }
-}
-
-static void handle_keyboard_destroy(struct wl_listener *listener, void *data) {
- struct wlr_seat_keyboard_state *state =
- wl_container_of(listener, state, keyboard_destroy);
- state->keyboard = NULL;
-}
-
-void wlr_seat_set_keyboard(struct wlr_seat *seat,
- struct wlr_input_device *device) {
- // TODO call this on device key event before the event reaches the
- // compositor and set a pending keyboard and then send the new keyboard
- // state on the next keyboard notify event.
- struct wlr_keyboard *keyboard = (device ? device->keyboard : NULL);
- if (seat->keyboard_state.keyboard == keyboard) {
- return;
- }
-
- if (seat->keyboard_state.keyboard) {
- wl_list_remove(&seat->keyboard_state.keyboard_destroy.link);
- wl_list_remove(&seat->keyboard_state.keyboard_keymap.link);
- wl_list_remove(&seat->keyboard_state.keyboard_repeat_info.link);
- seat->keyboard_state.keyboard = NULL;
- }
-
- if (keyboard) {
- assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
- seat->keyboard_state.keyboard = keyboard;
-
- wl_signal_add(&device->events.destroy,
- &seat->keyboard_state.keyboard_destroy);
- seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy;
- wl_signal_add(&device->keyboard->events.keymap,
- &seat->keyboard_state.keyboard_keymap);
- seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap;
- wl_signal_add(&device->keyboard->events.repeat_info,
- &seat->keyboard_state.keyboard_repeat_info);
- seat->keyboard_state.keyboard_repeat_info.notify =
- handle_keyboard_repeat_info;
-
- struct wlr_seat_client *client;
- wl_list_for_each(client, &seat->clients, link) {
- seat_client_send_keymap(client, keyboard);
- seat_client_send_repeat_info(client, keyboard);
- }
-
- wlr_seat_keyboard_send_modifiers(seat, &keyboard->modifiers);
- } else {
- seat->keyboard_state.keyboard = NULL;
- }
-}
-
-struct wlr_keyboard *wlr_seat_get_keyboard(struct wlr_seat *seat) {
- return seat->keyboard_state.keyboard;
-}
-
-void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat,
- struct wlr_seat_keyboard_grab *grab) {
- grab->seat = wlr_seat;
- wlr_seat->keyboard_state.grab = grab;
-
- wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_begin, grab);
-}
-
-void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) {
- struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab;
-
- if (grab != wlr_seat->keyboard_state.default_grab) {
- wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab;
- wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_end, grab);
- if (grab->interface->cancel) {
- grab->interface->cancel(grab);
- }
- }
-}
-
-static void keyboard_surface_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_keyboard_state *state = wl_container_of(
- listener, state, surface_destroy);
- wl_list_remove(&state->surface_destroy.link);
- wl_list_init(&state->surface_destroy.link);
- wlr_seat_keyboard_clear_focus(state->seat);
-}
-
-static void keyboard_resource_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_keyboard_state *state = wl_container_of(
- listener, state, resource_destroy);
- wl_list_remove(&state->resource_destroy.link);
- wl_list_init(&state->resource_destroy.link);
- wlr_seat_keyboard_clear_focus(state->seat);
-}
-
-void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
- struct wlr_keyboard_modifiers *modifiers) {
- struct wlr_seat_client *client = seat->keyboard_state.focused_client;
- if (client == NULL) {
- return;
- }
-
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- if (modifiers == NULL) {
- wl_keyboard_send_modifiers(resource, serial, 0, 0, 0, 0);
- } else {
- wl_keyboard_send_modifiers(resource, serial,
- modifiers->depressed, modifiers->latched,
- modifiers->locked, modifiers->group);
- }
- }
-}
-
-void wlr_seat_keyboard_enter(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- if (seat->keyboard_state.focused_surface == surface) {
- // this surface already got an enter notify
- return;
- }
-
- struct wlr_seat_client *client = NULL;
-
- if (surface) {
- struct wl_client *wl_client = wl_resource_get_client(surface->resource);
- client = wlr_seat_client_for_wl_client(seat, wl_client);
- }
-
- struct wlr_seat_client *focused_client =
- seat->keyboard_state.focused_client;
- struct wlr_surface *focused_surface =
- seat->keyboard_state.focused_surface;
-
- // leave the previously entered surface
- if (focused_client != NULL && focused_surface != NULL) {
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &focused_client->keyboards) {
- wl_keyboard_send_leave(resource, serial, focused_surface->resource);
- }
- }
-
- // enter the current surface
- if (client != NULL) {
- struct wl_array keys;
- wl_array_init(&keys);
- for (size_t i = 0; i < num_keycodes; ++i) {
- uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
- if (!p) {
- wlr_log(L_ERROR, "Cannot allocate memory, skipping keycode: %d\n",
- keycodes[i]);
- continue;
- }
- *p = keycodes[i];
- }
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- wl_keyboard_send_enter(resource, serial, surface->resource, &keys);
- }
- wl_array_release(&keys);
-
- wlr_seat_client_send_selection(client);
- wlr_seat_client_send_primary_selection(client);
- }
-
- // reinitialize the focus destroy events
- wl_list_remove(&seat->keyboard_state.surface_destroy.link);
- wl_list_init(&seat->keyboard_state.surface_destroy.link);
- wl_list_remove(&seat->keyboard_state.resource_destroy.link);
- wl_list_init(&seat->keyboard_state.resource_destroy.link);
- if (surface) {
- wl_signal_add(&surface->events.destroy,
- &seat->keyboard_state.surface_destroy);
- wl_resource_add_destroy_listener(surface->resource,
- &seat->keyboard_state.resource_destroy);
- seat->keyboard_state.resource_destroy.notify =
- keyboard_resource_destroy_notify;
- seat->keyboard_state.surface_destroy.notify =
- keyboard_surface_destroy_notify;
- }
-
- seat->keyboard_state.focused_client = client;
- seat->keyboard_state.focused_surface = surface;
-
- if (client != NULL) {
- // tell new client about any modifier change last,
- // as it targets seat->keyboard_state.focused_client
- wlr_seat_keyboard_send_modifiers(seat, modifiers);
- }
-}
-
-void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
- grab->interface->enter(grab, surface, keycodes, num_keycodes, modifiers);
-}
-
-void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) {
- // TODO respect grabs here?
- wlr_seat_keyboard_enter(seat, NULL, NULL, 0, NULL);
-}
-
-bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat) {
- return seat->keyboard_state.grab->interface != &default_keyboard_grab_impl;
-}
-
-void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat,
- struct wlr_keyboard_modifiers *modifiers) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
- grab->interface->modifiers(grab, modifiers);
-}
-
-void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,
- uint32_t key, uint32_t state) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
- grab->interface->key(grab, time, key, state);
-}
-
-void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat,
- struct wlr_seat_touch_grab *grab) {
- grab->seat = wlr_seat;
- wlr_seat->touch_state.grab = grab;
-
- wlr_signal_emit_safe(&wlr_seat->events.touch_grab_begin, grab);
-}
-
-void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) {
- struct wlr_seat_touch_grab *grab = wlr_seat->touch_state.grab;
-
- if (grab != wlr_seat->touch_state.default_grab) {
- wlr_seat->touch_state.grab = wlr_seat->touch_state.default_grab;
- wlr_signal_emit_safe(&wlr_seat->events.touch_grab_end, grab);
- if (grab->interface->cancel) {
- grab->interface->cancel(grab);
- }
- }
-}
-
-static void touch_point_clear_focus(struct wlr_touch_point *point) {
- if (point->focus_surface) {
- wl_list_remove(&point->focus_surface_destroy.link);
- point->focus_client = NULL;
- point->focus_surface = NULL;
- }
-}
-
-static void touch_point_destroy(struct wlr_touch_point *point) {
- wlr_signal_emit_safe(&point->events.destroy, point);
-
- touch_point_clear_focus(point);
- wl_list_remove(&point->surface_destroy.link);
- wl_list_remove(&point->resource_destroy.link);
- wl_list_remove(&point->link);
- free(point);
-}
-static void handle_touch_point_resource_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_touch_point *point =
- wl_container_of(listener, point, resource_destroy);
- touch_point_destroy(point);
-}
-
-static void handle_touch_point_surface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_touch_point *point =
- wl_container_of(listener, point, surface_destroy);
- touch_point_destroy(point);
-}
-
-static struct wlr_touch_point *touch_point_create(
- struct wlr_seat *seat, int32_t touch_id,
- struct wlr_surface *surface, double sx, double sy) {
- struct wl_client *wl_client = wl_resource_get_client(surface->resource);
- struct wlr_seat_client *client = wlr_seat_client_for_wl_client(seat, wl_client);
-
- if (client == NULL || wl_list_empty(&client->touches)) {
- // touch points are not valid without a connected client with touch
- return NULL;
- }
-
- struct wlr_touch_point *point = calloc(1, sizeof(struct wlr_touch_point));
- if (!point) {
- return NULL;
- }
-
- point->touch_id = touch_id;
- point->surface = surface;
- point->client = client;
-
- point->sx = sx;
- point->sy = sy;
-
- wl_signal_init(&point->events.destroy);
-
- wl_signal_add(&surface->events.destroy, &point->surface_destroy);
- point->surface_destroy.notify = handle_touch_point_surface_destroy;
- wl_resource_add_destroy_listener(surface->resource,
- &point->resource_destroy);
- point->resource_destroy.notify = handle_touch_point_resource_destroy;
-
- wl_list_insert(&seat->touch_state.touch_points, &point->link);
-
- return point;
-}
-
-struct wlr_touch_point *wlr_seat_touch_get_point(
- struct wlr_seat *seat, int32_t touch_id) {
- struct wlr_touch_point *point = NULL;
- wl_list_for_each(point, &seat->touch_state.touch_points, link) {
- if (point->touch_id == touch_id) {
- return point;
- }
- }
-
- return NULL;
-}
-
-uint32_t wlr_seat_touch_notify_down(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
- double sy) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- struct wlr_touch_point *point =
- touch_point_create(seat, touch_id, surface, sx, sy);
- if (!point) {
- wlr_log(L_ERROR, "could not create touch point");
- return 0;
- }
-
- uint32_t serial = grab->interface->down(grab, time, point);
-
- if (serial && wlr_seat_touch_num_points(seat) == 1) {
- seat->touch_state.grab_serial = serial;
- seat->touch_state.grab_id = touch_id;
- }
-
- return serial;
-}
-
-void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time,
- int32_t touch_id) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch up for unknown touch point");
- return;
- }
-
- grab->interface->up(grab, time, point);
-
- touch_point_destroy(point);
-}
-
-void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time,
- int32_t touch_id, double sx, double sy) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch motion for unknown touch point");
- return;
- }
-
- point->sx = sx;
- point->sy = sy;
-
- grab->interface->motion(grab, time, point);
-}
-
-static void handle_point_focus_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_touch_point *point =
- wl_container_of(listener, point, focus_surface_destroy);
- touch_point_clear_focus(point);
-}
-
-static void touch_point_set_focus(struct wlr_touch_point *point,
- struct wlr_surface *surface, double sx, double sy) {
- if (point->focus_surface == surface) {
- return;
- }
-
- touch_point_clear_focus(point);
-
- if (surface && surface->resource) {
- struct wlr_seat_client *client =
- wlr_seat_client_for_wl_client(point->client->seat,
- wl_resource_get_client(surface->resource));
-
- if (client && !wl_list_empty(&client->touches)) {
- wl_signal_add(&surface->events.destroy, &point->focus_surface_destroy);
- point->focus_surface_destroy.notify = handle_point_focus_destroy;
- point->focus_surface = surface;
- point->focus_client = client;
- point->sx = sx;
- point->sy = sy;
- }
- }
-}
-
-void wlr_seat_touch_point_focus(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
- double sy) {
- assert(surface);
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch point focus for unknown touch point");
- return;
- }
- struct wlr_surface *focus = point->focus_surface;
- touch_point_set_focus(point, surface, sx, sy);
-
- if (focus != point->focus_surface) {
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- grab->interface->enter(grab, time, point);
- }
-}
-
-void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time,
- int32_t touch_id) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch point focus for unknown touch point");
- return;
- }
-
- touch_point_clear_focus(point);
-}
-
-uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
- double sy) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch down for unknown touch point");
- return 0;
- }
-
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &point->client->touches) {
- wl_touch_send_down(resource, serial, time, surface->resource,
- touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy));
- wl_touch_send_frame(resource);
- }
-
- return serial;
-}
-
-void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_id) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch up for unknown touch point");
- return;
- }
-
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &point->client->touches) {
- wl_touch_send_up(resource, serial, time, touch_id);
- wl_touch_send_frame(resource);
- }
-}
-
-void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id,
- double sx, double sy) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch motion for unknown touch point");
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &point->client->touches) {
- wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx),
- wl_fixed_from_double(sy));
- wl_touch_send_frame(resource);
- }
-}
-
-int wlr_seat_touch_num_points(struct wlr_seat *seat) {
- return wl_list_length(&seat->touch_state.touch_points);
-}
-
-bool wlr_seat_touch_has_grab(struct wlr_seat *seat) {
- return seat->touch_state.grab->interface != &default_touch_grab_impl;
-}
-
-bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
- return true;
- //return serial == seat->pointer_state.grab_serial ||
- // serial == seat->touch_state.grab_serial;
-}
-
-struct wlr_seat_client *wlr_seat_client_from_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_seat_interface,
- &wl_seat_impl));
- return wl_resource_get_user_data(resource);
-}
diff --git a/types/wlr_surface.c b/types/wlr_surface.c
index 0cf8fec2..775f7adf 100644
--- a/types/wlr_surface.c
+++ b/types/wlr_surface.c
@@ -11,6 +11,10 @@
#include <wlr/util/region.h>
#include "util/signal.h"
+#define CALLBACK_VERSION 1
+#define SURFACE_VERSION 4
+#define SUBSURFACE_VERSION 1
+
static void surface_state_reset_buffer(struct wlr_surface_state *state) {
if (state->buffer) {
wl_list_remove(&state->buffer_destroy_listener.link);
@@ -18,29 +22,29 @@ static void surface_state_reset_buffer(struct wlr_surface_state *state) {
}
}
-static void buffer_destroy(struct wl_listener *listener, void *data) {
+static void surface_handle_buffer_destroy(struct wl_listener *listener,
+ void *data) {
struct wlr_surface_state *state =
wl_container_of(listener, state, buffer_destroy_listener);
-
- wl_list_remove(&state->buffer_destroy_listener.link);
- state->buffer = NULL;
+ surface_state_reset_buffer(state);
}
static void surface_state_release_buffer(struct wlr_surface_state *state) {
if (state->buffer) {
wl_resource_post_event(state->buffer, WL_BUFFER_RELEASE);
- wl_list_remove(&state->buffer_destroy_listener.link);
- state->buffer = NULL;
+ surface_state_reset_buffer(state);
}
}
static void surface_state_set_buffer(struct wlr_surface_state *state,
struct wl_resource *buffer) {
+ surface_state_reset_buffer(state);
+
state->buffer = buffer;
if (buffer) {
wl_resource_add_destroy_listener(buffer,
&state->buffer_destroy_listener);
- state->buffer_destroy_listener.notify = buffer_destroy;
+ state->buffer_destroy_listener.notify = surface_handle_buffer_destroy;
}
}
@@ -57,7 +61,6 @@ static void surface_attach(struct wl_client *client,
surface->pending->invalid |= WLR_SURFACE_INVALID_BUFFER;
surface->pending->sx = sx;
surface->pending->sy = sy;
- surface_state_reset_buffer(surface->pending);
surface_state_set_buffer(surface->pending, buffer);
}
@@ -80,7 +83,7 @@ static struct wlr_frame_callback *frame_callback_from_resource(
return wl_resource_get_user_data(resource);
}
-static void destroy_frame_callback(struct wl_resource *resource) {
+static void callback_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_frame_callback *cb = frame_callback_from_resource(resource);
wl_list_remove(&cb->link);
free(cb);
@@ -97,16 +100,15 @@ static void surface_frame(struct wl_client *client,
return;
}
- cb->resource = wl_resource_create(client, &wl_callback_interface, 1,
- callback);
+ cb->resource = wl_resource_create(client, &wl_callback_interface,
+ CALLBACK_VERSION, callback);
if (cb->resource == NULL) {
free(cb);
wl_resource_post_no_memory(resource);
return;
}
-
wl_resource_set_implementation(cb->resource, NULL, cb,
- destroy_frame_callback);
+ callback_handle_resource_destroy);
wl_list_insert(surface->pending->frame_callback_list.prev, &cb->link);
@@ -548,7 +550,7 @@ static void surface_damage_buffer(struct wl_client *client,
x, y, width, height);
}
-const struct wl_surface_interface surface_interface = {
+static const struct wl_surface_interface surface_interface = {
.destroy = surface_destroy,
.attach = surface_attach,
.damage = surface_damage,
@@ -584,7 +586,6 @@ static struct wlr_surface_state *surface_state_create() {
pixman_region32_init_rect(&state->input,
INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
-
return state;
}
@@ -604,6 +605,10 @@ static void surface_state_destroy(struct wlr_surface_state *state) {
}
static void subsurface_destroy(struct wlr_subsurface *subsurface) {
+ if (subsurface == NULL) {
+ return;
+ }
+
wlr_signal_emit_safe(&subsurface->events.destroy, subsurface);
wl_list_remove(&subsurface->surface_destroy.link);
@@ -615,8 +620,6 @@ static void subsurface_destroy(struct wlr_subsurface *subsurface) {
wl_list_remove(&subsurface->parent_destroy.link);
}
- wl_list_remove(wl_resource_get_link(subsurface->resource));
-
wl_resource_set_user_data(subsurface->resource, NULL);
if (subsurface->surface) {
subsurface->surface->role_data = NULL;
@@ -649,6 +652,8 @@ static void surface_handle_renderer_destroy(struct wl_listener *listener,
struct wlr_surface *wlr_surface_create(struct wl_client *client,
uint32_t version, uint32_t id, struct wlr_renderer *renderer,
struct wl_list *resource_list) {
+ assert(version <= SURFACE_VERSION);
+
struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
if (!surface) {
wl_client_post_no_memory(client);
@@ -726,10 +731,8 @@ static struct wlr_subsurface *subsurface_from_resource(
static void subsurface_resource_destroy(struct wl_resource *resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
-
- if (subsurface) {
- subsurface_destroy(subsurface);
- }
+ wl_list_remove(wl_resource_get_link(resource));
+ subsurface_destroy(subsurface);
}
static void subsurface_handle_destroy(struct wl_client *client,
@@ -737,13 +740,15 @@ static void subsurface_handle_destroy(struct wl_client *client,
wl_resource_destroy(resource);
}
-static void subsurface_set_position(struct wl_client *client,
+static void subsurface_handle_set_position(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
- struct wlr_surface *surface = subsurface->surface;
+ if (subsurface == NULL) {
+ return;
+ }
+ struct wlr_surface *surface = subsurface->surface;
surface->pending->invalid |= WLR_SURFACE_INVALID_SUBSURFACE_POSITION;
-
surface->pending->subsurface_position.x = x;
surface->pending->subsurface_position.y = y;
}
@@ -762,9 +767,12 @@ static struct wlr_subsurface *subsurface_find_sibling(
return NULL;
}
-static void subsurface_place_above(struct wl_client *client,
+static void subsurface_handle_place_above(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *sibling_resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
+ if (subsurface == NULL) {
+ return;
+ }
struct wlr_surface *sibling_surface =
wlr_surface_from_resource(sibling_resource);
@@ -786,9 +794,12 @@ static void subsurface_place_above(struct wl_client *client,
subsurface->reordered = true;
}
-static void subsurface_place_below(struct wl_client *client,
+static void subsurface_handle_place_below(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *sibling_resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
+ if (subsurface == NULL) {
+ return;
+ }
struct wlr_surface *sibling_surface =
wlr_surface_from_resource(sibling_resource);
@@ -810,20 +821,24 @@ static void subsurface_place_below(struct wl_client *client,
subsurface->reordered = true;
}
-static void subsurface_set_sync(struct wl_client *client,
+static void subsurface_handle_set_sync(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
-
- if (subsurface) {
- subsurface->synchronized = true;
+ if (subsurface == NULL) {
+ return;
}
+
+ subsurface->synchronized = true;
}
-static void subsurface_set_desync(struct wl_client *client,
+static void subsurface_handle_set_desync(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
+ if (subsurface == NULL) {
+ return;
+ }
- if (subsurface && subsurface->synchronized) {
+ if (subsurface->synchronized) {
subsurface->synchronized = false;
if (!subsurface_is_synchronized(subsurface)) {
@@ -835,11 +850,11 @@ static void subsurface_set_desync(struct wl_client *client,
static const struct wl_subsurface_interface subsurface_implementation = {
.destroy = subsurface_handle_destroy,
- .set_position = subsurface_set_position,
- .place_above = subsurface_place_above,
- .place_below = subsurface_place_below,
- .set_sync = subsurface_set_sync,
- .set_desync = subsurface_set_desync,
+ .set_position = subsurface_handle_set_position,
+ .place_above = subsurface_handle_place_above,
+ .place_below = subsurface_handle_place_below,
+ .set_sync = subsurface_handle_set_sync,
+ .set_desync = subsurface_handle_set_desync,
};
static void subsurface_handle_parent_destroy(struct wl_listener *listener,
@@ -862,6 +877,8 @@ static void subsurface_handle_surface_destroy(struct wl_listener *listener,
struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
struct wlr_surface *parent, uint32_t version, uint32_t id,
struct wl_list *resource_list) {
+ assert(version <= SUBSURFACE_VERSION);
+
struct wl_client *client = wl_resource_get_client(surface->resource);
struct wlr_subsurface *subsurface =