commit b3a5bda

shrub  ·  2026-01-31 21:34:22 +0000 UTC
parent d916cac
initial subsurface implementation
add basic wl_subsurface support with naive patrent child tracking,
subsurface positioning, parent clipping, synchronized subsurface
commits, stacking, and so on. TLDR, it gets firefox rendering, but it's
not very good and crashed often.
9 files changed,  +346, -21
+60, -9
  1@@ -219,11 +219,18 @@ repaint_view(struct target *target, struct compositor_view *view, pixman_region3
  2 {
  3 	pixman_region32_t view_region, view_damage, border_damage;
  4 	const struct swc_rectangle *geom = &view->base.geometry, *target_geom = &target->view->geometry;
  5+	bool has_parent = view->parent && view->parent != view;
  6+	pixman_region32_t parent_region;
  7 
  8 	if (!view->base.buffer)
  9 		return;
 10 
 11 	pixman_region32_init_rect(&view_region, geom->x, geom->y, geom->width, geom->height);
 12+	if (has_parent) {
 13+		const struct swc_rectangle *parent_geom = &view->parent->base.geometry;
 14+		pixman_region32_init_rect(&parent_region, parent_geom->x, parent_geom->y,
 15+					  parent_geom->width, parent_geom->height);
 16+	}
 17 	pixman_region32_init_with_extents(&view_damage, &view->extents);
 18 	pixman_region32_init(&border_damage);
 19 
 20@@ -231,9 +238,13 @@ repaint_view(struct target *target, struct compositor_view *view, pixman_region3
 21 	pixman_region32_subtract(&view_damage, &view_damage, &view->clip);
 22 	pixman_region32_subtract(&border_damage, &view_damage, &view_region);
 23 	pixman_region32_intersect(&view_damage, &view_damage, &view_region);
 24+	if (has_parent) {
 25+		pixman_region32_intersect(&view_damage, &view_damage, &parent_region);
 26+		pixman_region32_intersect(&border_damage, &border_damage, &parent_region);
 27+	}
 28 
 29 	if (pixman_region32_not_empty(&view_damage)) {
 30-		pixman_region32_translate(&view_damage, -geom->x, -geom->y);
 31+		pixman_region32_translate(&view_damage, -geom->x + view->buffer_offset_x, -geom->y + view->buffer_offset_y);
 32 		wld_copy_region(swc.drm->renderer, view->buffer, geom->x - target_geom->x, geom->y - target_geom->y, &view_damage);
 33 	}
 34 
 35@@ -272,6 +283,8 @@ repaint_view(struct target *target, struct compositor_view *view, pixman_region3
 36 	pixman_region32_fini(&in_rect);
 37 	pixman_region32_fini(&out_border);
 38 	pixman_region32_fini(&in_border);
 39+	if (has_parent)
 40+		pixman_region32_fini(&parent_region);
 41 
 42 }
 43 
 44@@ -731,8 +744,11 @@ static int
 45 attach(struct view *base, struct wld_buffer *buffer)
 46 {
 47 	struct compositor_view *view = (void *)base;
 48+	struct surface *surface = view->surface;
 49 	pixman_box32_t old_extents;
 50 	pixman_region32_t old, new, both;
 51+	uint32_t new_width = buffer ? buffer->width : 0;
 52+	uint32_t new_height = buffer ? buffer->height : 0;
 53 	int ret;
 54 
 55 	if ((ret = renderer_attach(view, buffer)) < 0)
 56@@ -742,7 +758,18 @@ attach(struct view *base, struct wld_buffer *buffer)
 57 	 * visible on. */
 58 	update(&view->base);
 59 
 60-	if (view_set_size_from_buffer(&view->base, buffer)) {
 61+	view->buffer_offset_x = 0;
 62+	view->buffer_offset_y = 0;
 63+	if (surface && surface->has_window_geometry && buffer) {
 64+		if (surface->window_width > 0 && surface->window_height > 0) {
 65+			new_width = (uint32_t)surface->window_width;
 66+			new_height = (uint32_t)surface->window_height;
 67+			view->buffer_offset_x = surface->window_x;
 68+			view->buffer_offset_y = surface->window_y;
 69+		}
 70+	}
 71+
 72+	if (view_set_size(&view->base, new_width, new_height)) {
 73 		/* The view was resized. */
 74 		old_extents = view->extents;
 75 		update_extents(view);
 76@@ -818,7 +845,8 @@ view_at(int32_t x, int32_t y)
 77 			continue;
 78 
 79 		if (pixman_region32_contains_point(&view->surface->state.input,
 80-		                                   x - geom->x, y - geom->y, NULL))
 81+		                                   x - geom->x + view->buffer_offset_x,
 82+		                                   y - geom->y + view->buffer_offset_y, NULL))
 83 		{
 84 			return view;
 85 		}
 86@@ -992,6 +1020,8 @@ compositor_create_view(struct surface *surface)
 87 	view->buffer = NULL;
 88 	view->window = NULL;
 89 	view->parent = NULL;
 90+	view->buffer_offset_x = 0;
 91+	view->buffer_offset_y = 0;
 92 	view->visible = false;
 93 	view->extents.x1 = 0;
 94 	view->extents.y1 = 0;
 95@@ -1137,13 +1167,28 @@ calculate_damage(void)
 96 			continue;
 97 
 98 		geom = &view->base.geometry;
 99+		bool has_parent = view->parent && view->parent != view;
100+		pixman_region32_t view_region;
101+		pixman_region32_t parent_region;
102+
103+		pixman_region32_init_rect(&view_region, geom->x, geom->y, geom->width, geom->height);
104+		if (has_parent) {
105+			const struct swc_rectangle *parent_geom = &view->parent->base.geometry;
106+			pixman_region32_init_rect(&parent_region, parent_geom->x, parent_geom->y,
107+			                          parent_geom->width, parent_geom->height);
108+		}
109 
110 		/* Clip the surface by the opaque region covering it. */
111 		pixman_region32_copy(&view->clip, &compositor.opaque);
112 
113 		/* Translate the opaque region to global coordinates. */
114 		pixman_region32_copy(&surface_opaque, &view->surface->state.opaque);
115-		pixman_region32_translate(&surface_opaque, geom->x, geom->y);
116+		pixman_region32_translate(&surface_opaque,
117+		                          geom->x - view->buffer_offset_x,
118+		                          geom->y - view->buffer_offset_y);
119+		pixman_region32_intersect(&surface_opaque, &surface_opaque, &view_region);
120+		if (has_parent)
121+			pixman_region32_intersect(&surface_opaque, &surface_opaque, &parent_region);
122 
123 		/* Add the surface's opaque region to the accumulated opaque region. */
124 		pixman_region32_union(&compositor.opaque, &compositor.opaque, &surface_opaque);
125@@ -1154,7 +1199,11 @@ calculate_damage(void)
126 			renderer_flush_view(view);
127 
128 			/* Translate surface damage to global coordinates. */
129-			pixman_region32_translate(surface_damage, geom->x, geom->y);
130+			pixman_region32_translate(surface_damage,
131+			                          geom->x - view->buffer_offset_x,
132+			                          geom->y - view->buffer_offset_y);
133+			if (has_parent)
134+				pixman_region32_intersect(surface_damage, surface_damage, &parent_region);
135 
136 			/* Add the surface damage to the compositor damage. */
137 			pixman_region32_union(&compositor.damage, &compositor.damage, surface_damage);
138@@ -1163,22 +1212,24 @@ calculate_damage(void)
139 
140 	                /* redraw entire thingy if either */
141 			if (view->border.damaged_border1 || view->border.damaged_border2) {
142-				pixman_region32_t border_region, view_region;
143+				pixman_region32_t border_region;
144 
145 				pixman_region32_init_with_extents(&border_region, &view->extents);
146-				pixman_region32_init_rect(&view_region, geom->x, geom->y, geom->width, geom->height);
147 
148 				pixman_region32_subtract(&border_region, &border_region, &view_region);
149 
150 				pixman_region32_union(&compositor.damage, &compositor.damage, &border_region);
151 
152 				pixman_region32_fini(&border_region);
153-				pixman_region32_fini(&view_region);
154 
155 				view->border.damaged_border1 = false;
156 				view->border.damaged_border2 = false;
157 			}
158-		}
159+
160+		pixman_region32_fini(&view_region);
161+		if (has_parent)
162+			pixman_region32_fini(&parent_region);
163+	}
164 
165 	pixman_region32_fini(&surface_opaque);
166 }
+2, -0
1@@ -55,6 +55,8 @@ struct compositor_view {
2 	struct wld_buffer *buffer;
3 	struct window *window;
4 	struct compositor_view *parent;
5+	int32_t buffer_offset_x;
6+	int32_t buffer_offset_y;
7 
8 	/* Whether or not the view is visible (mapped). */
9 	bool visible;
+12, -1
 1@@ -25,6 +25,7 @@
 2 #include "internal.h"
 3 #include "subcompositor.h"
 4 #include "subsurface.h"
 5+#include "surface.h"
 6 #include "util.h"
 7 
 8 static void
 9@@ -32,13 +33,23 @@ get_subsurface(struct wl_client *client, struct wl_resource *resource,
10                uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource)
11 {
12 	struct subsurface *subsurface;
13+	struct surface *surface = wl_resource_get_user_data(surface_resource);
14+	struct surface *parent = wl_resource_get_user_data(parent_resource);
15 
16-	subsurface = subsurface_new(client, wl_resource_get_version(resource), id);
17+	if (!surface || !parent || surface == parent)
18+		return;
19+
20+	if (surface->subsurface)
21+		return;
22+
23+	subsurface = subsurface_new(client, wl_resource_get_version(resource), id, surface, parent);
24 
25 	if (!subsurface) {
26 		wl_resource_post_no_memory(resource);
27 		return;
28 	}
29+
30+	surface->subsurface = subsurface;
31 }
32 
33 static const struct wl_subcompositor_interface subcompositor_impl = {
+184, -6
  1@@ -22,39 +22,144 @@
  2  */
  3 
  4 #include "subsurface.h"
  5+#include "compositor.h"
  6+#include "surface.h"
  7 #include "util.h"
  8+#include "view.h"
  9 
 10 #include <stdlib.h>
 11 #include <wayland-server.h>
 12 
 13+static void
 14+subsurface_update_position(struct subsurface *subsurface)
 15+{
 16+	struct compositor_view *parent_view;
 17+	struct compositor_view *view;
 18+
 19+	if (!subsurface->surface || !subsurface->parent)
 20+		return;
 21+
 22+	view = compositor_view(subsurface->surface->view);
 23+	parent_view = compositor_view(subsurface->parent->view);
 24+	if (!view || !parent_view)
 25+		return;
 26+
 27+	view_move(&view->base,
 28+	          parent_view->base.geometry.x + subsurface->x - parent_view->buffer_offset_x,
 29+	          parent_view->base.geometry.y + subsurface->y - parent_view->buffer_offset_y);
 30+}
 31+
 32+static void
 33+handle_parent_view_move(struct view_handler *handler)
 34+{
 35+	struct subsurface *subsurface = wl_container_of(handler, subsurface, parent_view_handler);
 36+	subsurface_update_position(subsurface);
 37+}
 38+
 39+static const struct view_handler_impl parent_view_handler_impl = {
 40+	.move = handle_parent_view_move,
 41+};
 42+
 43+static void
 44+handle_surface_destroy(struct wl_listener *listener, void *data)
 45+{
 46+	(void)data;
 47+	struct subsurface *subsurface = wl_container_of(listener, subsurface, surface_destroy_listener);
 48+	if (subsurface->resource)
 49+		wl_resource_destroy(subsurface->resource);
 50+}
 51+
 52+static void
 53+handle_parent_destroy(struct wl_listener *listener, void *data)
 54+{
 55+	(void)data;
 56+	struct subsurface *subsurface = wl_container_of(listener, subsurface, parent_destroy_listener);
 57+	struct compositor_view *view = NULL;
 58+
 59+	if (subsurface->surface && subsurface->surface->view)
 60+		view = compositor_view(subsurface->surface->view);
 61+
 62+	if (view) {
 63+		view->parent = NULL;
 64+		compositor_view_hide(view);
 65+	}
 66+
 67+	if (!wl_list_empty(&subsurface->parent_view_handler.link)) {
 68+		wl_list_remove(&subsurface->parent_view_handler.link);
 69+		wl_list_init(&subsurface->parent_view_handler.link);
 70+	}
 71+
 72+	if (!wl_list_empty(&subsurface->link)) {
 73+		wl_list_remove(&subsurface->link);
 74+		wl_list_init(&subsurface->link);
 75+	}
 76+
 77+	subsurface->parent = NULL;
 78+}
 79+
 80 static void
 81 set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y)
 82 {
 83-	/* TODO: Implement. */
 84+	(void)client;
 85+	struct subsurface *subsurface = wl_resource_get_user_data(resource);
 86+
 87+	subsurface->x = x;
 88+	subsurface->y = y;
 89+	subsurface_update_position(subsurface);
 90 }
 91 
 92 static void
 93 place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource)
 94 {
 95-	/* TODO: Implement. */
 96+	(void)client;
 97+	struct subsurface *subsurface = wl_resource_get_user_data(resource);
 98+	struct surface *sibling_surface = wl_resource_get_user_data(sibling_resource);
 99+	struct compositor_view *view = compositor_view(subsurface->surface->view);
100+	struct compositor_view *sibling_view = compositor_view(sibling_surface->view);
101+
102+	if (!view || !sibling_view || view == sibling_view)
103+		return;
104+
105+	if (view->parent != sibling_view->parent)
106+		return;
107+
108+	wl_list_remove(&view->link);
109+	wl_list_insert(sibling_view->link.prev, &view->link);
110 }
111 
112 static void
113 place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource)
114 {
115-	/* TODO: Implement. */
116+	(void)client;
117+	struct subsurface *subsurface = wl_resource_get_user_data(resource);
118+	struct surface *sibling_surface = wl_resource_get_user_data(sibling_resource);
119+	struct compositor_view *view = compositor_view(subsurface->surface->view);
120+	struct compositor_view *sibling_view = compositor_view(sibling_surface->view);
121+
122+	if (!view || !sibling_view || view == sibling_view)
123+		return;
124+
125+	if (view->parent != sibling_view->parent)
126+		return;
127+
128+	wl_list_remove(&view->link);
129+	wl_list_insert(&sibling_view->link, &view->link);
130 }
131 
132 static void
133 set_sync(struct wl_client *client, struct wl_resource *resource)
134 {
135-	/* TODO: Implement. */
136+	(void)client;
137+	struct subsurface *subsurface = wl_resource_get_user_data(resource);
138+	subsurface->sync = true;
139 }
140 
141 static void
142 set_desync(struct wl_client *client, struct wl_resource *resource)
143 {
144-	/* TODO: Implement. */
145+	(void)client;
146+	struct subsurface *subsurface = wl_resource_get_user_data(resource);
147+	subsurface->sync = false;
148 }
149 
150 static const struct wl_subsurface_interface subsurface_impl = {
151@@ -70,13 +175,47 @@ static void
152 subsurface_destroy(struct wl_resource *resource)
153 {
154 	struct subsurface *subsurface = wl_resource_get_user_data(resource);
155+
156+	if (subsurface->surface) {
157+		if (subsurface->surface->subsurface == subsurface)
158+			subsurface->surface->subsurface = NULL;
159+	}
160+
161+	if (!wl_list_empty(&subsurface->parent_destroy_listener.link)) {
162+		wl_list_remove(&subsurface->parent_destroy_listener.link);
163+		wl_list_init(&subsurface->parent_destroy_listener.link);
164+	}
165+	if (!wl_list_empty(&subsurface->surface_destroy_listener.link)) {
166+		wl_list_remove(&subsurface->surface_destroy_listener.link);
167+		wl_list_init(&subsurface->surface_destroy_listener.link);
168+	}
169+
170+	if (!wl_list_empty(&subsurface->parent_view_handler.link)) {
171+		wl_list_remove(&subsurface->parent_view_handler.link);
172+		wl_list_init(&subsurface->parent_view_handler.link);
173+	}
174+
175+	if (!wl_list_empty(&subsurface->link)) {
176+		wl_list_remove(&subsurface->link);
177+		wl_list_init(&subsurface->link);
178+	}
179+
180+	if (subsurface->surface && subsurface->surface->view) {
181+		struct compositor_view *view = compositor_view(subsurface->surface->view);
182+		if (view && !view->window)
183+			compositor_view_destroy(view);
184+	}
185+
186 	free(subsurface);
187 }
188 
189 struct subsurface *
190-subsurface_new(struct wl_client *client, uint32_t version, uint32_t id)
191+subsurface_new(struct wl_client *client, uint32_t version, uint32_t id,
192+               struct surface *surface, struct surface *parent)
193 {
194 	struct subsurface *subsurface;
195+	struct compositor_view *parent_view;
196+	struct compositor_view *view;
197 
198 	if (!(subsurface = malloc(sizeof(*subsurface))))
199 		goto error0;
200@@ -88,8 +227,47 @@ subsurface_new(struct wl_client *client, uint32_t version, uint32_t id)
201 
202 	wl_resource_set_implementation(subsurface->resource, &subsurface_impl, subsurface, &subsurface_destroy);
203 
204+	subsurface->surface = surface;
205+	subsurface->parent = parent;
206+	subsurface->x = 0;
207+	subsurface->y = 0;
208+	subsurface->sync = true;
209+	subsurface->pending = false;
210+
211+	subsurface->parent_view_handler.impl = &parent_view_handler_impl;
212+	wl_list_init(&subsurface->parent_view_handler.link);
213+	wl_list_init(&subsurface->surface_destroy_listener.link);
214+	wl_list_init(&subsurface->parent_destroy_listener.link);
215+	wl_list_init(&subsurface->link);
216+
217+	if (!surface->view)
218+		compositor_create_view(surface);
219+	if (!parent->view)
220+		compositor_create_view(parent);
221+
222+	parent_view = compositor_view(parent->view);
223+	view = compositor_view(surface->view);
224+	if (!parent_view || !view)
225+		goto error2;
226+
227+	compositor_view_set_parent(view, parent_view);
228+	wl_list_remove(&view->link);
229+	wl_list_insert(parent_view->link.prev, &view->link);
230+
231+	wl_list_insert(&parent_view->base.handlers, &subsurface->parent_view_handler.link);
232+	subsurface_update_position(subsurface);
233+	wl_list_insert(&parent->subsurfaces, &subsurface->link);
234+
235+	subsurface->surface_destroy_listener.notify = handle_surface_destroy;
236+	wl_resource_add_destroy_listener(surface->resource, &subsurface->surface_destroy_listener);
237+	subsurface->parent_destroy_listener.notify = handle_parent_destroy;
238+	wl_resource_add_destroy_listener(parent->resource, &subsurface->parent_destroy_listener);
239+
240 	return subsurface;
241 
242+error2:
243+	wl_resource_destroy(subsurface->resource);
244+	return NULL;
245 error1:
246 	free(subsurface);
247 error0:
+16, -1
 1@@ -24,14 +24,29 @@
 2 #ifndef SWC_SUBSURFACE_H
 3 #define SWC_SUBSURFACE_H
 4 
 5+#include "view.h"
 6+
 7+#include <stdbool.h>
 8 #include <stdint.h>
 9+#include <wayland-server.h>
10 
11 struct wl_client;
12+struct surface;
13 
14 struct subsurface {
15 	struct wl_resource *resource;
16+	struct surface *surface;
17+	struct surface *parent;
18+	struct view_handler parent_view_handler;
19+	struct wl_listener surface_destroy_listener;
20+	struct wl_listener parent_destroy_listener;
21+	struct wl_list link;
22+	int32_t x, y;
23+	bool sync;
24+	bool pending;
25 };
26 
27-struct subsurface *subsurface_new(struct wl_client *client, uint32_t version, uint32_t id);
28+struct subsurface *subsurface_new(struct wl_client *client, uint32_t version, uint32_t id,
29+                                  struct surface *surface, struct surface *parent);
30 
31 #endif
+36, -2
 1@@ -27,6 +27,7 @@
 2 #include "output.h"
 3 #include "region.h"
 4 #include "screen.h"
 5+#include "subsurface.h"
 6 #include "util.h"
 7 #include "view.h"
 8 #include "wayland_buffer.h"
 9@@ -218,9 +219,8 @@ trim_region(pixman_region32_t *region, struct wld_buffer *buffer)
10 }
11 
12 static void
13-commit(struct wl_client *client, struct wl_resource *resource)
14+surface_apply_pending(struct surface *surface, bool flush_children)
15 {
16-	struct surface *surface = wl_resource_get_user_data(resource);
17 	struct wld_buffer *buffer;
18 
19 	/* Attach */
20@@ -263,6 +263,32 @@ commit(struct wl_client *client, struct wl_resource *resource)
21 	}
22 
23 	surface->pending.commit = 0;
24+
25+	if (surface->subsurface)
26+		surface->subsurface->pending = false;
27+
28+	if (flush_children) {
29+		struct subsurface *child;
30+		wl_list_for_each (child, &surface->subsurfaces, link) {
31+			if (!child->sync || !child->pending)
32+				continue;
33+			if (child->surface)
34+				surface_apply_pending(child->surface, true);
35+		}
36+	}
37+}
38+
39+static void
40+commit(struct wl_client *client, struct wl_resource *resource)
41+{
42+	struct surface *surface = wl_resource_get_user_data(resource);
43+
44+	if (surface->subsurface && surface->subsurface->sync) {
45+		surface->subsurface->pending = true;
46+		return;
47+	}
48+
49+	surface_apply_pending(surface, true);
50 }
51 
52 static void
53@@ -339,6 +365,14 @@ surface_new(struct wl_client *client, uint32_t version, uint32_t id)
54 	surface->pending.commit = 0;
55 	surface->view = NULL;
56 	surface->view_handler.impl = &view_handler_impl;
57+	surface->subsurface = NULL;
58+	wl_list_init(&surface->subsurfaces);
59+	surface->has_window_geometry = false;
60+	surface->window_x = 0;
61+	surface->window_y = 0;
62+	surface->window_width = 0;
63+	surface->window_height = 0;
64+	surface->window_geometry_applied = false;
65 
66 	state_initialize(&surface->state);
67 	state_initialize(&surface->pending.state);
+9, -0
 1@@ -29,6 +29,8 @@
 2 #include <pixman.h>
 3 #include <wayland-server.h>
 4 
 5+struct subsurface;
 6+
 7 enum {
 8 	SURFACE_COMMIT_ATTACH = (1 << 0),
 9 	SURFACE_COMMIT_DAMAGE = (1 << 1),
10@@ -67,6 +69,13 @@ struct surface {
11 
12 	struct view *view;
13 	struct view_handler view_handler;
14+
15+	struct subsurface *subsurface;
16+	struct wl_list subsurfaces;
17+	bool has_window_geometry;
18+	int32_t window_x, window_y;
19+	int32_t window_width, window_height;
20+	bool window_geometry_applied;
21 };
22 
23 struct surface *surface_new(struct wl_client *client, uint32_t version, uint32_t id);
+8, -2
 1@@ -395,8 +395,14 @@ window_initialize(struct window *window, const struct window_impl *impl, struct
 2 	window->base.app_id = NULL;
 3 	window->base.parent = NULL;
 4 
 5-	if (!(window->view = compositor_create_view(surface)))
 6-		return false;
 7+	if (surface->view) {
 8+		window->view = compositor_view(surface->view);
 9+		if (!window->view || window->view->window)
10+			return false;
11+	} else {
12+		if (!(window->view = compositor_create_view(surface)))
13+			return false;
14+	}
15 
16 	window->impl = impl;
17 	window->handler = &null_handler;
+19, -0
 1@@ -591,6 +591,25 @@ ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t s
 2 static void
 3 set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
 4 {
 5+	(void)client;
 6+	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
 7+	struct surface *surface = xdg_surface->surface;
 8+
 9+	if (width <= 0 || height <= 0) {
10+		surface->has_window_geometry = false;
11+		return;
12+	}
13+
14+	surface->has_window_geometry = true;
15+	surface->window_x = x;
16+	surface->window_y = y;
17+	surface->window_width = width;
18+	surface->window_height = height;
19+	if (!surface->window_geometry_applied && surface->view && (x != 0 || y != 0)) {
20+		struct swc_rectangle *geom = &surface->view->geometry;
21+		view_move(surface->view, geom->x - x, geom->y - y);
22+		surface->window_geometry_applied = true;
23+	}
24 }
25 
26 static const struct xdg_surface_interface xdg_surface_impl = {