subsurface: Add more log for debug
[platform/core/uifw/libds.git] / src / compositor / subsurface.c
1 #include "compositor_private.h"
2
3 static const struct wl_subsurface_interface subsurface_impl;
4 static const struct ds_surface_role subsurface_role;
5
6 static void subsurface_handle_resource_destroy(struct wl_resource *resource);
7 static void subsurface_handle_surface_destroy(struct wl_listener *listener,
8         void *data);
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);
19
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)
23 {
24     return create_subsurface(factory_resource, surface, parent,
25             wl_resource_get_version(factory_resource), id);
26 }
27
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)
32 {
33     struct wl_client *client;
34     struct ds_subsurface *subsurface;
35
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));
42         return NULL;
43     }
44
45     if (surface_is_ancestor_of(surface, parent)) {
46         ds_inf("ds_surface(%p) is an ancestor of given parent(%p)",
47                 surface, parent);
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));
52         return NULL;
53     }
54
55     client = wl_resource_get_client(factory_resource);
56
57     subsurface = calloc(1, sizeof *subsurface);
58     if (!subsurface) {
59         ds_log_errno(DS_ERR, "Could not allocate memory");
60         wl_client_post_no_memory(client);
61         return NULL;
62     }
63
64     if (!ds_surface_set_role(surface, &subsurface_role, subsurface,
65             factory_resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE)) {
66         free(subsurface);
67         return NULL;
68     }
69
70     subsurface->resource = wl_resource_create(client, &wl_subsurface_interface,
71             version, id);
72     if (!subsurface->resource) {
73         ds_log_errno(DS_ERR, "Could not create resource");
74         free(subsurface);
75         wl_client_post_no_memory(client);
76         return NULL;
77     }
78     wl_resource_set_implementation(subsurface->resource, &subsurface_impl,
79             subsurface, subsurface_handle_resource_destroy);
80
81     subsurface->synchronized = true;
82
83     wl_signal_init(&subsurface->events.destroy);
84     wl_signal_init(&subsurface->events.cached);
85     wl_signal_init(&subsurface->events.request_move);
86
87     surface_state_init(&subsurface->cached);
88     subsurface_link_surface(subsurface, surface);
89     subsurface_link_parent(subsurface, parent);
90
91     ds_inf("New ds_subsurface(%p): surface(%p), parent surface(%p)",
92             subsurface, surface, parent);
93
94     wl_signal_emit_mutable(&parent->events.new_subsurface, subsurface);
95
96     return subsurface;
97 }
98
99 WL_EXPORT bool
100 ds_surface_is_subsurface(struct ds_surface *surface)
101 {
102     return ds_surface_get_role(surface) == &subsurface_role;
103 }
104
105 void
106 subsurface_commit(struct ds_subsurface *subsurface)
107 {
108     struct ds_surface *surface = subsurface->surface;
109     struct ds_subsurface *child;
110     bool need_sync;
111
112     need_sync = subsurface_is_synchronized(subsurface);
113
114     ds_dbg("ds_subsurface(%p) surface(%p) commit: need_sync(%d) has_cache(%d)",
115             subsurface, subsurface->surface, need_sync, subsurface->has_cache);
116
117     if (need_sync) {
118         surface_state_init(&subsurface->cached);
119         surface_state_move(&subsurface->cached, &surface->pending);
120         subsurface->has_cache = true;
121
122         wl_signal_emit_mutable(&subsurface->events.cached, subsurface);
123     }
124     else {
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;
129         }
130         else {
131             surface_commit_state(surface, &surface->pending);
132         }
133
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);
138     }
139 }
140
141 void
142 subsurface_parent_commit(struct ds_subsurface *subsurface, bool synchronized)
143 {
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);
150
151         subsurface->current.x = subsurface->pending.x;
152         subsurface->current.y = subsurface->pending.y;
153
154         wl_signal_emit_mutable(&subsurface->events.request_move, subsurface);
155     }
156
157     if (synchronized || subsurface->synchronized) {
158         subsurface_synchronized_commit(subsurface);
159     }
160 }
161
162 WL_EXPORT struct ds_subsurface *
163 ds_subsurface_from_resource(struct wl_resource *resource)
164 {
165     DS_ASSERT(wl_resource_instance_of(resource, &wl_subsurface_interface,
166                 &subsurface_impl));
167     return wl_resource_get_user_data(resource);
168 }
169
170 struct ds_surface *
171 subsurface_get_parent(struct ds_subsurface *subsurface)
172 {
173     return subsurface->parent;
174 }
175
176 WL_EXPORT struct ds_subsurface *
177 ds_subsurface_from_surface(struct ds_surface *surface)
178 {
179     if (!ds_surface_is_subsurface(surface))
180         return NULL;
181     return (struct ds_subsurface *)surface->role_data;
182 }
183
184 static const struct ds_surface_role subsurface_role =
185 {
186     .name = "wl_subsurface",
187 };
188
189 static void
190 subsurface_handle_destroy(struct wl_client *client,
191         struct wl_resource *resource)
192 {
193     wl_resource_destroy(resource);
194 }
195
196 static void
197 subsurface_handle_set_position(struct wl_client *client,
198         struct wl_resource *resource, int32_t x, int32_t y)
199 {
200     struct ds_subsurface *subsurface;
201
202     subsurface = wl_resource_get_user_data(resource);
203     if (!subsurface)
204         return;
205
206     ds_inf("ds_subsurface(%p) surface(%p) set_position: (%d,%d)",
207             subsurface, subsurface->surface, x, y);
208
209     subsurface->pending.x = x;
210     subsurface->pending.y = y;
211 }
212
213 static void
214 subsurface_handle_place_above(struct wl_client *client,
215         struct wl_resource *resource, struct wl_resource *sibling_resource)
216 {
217     struct ds_subsurface *subsurface, *sibling;
218     struct ds_surface *sibling_surface;
219     struct wl_list *node;
220
221     subsurface = wl_resource_get_user_data(resource);
222     if (!subsurface)
223         return;
224
225     sibling_surface = ds_surface_from_resource(sibling_resource);
226
227     ds_inf("ds_subsurface(%p) surface(%p) place_above: sibling surface(%p)",
228             subsurface, subsurface->surface, sibling_surface);
229
230     if (sibling_surface == subsurface->parent) {
231         node = &subsurface->parent->pending.subsurfaces_above;
232     }
233     else {
234         sibling = subsurface_find_sibling(subsurface, sibling_surface);
235         if (!sibling) {
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));
240             return;
241         }
242         node = &sibling->pending.link;
243     }
244
245     wl_list_remove(&subsurface->pending.link);
246     wl_list_insert(node, &subsurface->pending.link);
247
248     subsurface->reordered = true;
249 }
250
251 static void
252 subsurface_handle_place_below(struct wl_client *client,
253         struct wl_resource *resource, struct wl_resource *sibling_resource)
254 {
255     struct ds_subsurface *subsurface, *sibling;
256     struct ds_surface *sibling_surface;
257     struct wl_list *node;
258
259     subsurface = wl_resource_get_user_data(resource);
260     if (!subsurface)
261         return;
262
263     sibling_surface = ds_surface_from_resource(sibling_resource);
264
265     ds_inf("ds_subsurface(%p) surface(%p) place_below: sibling surface(%p)",
266             subsurface, subsurface->surface, sibling_surface);
267
268     if (sibling_surface == subsurface->parent) {
269         node = &subsurface->parent->pending.subsurfaces_below;
270     }
271     else {
272         sibling = subsurface_find_sibling(subsurface, sibling_surface);
273         if (!sibling) {
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));
278             return;
279         }
280         node = &sibling->pending.link;
281
282     }
283
284     wl_list_remove(&subsurface->pending.link);
285     wl_list_insert(node->prev, &subsurface->pending.link);
286
287     subsurface->reordered = true;
288 }
289
290 static void
291 subsurface_handle_set_sync(struct wl_client *client,
292         struct wl_resource *resource)
293 {
294     struct ds_subsurface *subsurface;
295
296     subsurface = wl_resource_get_user_data(resource);
297     if (!subsurface)
298         return;
299
300     ds_inf("ds_subsurface(%p) surface(%p) set_sync",
301             subsurface, subsurface->surface);
302
303     subsurface->synchronized = true;
304 }
305
306 static void
307 subsurface_handle_set_desync(struct wl_client *client,
308         struct wl_resource *resource)
309 {
310     struct ds_subsurface *subsurface;
311
312     subsurface = wl_resource_get_user_data(resource);
313     if (!subsurface)
314         return;
315
316     ds_inf("ds_subsurface(%p) surface(%p) set_desync",
317             subsurface, subsurface->surface);
318
319     if (subsurface->synchronized) {
320         subsurface->synchronized = false;
321
322         if (!subsurface_is_synchronized(subsurface))
323             subsurface_synchronized_commit(subsurface);
324     }
325 }
326
327 static const struct wl_subsurface_interface subsurface_impl =
328 {
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,
335 };
336
337 static void
338 subsurface_destroy(struct ds_subsurface *subsurface)
339 {
340     ds_inf("Destroy ds_subsurface(%p) surface(%p)",
341             subsurface, subsurface->surface);
342
343     wl_signal_emit_mutable(&subsurface->events.destroy, subsurface);
344
345     if (subsurface->parent)
346         subsurface_unlink_parent(subsurface);
347
348     if (subsurface->surface)
349         subsurface_unlink_surface(subsurface);
350
351     surface_state_finish(&subsurface->cached);
352     wl_resource_set_user_data(subsurface->resource, NULL);
353
354     free(subsurface);
355 }
356
357 static void
358 subsurface_handle_resource_destroy(struct wl_resource *resource)
359 {
360     struct ds_subsurface *subsurface;
361
362     subsurface = wl_resource_get_user_data(resource);
363     if (!subsurface)
364         return;
365
366     subsurface_destroy(subsurface);
367 }
368
369 static
370 void subsurface_handle_surface_destroy(struct wl_listener *listener,
371         void *data)
372 {
373     struct ds_subsurface *subsurface;
374
375     subsurface = wl_container_of(listener, subsurface,
376             listener.surface_destroy);
377     subsurface_destroy(subsurface);
378 }
379
380 static void
381 subsurface_handle_parent_destroy(struct wl_listener *listener,
382         void *data)
383 {
384     struct ds_subsurface *subsurface;
385
386     subsurface = wl_container_of(listener, subsurface,
387             listener.parent_destroy);
388     subsurface_destroy(subsurface);
389 }
390
391 static void
392 subsurface_link_surface(struct ds_subsurface *subsurface, struct ds_surface *surface)
393 {
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);
399 }
400
401 static void
402 subsurface_unlink_surface(struct ds_subsurface *subsurface)
403 {
404     wl_list_remove(&subsurface->listener.surface_destroy.link);
405     subsurface->surface->role_data = NULL;
406     subsurface->surface = NULL;
407 }
408
409 static void
410 subsurface_link_parent(struct ds_subsurface *subsurface, struct ds_surface *parent)
411 {
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);
421 }
422
423 static void
424 subsurface_unlink_parent(struct ds_subsurface *subsurface)
425 {
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;
430 }
431
432 static struct ds_subsurface *
433 subsurface_find_sibling(struct ds_subsurface *subsurface, struct ds_surface *surface)
434 {
435     struct ds_surface *parent = subsurface->parent;
436     struct ds_subsurface *sibling;
437
438     wl_list_for_each(sibling, &parent->pending.subsurfaces_below, pending.link) {
439         if (sibling->surface == surface && sibling != subsurface)
440             return sibling;
441     }
442
443     wl_list_for_each(sibling, &parent->pending.subsurfaces_above, pending.link) {
444         if (sibling->surface == surface && sibling != subsurface) {
445             return sibling;
446         }
447     }
448
449     return NULL;
450 }
451
452 static bool
453 subsurface_is_synchronized(struct ds_subsurface *subsurface)
454 {
455     struct ds_subsurface *iter = subsurface;
456
457     do {
458         if (iter->synchronized)
459             return true;
460     } while ((iter = ds_subsurface_from_surface(iter->parent)));
461
462     return false;
463 }
464
465 static void
466 subsurface_synchronized_commit(struct ds_subsurface *subsurface)
467 {
468     struct ds_surface *surface = subsurface->surface;
469     struct ds_subsurface *child;
470
471     ds_dbg("ds_subsurface(%p) surface(%p) synchronized commit",
472             subsurface, subsurface->surface);
473
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;
478     }
479
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);
484 }