6a8a7a2caa7606408bfbe8243d89d1ef70242bb4
[platform/core/uifw/libds.git] / src / xdg_shell_v6 / xdg_toplevel_v6.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "util.h"
5 #include "xdg_shell_v6.h"
6
7 static const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_impl;
8
9 static void xdg_toplevel_v6_handle_resource_destroy(struct wl_resource *resource);
10 static void xdg_toplevel_v6_set_parent(struct ds_xdg_toplevel_v6 *toplevel,
11         struct ds_xdg_toplevel_v6 *parent);
12
13 WL_EXPORT void
14 ds_xdg_toplevel_v6_add_set_parent_listener(struct ds_xdg_toplevel_v6 *toplevel,
15         struct wl_listener *listener)
16 {
17     wl_signal_add(&toplevel->events.set_parent, listener);
18 }
19
20 WL_EXPORT void
21 ds_xdg_toplevel_v6_add_request_move_listener(struct ds_xdg_toplevel_v6 *toplevel,
22         struct wl_listener *listener)
23 {
24     wl_signal_add(&toplevel->events.request_move, listener);
25 }
26
27 WL_EXPORT void
28 ds_xdg_toplevel_v6_add_request_resize_listener(struct ds_xdg_toplevel_v6 *toplevel,
29         struct wl_listener *listener)
30 {
31     wl_signal_add(&toplevel->events.request_resize, listener);
32 }
33
34 WL_EXPORT void
35 ds_xdg_toplevel_v6_add_request_maximize_listener(
36         struct ds_xdg_toplevel_v6 *toplevel,
37         struct wl_listener *listener)
38 {
39     wl_signal_add(&toplevel->events.request_maximize, listener);
40 }
41
42 WL_EXPORT void
43 ds_xdg_toplevel_v6_add_request_fullscreen_listener(
44         struct ds_xdg_toplevel_v6 *toplevel,
45         struct wl_listener *listener)
46 {
47     wl_signal_add(&toplevel->events.request_fullscreen, listener);
48 }
49
50 WL_EXPORT void
51 ds_xdg_toplevel_v6_add_request_minimize_listener(
52         struct ds_xdg_toplevel_v6 *toplevel,
53         struct wl_listener *listener)
54 {
55     wl_signal_add(&toplevel->events.request_minimize, listener);
56 }
57
58 WL_EXPORT uint32_t
59 ds_xdg_toplevel_v6_set_size(struct ds_xdg_toplevel_v6 *toplevel,
60         int32_t width, int32_t height)
61 {
62     toplevel->scheduled.width = width;
63     toplevel->scheduled.height = height;
64     return ds_xdg_surface_v6_schedule_configure(toplevel->base);
65 }
66
67 WL_EXPORT uint32_t
68 ds_xdg_toplevel_v6_set_activated(struct ds_xdg_toplevel_v6 *toplevel,
69         bool activated)
70 {
71     toplevel->scheduled.activated = activated;
72     return ds_xdg_surface_v6_schedule_configure(toplevel->base);
73 }
74
75 WL_EXPORT uint32_t
76 ds_xdg_toplevel_v6_set_maximized(struct ds_xdg_toplevel_v6 *toplevel,
77         bool maximized)
78 {
79     toplevel->scheduled.maximized = maximized;
80     return ds_xdg_surface_v6_schedule_configure(toplevel->base);
81 }
82
83 WL_EXPORT uint32_t
84 ds_xdg_toplevel_v6_set_fullscreen(struct ds_xdg_toplevel_v6 *toplevel,
85         bool fullscreen)
86 {
87     toplevel->scheduled.fullscreen = fullscreen;
88     return ds_xdg_surface_v6_schedule_configure(toplevel->base);
89 }
90
91 WL_EXPORT uint32_t
92 ds_xdg_toplevel_v6_set_resizing(struct ds_xdg_toplevel_v6 *toplevel,
93         bool resizing)
94 {
95     toplevel->scheduled.resizing = resizing;
96     return ds_xdg_surface_v6_schedule_configure(toplevel->base);
97 }
98
99 void
100 create_xdg_toplevel_v6(struct ds_xdg_surface_v6 *surface, uint32_t id)
101 {
102     if (surface->role != DS_XDG_SURFACE_V6_ROLE_NONE) {
103         wl_resource_post_error(surface->resource,
104                 ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
105                 "xdg_surface_v6 has already been constructed");
106         return;
107     }
108
109     DS_ASSERT(surface->toplevel == NULL);
110
111     surface->toplevel = calloc(1, sizeof *surface->toplevel);
112     if (!surface->toplevel) {
113         wl_resource_post_no_memory(surface->resource);
114         return;
115     }
116
117     surface->toplevel->base = surface;
118
119     wl_signal_init(&surface->toplevel->events.request_maximize);
120     wl_signal_init(&surface->toplevel->events.request_fullscreen);
121     wl_signal_init(&surface->toplevel->events.request_minimize);
122     wl_signal_init(&surface->toplevel->events.request_move);
123     wl_signal_init(&surface->toplevel->events.request_resize);
124     wl_signal_init(&surface->toplevel->events.request_show_window_menu);
125     wl_signal_init(&surface->toplevel->events.set_parent);
126     wl_signal_init(&surface->toplevel->events.set_title);
127     wl_signal_init(&surface->toplevel->events.set_app_id);
128
129     surface->toplevel->resource = wl_resource_create(
130             surface->client->wl_client, &zxdg_toplevel_v6_interface,
131             wl_resource_get_version(surface->resource), id);
132     if (!surface->toplevel->resource) {
133         free(surface->toplevel);
134         wl_resource_post_no_memory(surface->resource);
135         return;
136     }
137
138     wl_resource_set_implementation(surface->toplevel->resource,
139             &xdg_toplevel_v6_impl, surface->toplevel,
140             xdg_toplevel_v6_handle_resource_destroy);
141
142     surface->role = DS_XDG_SURFACE_V6_ROLE_TOPLEVEL;
143 }
144
145 void
146 handle_xdg_toplevel_v6_committed(struct ds_xdg_toplevel_v6 *toplevel)
147 {
148     toplevel->current = toplevel->pending;
149
150     if (!toplevel->sent_initial_configure) {
151         ds_xdg_surface_v6_schedule_configure(toplevel->base);
152         toplevel->sent_initial_configure = true;
153     }
154 }
155
156 void
157 send_xdg_toplevel_v6_configure(struct ds_xdg_surface_v6 *surface,
158         struct ds_xdg_surface_v6_configure *configure)
159 {
160     struct wl_array states;
161     uint32_t width, height;
162
163     configure->toplevel_configure =
164         malloc(sizeof *configure->toplevel_configure);
165     if (!configure->toplevel_configure) {
166         wl_resource_post_no_memory(surface->toplevel->resource);
167         return;
168     }
169
170     *configure->toplevel_configure = surface->toplevel->scheduled;
171
172     wl_array_init(&states);
173     if (surface->toplevel->scheduled.maximized) {
174         uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
175         if (!s)
176             goto error_out;
177         *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
178     }
179
180     if (surface->toplevel->scheduled.fullscreen) {
181         uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
182         if (!s)
183             goto error_out;
184         *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
185     }
186
187     if (surface->toplevel->scheduled.resizing) {
188         uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
189         if (!s)
190             goto error_out;
191         *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
192     }
193
194     if (surface->toplevel->scheduled.activated) {
195         uint32_t *s = wl_array_add(&states, sizeof(uint32_t));
196         if (!s)
197             goto error_out;
198         *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
199     }
200
201     width = surface->toplevel->scheduled.width;
202     height = surface->toplevel->scheduled.height;
203
204     zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, height,
205             &states);
206     wl_array_release(&states);
207
208     return;
209
210 error_out:
211     wl_array_release(&states);
212     wl_resource_post_no_memory(surface->toplevel->resource);
213 }
214
215 void
216 destroy_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel)
217 {
218     wl_resource_set_user_data(toplevel->resource, NULL);
219     free(toplevel);
220 }
221
222 void
223 reset_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel)
224 {
225     if (toplevel->parent) {
226         wl_list_remove(&toplevel->parent_unmap.link);
227         toplevel->parent = NULL;
228     }
229
230     free(toplevel->title);
231     toplevel->title = NULL;
232
233     free(toplevel->app_id);
234     toplevel->app_id = NULL;
235
236     if (toplevel->requested.fullscreen_output) {
237         wl_list_remove(&toplevel->requested.fullscreen_output_destroy.link);
238         toplevel->requested.fullscreen_output = NULL;
239     }
240
241     toplevel->requested.fullscreen = false;
242     toplevel->requested.maximized = false;
243     toplevel->requested.minimized = false;
244
245     toplevel->sent_initial_configure = false;
246 }
247
248 static void
249 xdg_toplevel_v6_handle_destroy(struct wl_client *client,
250         struct wl_resource *resource)
251 {
252     wl_resource_destroy(resource);
253 }
254
255 static void
256 xdg_toplevel_v6_handle_set_parent(struct wl_client *client,
257         struct wl_resource *resource, struct wl_resource *parent_resource)
258 {
259     struct ds_xdg_toplevel_v6 *toplevel, *parent = NULL;
260
261     toplevel = wl_resource_get_user_data(resource);
262     if (!toplevel)
263         return;
264
265     if (parent_resource)
266         parent = wl_resource_get_user_data(parent_resource);
267
268     xdg_toplevel_v6_set_parent(toplevel, parent);
269 }
270
271 static void
272 xdg_toplevel_v6_handle_set_title(struct wl_client *client,
273         struct wl_resource *resource, const char *title)
274 {
275     struct ds_xdg_toplevel_v6 *toplevel;
276     char *tmp;
277
278     toplevel = wl_resource_get_user_data(resource);
279     if (!toplevel)
280         return;
281
282     tmp = strdup(title);
283     if (!tmp) {
284         wl_resource_post_no_memory(resource);
285         return;
286     }
287
288     if (toplevel->title)
289         free(toplevel->title);
290
291     toplevel->title = tmp;
292     wl_signal_emit_mutable(&toplevel->events.set_title, toplevel);
293 }
294
295 static void
296 xdg_toplevel_v6_handle_set_app_id(struct wl_client *client,
297         struct wl_resource *resource, const char *app_id)
298 {
299     struct ds_xdg_toplevel_v6 *toplevel;
300     char *tmp;
301
302     toplevel = wl_resource_get_user_data(resource);
303     if (!toplevel)
304         return;
305
306     tmp = strdup(app_id);
307     if (!tmp) {
308         wl_resource_post_no_memory(resource);
309         return;
310     }
311
312     if (toplevel->app_id)
313         free(toplevel->app_id);
314
315     toplevel->app_id= tmp;
316     wl_signal_emit_mutable(&toplevel->events.set_app_id, toplevel);
317 }
318
319 static void
320 xdg_toplevel_v6_handle_show_window_menu(struct wl_client *client,
321         struct wl_resource *resource, struct wl_resource *seat_resource,
322         uint32_t serial, int32_t x, int32_t y)
323 {
324     // TODO
325 }
326
327 static void
328 xdg_toplevel_v6_handle_move(struct wl_client *client,
329         struct wl_resource *resource, struct wl_resource *seat_resource,
330         uint32_t serial)
331 {
332     struct ds_xdg_toplevel_v6 *toplevel;
333
334     toplevel = wl_resource_get_user_data(resource);
335     if (!toplevel)
336         return;
337
338     if (!toplevel->base->configured) {
339         wl_resource_post_error(toplevel->base->resource,
340                 ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
341                 "surface has not been configured yet");
342         return;
343     }
344
345     struct ds_xdg_toplevel_v6_event_request_move event = {
346         .toplevel = toplevel,
347         .seat_resource = seat_resource,
348         .serial = serial,
349     };
350     wl_signal_emit_mutable(&toplevel->events.request_move, &event);
351 }
352
353 static void
354 xdg_toplevel_v6_handle_resize(struct wl_client *client,
355         struct wl_resource *resource, struct wl_resource *seat_resource,
356         uint32_t serial, uint32_t edges)
357 {
358     struct ds_xdg_toplevel_v6 *toplevel;
359
360     toplevel = wl_resource_get_user_data(resource);
361     if (!toplevel)
362         return;
363
364     if (!toplevel->base->configured) {
365         wl_resource_post_error(toplevel->base->resource,
366                 ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
367                 "surface has not been configured yet");
368         return;
369     }
370
371     struct ds_xdg_toplevel_v6_event_request_resize event = {
372         .toplevel = toplevel,
373         .seat_resource = seat_resource,
374         .serial = serial,
375         .edges = edges,
376     };
377     wl_signal_emit_mutable(&toplevel->events.request_resize, &event);
378 }
379
380 static void
381 xdg_toplevel_v6_handle_set_max_size(struct wl_client *client,
382         struct wl_resource *resource, int32_t width, int32_t height)
383 {
384     struct ds_xdg_toplevel_v6 *toplevel;
385
386     toplevel = wl_resource_get_user_data(resource);
387     if (!toplevel)
388         return;
389
390     toplevel->pending.max_width = width;
391     toplevel->pending.max_height = height;
392 }
393
394 static void
395 xdg_toplevel_v6_handle_set_min_size(struct wl_client *client,
396         struct wl_resource *resource, int32_t width, int32_t height)
397 {
398     struct ds_xdg_toplevel_v6 *toplevel;
399
400     toplevel = wl_resource_get_user_data(resource);
401     if (!toplevel)
402         return;
403
404     toplevel->pending.min_width = width;
405     toplevel->pending.min_height = height;
406 }
407
408 static void
409 xdg_toplevel_v6_handle_set_maximized(struct wl_client *client,
410         struct wl_resource *resource)
411 {
412     struct ds_xdg_toplevel_v6 *toplevel;
413
414     toplevel = wl_resource_get_user_data(resource);
415     if (!toplevel)
416         return;
417
418     toplevel->requested.maximized = true;
419     wl_signal_emit_mutable(&toplevel->events.request_maximize, toplevel);
420 }
421
422 static void
423 xdg_toplevel_v6_handle_unset_maximized(struct wl_client *client,
424         struct wl_resource *resource)
425 {
426     struct ds_xdg_toplevel_v6 *toplevel;
427
428     toplevel = wl_resource_get_user_data(resource);
429     if (!toplevel)
430         return;
431
432     toplevel->requested.maximized = false;
433     wl_signal_emit_mutable(&toplevel->events.request_maximize, toplevel);
434 }
435
436 static void
437 xdg_toplevel_v6_handle_set_fullscreen(struct wl_client *client,
438         struct wl_resource *resource, struct wl_resource  *output_resource)
439 {
440     struct ds_xdg_toplevel_v6 *toplevel;
441
442     toplevel = wl_resource_get_user_data(resource);
443     if (!toplevel)
444         return;
445
446     // TODO get a ds_output from an output_resource
447
448     toplevel->requested.fullscreen = true;
449     wl_signal_emit_mutable(&toplevel->events.request_fullscreen, toplevel);
450 }
451
452 static void
453 xdg_toplevel_v6_handle_unset_fullscreen(struct wl_client *client,
454         struct wl_resource *resource)
455 {
456     struct ds_xdg_toplevel_v6 *toplevel;
457
458     toplevel = wl_resource_get_user_data(resource);
459     if (!toplevel)
460         return;
461
462     toplevel->requested.fullscreen = false;
463     wl_signal_emit_mutable(&toplevel->events.request_fullscreen, toplevel);
464 }
465
466 static void
467 xdg_toplevel_v6_handle_set_minimized(struct wl_client *client,
468         struct wl_resource *resource)
469 {
470     struct ds_xdg_toplevel_v6 *toplevel;
471
472     toplevel = wl_resource_get_user_data(resource);
473     if (!toplevel)
474         return;
475
476     toplevel->requested.minimized = true;
477     wl_signal_emit_mutable(&toplevel->events.request_maximize, toplevel);
478 }
479
480 static const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_impl =
481 {
482     xdg_toplevel_v6_handle_destroy,
483     xdg_toplevel_v6_handle_set_parent,
484     xdg_toplevel_v6_handle_set_title,
485     xdg_toplevel_v6_handle_set_app_id,
486     xdg_toplevel_v6_handle_show_window_menu,
487     xdg_toplevel_v6_handle_move,
488     xdg_toplevel_v6_handle_resize,
489     xdg_toplevel_v6_handle_set_max_size,
490     xdg_toplevel_v6_handle_set_min_size,
491     xdg_toplevel_v6_handle_set_maximized,
492     xdg_toplevel_v6_handle_unset_maximized,
493     xdg_toplevel_v6_handle_set_fullscreen,
494     xdg_toplevel_v6_handle_unset_fullscreen,
495     xdg_toplevel_v6_handle_set_minimized,
496 };
497
498 static void
499 xdg_toplevel_v6_handle_resource_destroy(struct wl_resource *resource)
500 {
501     struct ds_xdg_toplevel_v6 *toplevel;
502
503     toplevel = wl_resource_get_user_data(resource);
504     if (!toplevel)
505         return;
506
507     destroy_xdg_surface_v6_role(toplevel->base);
508 }
509
510 static void
511 xdg_toplevel_v6_handle_parent_unmap(struct wl_listener *listener, void *data)
512 {
513     struct ds_xdg_toplevel_v6 *toplevel;
514
515     toplevel = wl_container_of(listener, toplevel, parent_unmap);
516     xdg_toplevel_v6_set_parent(toplevel, toplevel->parent->parent);
517 }
518
519 static void
520 xdg_toplevel_v6_set_parent(struct ds_xdg_toplevel_v6 *toplevel,
521         struct ds_xdg_toplevel_v6 *parent)
522 {
523     struct ds_xdg_toplevel_v6 *iter = parent;
524
525     while (iter) {
526         if (iter == toplevel)
527             return;
528         iter = iter->parent;
529     }
530
531     if (toplevel->parent)
532         wl_list_remove(&toplevel->parent_unmap.link);
533
534     if (parent && parent->base->mapped) {
535         toplevel->parent = parent;
536         toplevel->parent_unmap.notify = xdg_toplevel_v6_handle_parent_unmap;
537         wl_signal_add(&toplevel->parent->base->events.unmap,
538                 &toplevel->parent_unmap);
539     }
540     else {
541         toplevel->parent = NULL;
542     }
543
544     wl_signal_emit_mutable(&toplevel->events.set_parent, NULL);
545 }