1 #include "compositor_private.h"
3 static const struct wl_subsurface_interface subsurface_impl;
4 static const struct ds_surface_role subsurface_role;
6 static void subsurface_handle_resource_destroy(struct wl_resource *resource);
7 static void subsurface_handle_surface_destroy(struct wl_listener *listener,
9 static void subsurface_link_surface(struct ds_subsurface *subsurface,
10 struct ds_surface *surface);
11 static void subsurface_unlink_surface(struct ds_subsurface *subsurface);
12 static void subsurface_link_parent(struct ds_subsurface *subsurface,
13 struct ds_surface *parent);
14 static void subsurface_unlink_parent(struct ds_subsurface *subsurface);
15 static struct ds_subsurface *subsurface_find_sibling(struct ds_subsurface *subsurface,
16 struct ds_surface *surface);
17 static bool subsurface_is_synchronized(struct ds_subsurface *subsurface);
18 static void subsurface_synchronized_commit(struct ds_subsurface *subsurface);
20 WL_EXPORT struct ds_subsurface *
21 ds_subsurface_create(struct wl_resource *factory_resource,
22 struct ds_surface *surface, struct ds_surface *parent, uint32_t id)
24 return create_subsurface(factory_resource, surface, parent,
25 wl_resource_get_version(factory_resource), id);
28 struct ds_subsurface *
29 create_subsurface(struct wl_resource *factory_resource,
30 struct ds_surface *surface, struct ds_surface *parent,
31 uint32_t version, uint32_t id)
33 struct wl_client *client;
34 struct ds_subsurface *subsurface;
36 if (surface == parent) {
37 ds_inf("ds_surface(%p) cannot be its own parent", surface);
38 wl_resource_post_error(factory_resource,
39 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
40 "%d: wl_surface@%d cannot be its own parent",
41 id, wl_resource_get_id(surface->resource));
45 if (surface_is_ancestor_of(surface, parent)) {
46 ds_inf("ds_surface(%p) is an ancestor of given parent(%p)",
48 wl_resource_post_error(factory_resource,
49 WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
50 "%d: wl_surface@%d is an ancestor of parent",
51 id, wl_resource_get_id(surface->resource));
55 client = wl_resource_get_client(factory_resource);
57 subsurface = calloc(1, sizeof *subsurface);
59 ds_log_errno(DS_ERR, "Could not allocate memory");
60 wl_client_post_no_memory(client);
64 if (!ds_surface_set_role(surface, &subsurface_role, subsurface,
65 factory_resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE)) {
70 subsurface->resource = wl_resource_create(client, &wl_subsurface_interface,
72 if (!subsurface->resource) {
73 ds_log_errno(DS_ERR, "Could not create resource");
75 wl_client_post_no_memory(client);
78 wl_resource_set_implementation(subsurface->resource, &subsurface_impl,
79 subsurface, subsurface_handle_resource_destroy);
81 subsurface->synchronized = true;
83 wl_signal_init(&subsurface->events.destroy);
84 wl_signal_init(&subsurface->events.cached);
85 wl_signal_init(&subsurface->events.request_move);
87 surface_state_init(&subsurface->cached);
88 subsurface_link_surface(subsurface, surface);
89 subsurface_link_parent(subsurface, parent);
91 ds_inf("New ds_subsurface(%p): surface(%p), parent surface(%p)",
92 subsurface, surface, parent);
94 wl_signal_emit_mutable(&parent->events.new_subsurface, subsurface);
100 ds_surface_is_subsurface(struct ds_surface *surface)
102 return ds_surface_get_role(surface) == &subsurface_role;
106 subsurface_commit(struct ds_subsurface *subsurface)
108 struct ds_surface *surface = subsurface->surface;
109 struct ds_subsurface *child;
112 need_sync = subsurface_is_synchronized(subsurface);
114 ds_dbg("ds_subsurface(%p) surface(%p) commit: need_sync(%d) has_cache(%d)",
115 subsurface, subsurface->surface, need_sync, subsurface->has_cache);
118 surface_state_init(&subsurface->cached);
119 surface_state_move(&subsurface->cached, &surface->pending);
120 subsurface->has_cache = true;
122 wl_signal_emit_mutable(&subsurface->events.cached, subsurface);
125 if (subsurface->has_cache) {
126 surface_state_move(&subsurface->cached, &surface->pending);
127 surface_commit_state(surface, &subsurface->cached);
128 subsurface->has_cache = false;
131 surface_commit_state(surface, &surface->pending);
134 wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
135 subsurface_parent_commit(child, false);
136 wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
137 subsurface_parent_commit(child, false);
142 subsurface_parent_commit(struct ds_subsurface *subsurface, bool synchronized)
144 if (subsurface->current.x != subsurface->pending.x ||
145 subsurface->current.y != subsurface->pending.y) {
146 ds_inf("ds_subsurface(%p) surface(%p) request_move: old(%d,%d) new(%d,%d)",
147 subsurface, subsurface->surface,
148 subsurface->current.x, subsurface->current.y,
149 subsurface->pending.x, subsurface->pending.y);
151 subsurface->current.x = subsurface->pending.x;
152 subsurface->current.y = subsurface->pending.y;
154 wl_signal_emit_mutable(&subsurface->events.request_move, subsurface);
157 if (synchronized || subsurface->synchronized) {
158 subsurface_synchronized_commit(subsurface);
162 WL_EXPORT struct ds_subsurface *
163 ds_subsurface_from_resource(struct wl_resource *resource)
165 DS_ASSERT(wl_resource_instance_of(resource, &wl_subsurface_interface,
167 return wl_resource_get_user_data(resource);
171 subsurface_get_parent(struct ds_subsurface *subsurface)
173 return subsurface->parent;
176 WL_EXPORT struct ds_subsurface *
177 ds_subsurface_from_surface(struct ds_surface *surface)
179 if (!ds_surface_is_subsurface(surface))
181 return (struct ds_subsurface *)surface->role_data;
184 static const struct ds_surface_role subsurface_role =
186 .name = "wl_subsurface",
190 subsurface_handle_destroy(struct wl_client *client,
191 struct wl_resource *resource)
193 wl_resource_destroy(resource);
197 subsurface_handle_set_position(struct wl_client *client,
198 struct wl_resource *resource, int32_t x, int32_t y)
200 struct ds_subsurface *subsurface;
202 subsurface = wl_resource_get_user_data(resource);
206 ds_inf("ds_subsurface(%p) surface(%p) set_position: (%d,%d)",
207 subsurface, subsurface->surface, x, y);
209 subsurface->pending.x = x;
210 subsurface->pending.y = y;
214 subsurface_handle_place_above(struct wl_client *client,
215 struct wl_resource *resource, struct wl_resource *sibling_resource)
217 struct ds_subsurface *subsurface, *sibling;
218 struct ds_surface *sibling_surface;
219 struct wl_list *node;
221 subsurface = wl_resource_get_user_data(resource);
225 sibling_surface = ds_surface_from_resource(sibling_resource);
227 ds_inf("ds_subsurface(%p) surface(%p) place_above: sibling surface(%p)",
228 subsurface, subsurface->surface, sibling_surface);
230 if (sibling_surface == subsurface->parent) {
231 node = &subsurface->parent->pending.subsurfaces_above;
234 sibling = subsurface_find_sibling(subsurface, sibling_surface);
236 wl_resource_post_error(subsurface->resource,
237 WL_SUBSURFACE_ERROR_BAD_SURFACE,
238 "%s: wl_surface@%d is not a parent or sibling",
239 "place_above", wl_resource_get_id(sibling_resource));
242 node = &sibling->pending.link;
245 wl_list_remove(&subsurface->pending.link);
246 wl_list_insert(node, &subsurface->pending.link);
248 subsurface->reordered = true;
252 subsurface_handle_place_below(struct wl_client *client,
253 struct wl_resource *resource, struct wl_resource *sibling_resource)
255 struct ds_subsurface *subsurface, *sibling;
256 struct ds_surface *sibling_surface;
257 struct wl_list *node;
259 subsurface = wl_resource_get_user_data(resource);
263 sibling_surface = ds_surface_from_resource(sibling_resource);
265 ds_inf("ds_subsurface(%p) surface(%p) place_below: sibling surface(%p)",
266 subsurface, subsurface->surface, sibling_surface);
268 if (sibling_surface == subsurface->parent) {
269 node = &subsurface->parent->pending.subsurfaces_below;
272 sibling = subsurface_find_sibling(subsurface, sibling_surface);
274 wl_resource_post_error(subsurface->resource,
275 WL_SUBSURFACE_ERROR_BAD_SURFACE,
276 "%s: wl_surface@%d is not a parent or sibling",
277 "place_below", wl_resource_get_id(sibling_resource));
280 node = &sibling->pending.link;
284 wl_list_remove(&subsurface->pending.link);
285 wl_list_insert(node->prev, &subsurface->pending.link);
287 subsurface->reordered = true;
291 subsurface_handle_set_sync(struct wl_client *client,
292 struct wl_resource *resource)
294 struct ds_subsurface *subsurface;
296 subsurface = wl_resource_get_user_data(resource);
300 ds_inf("ds_subsurface(%p) surface(%p) set_sync",
301 subsurface, subsurface->surface);
303 subsurface->synchronized = true;
307 subsurface_handle_set_desync(struct wl_client *client,
308 struct wl_resource *resource)
310 struct ds_subsurface *subsurface;
312 subsurface = wl_resource_get_user_data(resource);
316 ds_inf("ds_subsurface(%p) surface(%p) set_desync",
317 subsurface, subsurface->surface);
319 if (subsurface->synchronized) {
320 subsurface->synchronized = false;
322 if (!subsurface_is_synchronized(subsurface))
323 subsurface_synchronized_commit(subsurface);
327 static const struct wl_subsurface_interface subsurface_impl =
329 .destroy = subsurface_handle_destroy,
330 .set_position = subsurface_handle_set_position,
331 .place_above = subsurface_handle_place_above,
332 .place_below = subsurface_handle_place_below,
333 .set_sync = subsurface_handle_set_sync,
334 .set_desync = subsurface_handle_set_desync,
338 subsurface_destroy(struct ds_subsurface *subsurface)
340 ds_inf("Destroy ds_subsurface(%p) surface(%p)",
341 subsurface, subsurface->surface);
343 wl_signal_emit_mutable(&subsurface->events.destroy, subsurface);
345 if (subsurface->parent)
346 subsurface_unlink_parent(subsurface);
348 if (subsurface->surface)
349 subsurface_unlink_surface(subsurface);
351 surface_state_finish(&subsurface->cached);
352 wl_resource_set_user_data(subsurface->resource, NULL);
358 subsurface_handle_resource_destroy(struct wl_resource *resource)
360 struct ds_subsurface *subsurface;
362 subsurface = wl_resource_get_user_data(resource);
366 subsurface_destroy(subsurface);
370 void subsurface_handle_surface_destroy(struct wl_listener *listener,
373 struct ds_subsurface *subsurface;
375 subsurface = wl_container_of(listener, subsurface,
376 listener.surface_destroy);
377 subsurface_destroy(subsurface);
381 subsurface_handle_parent_destroy(struct wl_listener *listener,
384 struct ds_subsurface *subsurface;
386 subsurface = wl_container_of(listener, subsurface,
387 listener.parent_destroy);
388 subsurface_destroy(subsurface);
392 subsurface_link_surface(struct ds_subsurface *subsurface, struct ds_surface *surface)
394 subsurface->surface = surface;
395 subsurface->listener.surface_destroy.notify =
396 subsurface_handle_surface_destroy;
397 ds_surface_add_destroy_listener(surface,
398 &subsurface->listener.surface_destroy);
402 subsurface_unlink_surface(struct ds_subsurface *subsurface)
404 wl_list_remove(&subsurface->listener.surface_destroy.link);
405 subsurface->surface->role_data = NULL;
406 subsurface->surface = NULL;
410 subsurface_link_parent(struct ds_subsurface *subsurface, struct ds_surface *parent)
412 subsurface->parent = parent;
413 subsurface->listener.parent_destroy.notify =
414 subsurface_handle_parent_destroy;
415 ds_surface_add_destroy_listener(parent,
416 &subsurface->listener.parent_destroy);
417 wl_list_insert(parent->current.subsurfaces_above.prev,
418 &subsurface->current.link);
419 wl_list_insert(parent->pending.subsurfaces_above.prev,
420 &subsurface->pending.link);
424 subsurface_unlink_parent(struct ds_subsurface *subsurface)
426 wl_list_remove(&subsurface->current.link);
427 wl_list_remove(&subsurface->pending.link);
428 wl_list_remove(&subsurface->listener.parent_destroy.link);
429 subsurface->parent = NULL;
432 static struct ds_subsurface *
433 subsurface_find_sibling(struct ds_subsurface *subsurface, struct ds_surface *surface)
435 struct ds_surface *parent = subsurface->parent;
436 struct ds_subsurface *sibling;
438 wl_list_for_each(sibling, &parent->pending.subsurfaces_below, pending.link) {
439 if (sibling->surface == surface && sibling != subsurface)
443 wl_list_for_each(sibling, &parent->pending.subsurfaces_above, pending.link) {
444 if (sibling->surface == surface && sibling != subsurface) {
453 subsurface_is_synchronized(struct ds_subsurface *subsurface)
455 struct ds_subsurface *iter = subsurface;
458 if (iter->synchronized)
460 } while ((iter = ds_subsurface_from_surface(iter->parent)));
466 subsurface_synchronized_commit(struct ds_subsurface *subsurface)
468 struct ds_surface *surface = subsurface->surface;
469 struct ds_subsurface *child;
471 ds_dbg("ds_subsurface(%p) surface(%p) synchronized commit",
472 subsurface, subsurface->surface);
474 if (subsurface->has_cache) {
475 surface_state_move(&subsurface->cached, &surface->pending);
476 surface_commit_state(surface, &subsurface->cached);
477 subsurface->has_cache = false;
480 wl_list_for_each(child, &surface->current.subsurfaces_below, current.link)
481 subsurface_parent_commit(child, true);
482 wl_list_for_each(child, &surface->current.subsurfaces_above, current.link)
483 subsurface_parent_commit(child, true);