shell: Introduce fullscreen and split role type of a surface
[src/agl-compositor.git] / src / shell.c
1 /*
2  * Copyright © 2019 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "ivi-compositor.h"
27 #include "policy.h"
28
29 #include <assert.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <libweston/libweston.h>
38 #include <libweston/config-parser.h>
39
40 #include "shared/os-compatibility.h"
41
42 #include "agl-shell-server-protocol.h"
43 #include "agl-shell-desktop-server-protocol.h"
44
45 static void
46 create_black_surface_view(struct ivi_output *output);
47
48 static void
49 insert_black_surface(struct ivi_output *output);
50
51 void
52 ivi_set_desktop_surface(struct ivi_surface *surface)
53 {
54         struct desktop_client *dclient;
55         struct ivi_compositor *ivi = surface->ivi;
56         assert(surface->role == IVI_SURFACE_ROLE_NONE);
57
58         surface->role = IVI_SURFACE_ROLE_DESKTOP;
59         wl_list_insert(&surface->ivi->surfaces, &surface->link);
60
61         /* advertise to all desktop clients the new surface */
62         wl_list_for_each(dclient, &ivi->desktop_clients, link) {
63                 const char *app_id =
64                         weston_desktop_surface_get_app_id(surface->dsurface);
65                 agl_shell_desktop_send_application(dclient->resource, app_id);
66         }
67 }
68
69 static void
70 ivi_set_desktop_surface_popup(struct ivi_surface *surface)
71 {
72         struct ivi_compositor *ivi = surface->ivi;
73         assert(surface->role == IVI_SURFACE_ROLE_NONE);
74
75         surface->role = IVI_SURFACE_ROLE_POPUP;
76         wl_list_insert(&ivi->surfaces, &surface->link);
77 }
78
79 static void
80 ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface)
81 {
82         struct ivi_compositor *ivi = surface->ivi;
83         assert(surface->role == IVI_SURFACE_ROLE_NONE);
84
85         surface->role = IVI_SURFACE_ROLE_FULLSCREEN;
86         wl_list_insert(&ivi->surfaces, &surface->link);
87 }
88
89 static void
90 ivi_set_desktop_surface_split(struct ivi_surface *surface)
91 {
92         struct ivi_compositor *ivi = surface->ivi;
93         assert(surface->role == IVI_SURFACE_ROLE_NONE);
94
95         if (surface->split.orientation == AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL)
96                 surface->role = IVI_SURFACE_ROLE_SPLIT_V;
97         else
98                 surface->role = IVI_SURFACE_ROLE_SPLIT_H;
99
100         wl_list_insert(&ivi->surfaces, &surface->link);
101 }
102
103 static void
104 ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput,
105                                       int x, int y, const char *app_id)
106 {
107         struct ivi_compositor *ivi = ioutput->ivi;
108         size_t len_app_id = strlen(app_id);
109
110         struct pending_popup *p_popup = zalloc(sizeof(*p_popup));
111
112         p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
113         memcpy(p_popup->app_id, app_id, len_app_id);
114         p_popup->ioutput = ioutput;
115         p_popup->x = x;
116         p_popup->y = y;
117
118         wl_list_insert(&ivi->popup_pending_apps, &p_popup->link);
119 }
120
121 static void
122 ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput,
123                                            const char *app_id)
124 {
125         struct ivi_compositor *ivi = ioutput->ivi;
126         size_t len_app_id = strlen(app_id);
127
128         struct pending_fullscreen *fs = zalloc(sizeof(*fs));
129
130         fs->app_id = zalloc(sizeof(char) * (len_app_id + 1));
131         memcpy(fs->app_id, app_id, len_app_id);
132
133         fs->ioutput = ioutput;
134
135         wl_list_insert(&ivi->fullscreen_pending_apps, &fs->link);
136 }
137
138 static void
139 ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput,
140                                       const char *app_id, uint32_t orientation)
141 {
142         struct ivi_compositor *ivi = ioutput->ivi;
143         size_t len_app_id = strlen(app_id);
144
145         if (orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL &&
146             orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL)
147                 return;
148
149         struct pending_split *split = zalloc(sizeof(*split));
150
151         split->app_id = zalloc(sizeof(char) * (len_app_id + 1));
152         memcpy(split->app_id, app_id, len_app_id);
153
154         split->ioutput = ioutput;
155         split->orientation = orientation;
156
157         wl_list_insert(&ivi->split_pending_apps, &split->link);
158 }
159
160 static void
161 ivi_remove_pending_desktop_surface_split(struct pending_split *split)
162 {
163         free(split->app_id);
164         wl_list_remove(&split->link);
165         free(split);
166 }
167
168 static void
169 ivi_remove_pending_desktop_surface_fullscreen(struct pending_fullscreen *fs)
170 {
171         free(fs->app_id);
172         wl_list_remove(&fs->link);
173         free(fs);
174 }
175
176 static void
177 ivi_remove_pending_desktop_surface_popup(struct pending_popup *p_popup)
178 {
179         free(p_popup->app_id);
180         wl_list_remove(&p_popup->link);
181         free(p_popup);
182 }
183
184 static bool
185 ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface)
186 {
187         struct ivi_compositor *ivi = surface->ivi;
188         struct pending_popup *p_popup, *next_p_popup;
189         const char *_app_id =
190                         weston_desktop_surface_get_app_id(surface->dsurface);
191
192         if (wl_list_empty(&ivi->popup_pending_apps))
193                 return false;
194
195         wl_list_for_each_safe(p_popup, next_p_popup,
196                               &ivi->popup_pending_apps, link) {
197                 if (!strcmp(_app_id, p_popup->app_id)) {
198                         surface->popup.output = p_popup->ioutput;
199                         surface->popup.x = p_popup->x;
200                         surface->popup.y = p_popup->y;
201                         ivi_remove_pending_desktop_surface_popup(p_popup);
202                         return true;
203                 }
204         }
205
206         return false;
207 }
208
209 static bool
210 ivi_check_pending_desktop_surface_split(struct ivi_surface *surface)
211 {
212         struct pending_split *split_surf, *next_split_surf;
213         struct ivi_compositor *ivi = surface->ivi;
214         const char *_app_id =
215                         weston_desktop_surface_get_app_id(surface->dsurface);
216
217         if (wl_list_empty(&ivi->split_pending_apps))
218                 return false;
219
220         wl_list_for_each_safe(split_surf, next_split_surf,
221                               &ivi->split_pending_apps, link) {
222                 if (!strcmp(_app_id, split_surf->app_id)) {
223                         surface->split.output = split_surf->ioutput;
224                         surface->split.orientation = split_surf->orientation;
225                         ivi_remove_pending_desktop_surface_split(split_surf);
226                         return true;
227                 }
228         }
229
230         return false;
231 }
232
233 static bool
234 ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface)
235 {
236         struct pending_fullscreen *fs_surf, *next_fs_surf;
237         struct ivi_compositor *ivi = surface->ivi;
238         const char *_app_id =
239                         weston_desktop_surface_get_app_id(surface->dsurface);
240
241         if (wl_list_empty(&ivi->fullscreen_pending_apps))
242                 return false;
243
244         wl_list_for_each_safe(fs_surf, next_fs_surf,
245                               &ivi->fullscreen_pending_apps, link) {
246                 if (!strcmp(_app_id, fs_surf->app_id)) {
247                         surface->fullscreen.output = fs_surf->ioutput;
248                         ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
249                         return true;
250                 }
251         }
252
253         return false;
254 }
255
256 void
257 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
258 {
259         bool ret = false;
260
261         ret = ivi_check_pending_desktop_surface_popup(surface);
262         if (ret) {
263                 ivi_set_desktop_surface_popup(surface);
264                 return;
265         }
266
267         ret = ivi_check_pending_desktop_surface_split(surface);
268         if (ret) {
269                 ivi_set_desktop_surface_split(surface);
270                 return;
271         }
272
273         ret = ivi_check_pending_desktop_surface_fullscreen(surface);
274         if (ret) {
275                 ivi_set_desktop_surface_fullscreen(surface);
276                 return;
277         }
278
279         /* if we end up here means we have a regular desktop app */
280         ivi_set_desktop_surface(surface);
281 }
282
283 void
284 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
285 {
286         struct ivi_output *out;
287
288         wl_list_for_each(out, &ivi->outputs, link) {
289                 create_black_surface_view(out);
290                 insert_black_surface(out);
291         }
292 }
293
294 int
295 ivi_shell_init(struct ivi_compositor *ivi)
296 {
297         weston_layer_init(&ivi->hidden, ivi->compositor);
298         weston_layer_init(&ivi->background, ivi->compositor);
299         weston_layer_init(&ivi->normal, ivi->compositor);
300         weston_layer_init(&ivi->panel, ivi->compositor);
301         weston_layer_init(&ivi->popup, ivi->compositor);
302         weston_layer_init(&ivi->fullscreen, ivi->compositor);
303
304         weston_layer_set_position(&ivi->hidden,
305                                   WESTON_LAYER_POSITION_HIDDEN);
306         weston_layer_set_position(&ivi->background,
307                                   WESTON_LAYER_POSITION_BACKGROUND);
308         weston_layer_set_position(&ivi->normal,
309                                   WESTON_LAYER_POSITION_NORMAL);
310         weston_layer_set_position(&ivi->panel,
311                                   WESTON_LAYER_POSITION_UI);
312         weston_layer_set_position(&ivi->popup,
313                                   WESTON_LAYER_POSITION_TOP_UI);
314         weston_layer_set_position(&ivi->fullscreen,
315                                   WESTON_LAYER_POSITION_FULLSCREEN);
316
317         return 0;
318 }
319
320 static void
321 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
322 {
323         struct ivi_surface *surface;
324
325         wl_list_for_each(surface, &ivi->surfaces, link) {
326                 const char *app_id =
327                         weston_desktop_surface_get_app_id(surface->dsurface);
328                 agl_shell_desktop_send_application(resource, app_id);
329         }
330 }
331
332 static void
333 client_exec(const char *command, int fd)
334 {
335         sigset_t sig;
336         char s[32];
337
338         /* Don't give the child our signal mask */
339         sigfillset(&sig);
340         sigprocmask(SIG_UNBLOCK, &sig, NULL);
341
342         /* Launch clients as the user; don't give them the wrong euid */
343         if (seteuid(getuid()) == -1) {
344                 weston_log("seteuid failed: %s\n", strerror(errno));
345                 return;
346         }
347
348         /* Duplicate fd to unset the CLOEXEC flag. We don't need to worry about
349          * clobbering fd, as we'll exit/exec either way.
350          */
351         fd = dup(fd);
352         if (fd == -1) {
353                 weston_log("dup failed: %s\n", strerror(errno));
354                 return;
355         }
356
357         snprintf(s, sizeof s, "%d", fd);
358         setenv("WAYLAND_SOCKET", s, 1);
359
360         execl("/bin/sh", "/bin/sh", "-c", command, NULL);
361         weston_log("executing '%s' failed: %s", command, strerror(errno));
362 }
363
364 static struct wl_client *
365 launch_shell_client(struct ivi_compositor *ivi, const char *command)
366 {
367         struct wl_client *client;
368         int sock[2];
369         pid_t pid;
370
371         weston_log("launching' %s'\n", command);
372
373         if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
374                 weston_log("socketpair failed while launching '%s': %s\n",
375                            command, strerror(errno));
376                 return NULL;
377         }
378
379         pid = fork();
380         if (pid == -1) {
381                 close(sock[0]);
382                 close(sock[1]);
383                 weston_log("fork failed while launching '%s': %s\n",
384                            command, strerror(errno));
385                 return NULL;
386         }
387
388         if (pid == 0) {
389                 client_exec(command, sock[1]);
390                 _Exit(EXIT_FAILURE);
391         }
392         close(sock[1]);
393
394         client = wl_client_create(ivi->compositor->wl_display, sock[0]);
395         if (!client) {
396                 close(sock[0]);
397                 weston_log("Failed to create wayland client for '%s'",
398                            command);
399                 return NULL;
400         }
401
402         return client;
403 }
404
405 int
406 ivi_launch_shell_client(struct ivi_compositor *ivi)
407 {
408         struct weston_config_section *section;
409         char *command = NULL;
410
411         section = weston_config_get_section(ivi->config, "shell-client",
412                                             NULL, NULL);
413         if (section)
414                 weston_config_section_get_string(section, "command",
415                                                  &command, NULL);
416
417         if (!command)
418                 return -1;
419
420         ivi->shell_client.client = launch_shell_client(ivi, command);
421         if (!ivi->shell_client.client)
422                 return -1;
423
424         return 0;
425 }
426
427 static void
428 destroy_black_view(struct wl_listener *listener, void *data)
429 {
430         struct fullscreen_view *fs =
431                 wl_container_of(listener, fs, fs_destroy);
432
433
434         if (fs && fs->fs) {
435                 if (fs->fs->view && fs->fs->view->surface) {
436                         weston_surface_destroy(fs->fs->view->surface);
437                         fs->fs->view = NULL;
438                 }
439
440                 free(fs->fs);
441                 wl_list_remove(&fs->fs_destroy.link);
442         }
443 }
444
445
446 static void
447 create_black_surface_view(struct ivi_output *output)
448 {
449         struct weston_surface *surface = NULL;
450         struct weston_view *view;
451         struct ivi_compositor *ivi = output->ivi;
452         struct weston_compositor *wc= ivi->compositor;
453         struct weston_output *woutput = output->output;
454
455         surface = weston_surface_create(wc);
456         view = weston_view_create(surface);
457
458         assert(view || surface);
459
460         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
461         weston_surface_set_size(surface, woutput->width, woutput->height);
462         weston_view_set_position(view, woutput->x, woutput->y);
463
464         output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
465         output->fullscreen_view.fs->view = view;
466
467         output->fullscreen_view.fs_destroy.notify = destroy_black_view;
468         wl_signal_add(&woutput->destroy_signal,
469                       &output->fullscreen_view.fs_destroy);
470 }
471
472 static void
473 remove_black_surface(struct ivi_output *output)
474 {
475         struct weston_view *view = output->fullscreen_view.fs->view;
476
477         assert(view->is_mapped == true ||
478                view->surface->is_mapped == true);
479
480         view->is_mapped = false;
481         view->surface->is_mapped = false;
482
483         weston_layer_entry_remove(&view->layer_link);
484         weston_view_update_transform(view);
485
486         weston_output_damage(output->output);
487 }
488
489 static void
490 insert_black_surface(struct ivi_output *output)
491 {
492         struct weston_view *view = output->fullscreen_view.fs->view;
493
494         if (view->is_mapped || view->surface->is_mapped)
495                 return;
496
497         weston_layer_entry_remove(&view->layer_link);
498         weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
499                                   &view->layer_link);
500
501         view->is_mapped = true;
502         view->surface->is_mapped = true;
503
504         weston_view_update_transform(view);
505         weston_output_damage(output->output);
506 }
507
508 static void
509 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
510 {
511         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
512         struct ivi_output *output;
513         struct ivi_surface *surface, *tmp;
514
515         /* Init already finished. Do nothing */
516         if (ivi->shell_client.ready)
517                 return;
518
519         ivi->shell_client.ready = true;
520
521         wl_list_for_each(output, &ivi->outputs, link) {
522                 remove_black_surface(output);
523                 ivi_layout_init(ivi, output);
524         }
525
526         wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
527                 wl_list_remove(&surface->link);
528
529                 if (ivi_check_pending_desktop_surface_popup(surface)) {
530                         ivi_set_desktop_surface_popup(surface);
531                 } else {
532                         ivi_set_desktop_surface(surface);
533                         ivi_layout_desktop_committed(surface);
534                 }
535         }
536 }
537
538 static void
539 shell_set_background(struct wl_client *client,
540                      struct wl_resource *shell_res,
541                      struct wl_resource *surface_res,
542                      struct wl_resource *output_res)
543 {
544         struct weston_head *head = weston_head_from_resource(output_res);
545         struct weston_output *woutput = weston_head_get_output(head);
546         struct ivi_output *output = to_ivi_output(woutput);
547         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
548         struct weston_desktop_surface *dsurface;
549         struct ivi_surface *surface;
550
551         dsurface = weston_surface_get_desktop_surface(wsurface);
552         if (!dsurface) {
553                 wl_resource_post_error(shell_res,
554                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
555                                        "surface must be a desktop surface");
556                 return;
557         }
558
559         surface = weston_desktop_surface_get_user_data(dsurface);
560         if (surface->role != IVI_SURFACE_ROLE_NONE) {
561                 wl_resource_post_error(shell_res,
562                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
563                                        "surface already has another ivi role");
564                 return;
565         }
566
567         if (output->background) {
568                 wl_resource_post_error(shell_res,
569                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
570                                        "output already has background");
571                 return;
572         }
573
574         surface->role = IVI_SURFACE_ROLE_BACKGROUND;
575         surface->bg.output = output;
576         wl_list_remove(&surface->link);
577         wl_list_init(&surface->link);
578
579         output->background = surface;
580
581         weston_desktop_surface_set_maximized(dsurface, true);
582         weston_desktop_surface_set_size(dsurface,
583                                         output->output->width,
584                                         output->output->height);
585 }
586
587 static void
588 shell_set_panel(struct wl_client *client,
589                 struct wl_resource *shell_res,
590                 struct wl_resource *surface_res,
591                 struct wl_resource *output_res,
592                 uint32_t edge)
593 {
594         struct weston_head *head = weston_head_from_resource(output_res);
595         struct weston_output *woutput = weston_head_get_output(head);
596         struct ivi_output *output = to_ivi_output(woutput);
597         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
598         struct weston_desktop_surface *dsurface;
599         struct ivi_surface *surface;
600         struct ivi_surface **member;
601         int32_t width = 0, height = 0;
602
603         dsurface = weston_surface_get_desktop_surface(wsurface);
604         if (!dsurface) {
605                 wl_resource_post_error(shell_res,
606                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
607                                        "surface must be a desktop surface");
608                 return;
609         }
610
611         surface = weston_desktop_surface_get_user_data(dsurface);
612         if (surface->role != IVI_SURFACE_ROLE_NONE) {
613                 wl_resource_post_error(shell_res,
614                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
615                                        "surface already has another ivi role");
616                 return;
617         }
618
619         switch (edge) {
620         case AGL_SHELL_EDGE_TOP:
621                 member = &output->top;
622                 break;
623         case AGL_SHELL_EDGE_BOTTOM:
624                 member = &output->bottom;
625                 break;
626         case AGL_SHELL_EDGE_LEFT:
627                 member = &output->left;
628                 break;
629         case AGL_SHELL_EDGE_RIGHT:
630                 member = &output->right;
631                 break;
632         default:
633                 wl_resource_post_error(shell_res,
634                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
635                                        "invalid edge for panel");
636                 return;
637         }
638
639         if (*member) {
640                 wl_resource_post_error(shell_res,
641                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
642                                        "output already has panel on this edge");
643                 return;
644         }
645
646         surface->role = IVI_SURFACE_ROLE_PANEL;
647         surface->panel.output = output;
648         surface->panel.edge = edge;
649         wl_list_remove(&surface->link);
650         wl_list_init(&surface->link);
651
652         *member = surface;
653
654         switch (surface->panel.edge) {
655         case AGL_SHELL_EDGE_TOP:
656         case AGL_SHELL_EDGE_BOTTOM:
657                 width = woutput->width;
658                 break;
659         case AGL_SHELL_EDGE_LEFT:
660         case AGL_SHELL_EDGE_RIGHT:
661                 height = woutput->height;
662                 break;
663         }
664
665         weston_desktop_surface_set_size(dsurface, width, height);
666 }
667
668
669 static void
670 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
671                           const char *data, uint32_t app_state)
672 {
673         struct desktop_client *dclient;
674         uint32_t app_role;
675         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
676         struct ivi_policy *policy = ivi->policy;
677
678         /* FIXME: should queue it here and see when binding agl-shell-desktop
679          * if there are any to be sent */
680         if (!surf)
681                 return;
682
683         if (policy && policy->api.surface_advertise_state_change &&
684             !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
685                 return;
686         }
687
688         app_role = surf->role;
689         if (app_role == IVI_SURFACE_ROLE_POPUP)
690                 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
691
692         wl_list_for_each(dclient, &ivi->desktop_clients, link)
693                 agl_shell_desktop_send_state_app(dclient->resource, app_id,
694                                                  data, app_state, app_role);
695 }
696
697 static void
698 shell_activate_app(struct wl_client *client,
699                    struct wl_resource *shell_res,
700                    const char *app_id,
701                    struct wl_resource *output_res)
702 {
703         struct weston_head *head = weston_head_from_resource(output_res);
704         struct weston_output *woutput = weston_head_get_output(head);
705         struct ivi_output *output = to_ivi_output(woutput);
706
707         ivi_layout_activate(output, app_id);
708 }
709
710 static void
711 shell_desktop_activate_app(struct wl_client *client,
712                            struct wl_resource *shell_res,
713                            const char *app_id, const char *data,
714                            struct wl_resource *output_res)
715 {
716         struct weston_head *head = weston_head_from_resource(output_res);
717         struct weston_output *woutput = weston_head_get_output(head);
718         struct ivi_output *output = to_ivi_output(woutput);
719
720         ivi_layout_activate(output, app_id);
721         shell_advertise_app_state(output->ivi, app_id,
722                                   data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
723 }
724
725 static void
726 shell_deactivate_app(struct wl_client *client,
727                    struct wl_resource *shell_res,
728                    const char *app_id)
729 {
730         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
731         struct ivi_compositor *ivi = dclient->ivi;
732
733         ivi_layout_deactivate(ivi, app_id);
734         shell_advertise_app_state(ivi, app_id,
735                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
736 }
737
738 static const struct agl_shell_interface agl_shell_implementation = {
739         .ready = shell_ready,
740         .set_background = shell_set_background,
741         .set_panel = shell_set_panel,
742         .activate_app = shell_activate_app,
743 };
744
745 static void
746 shell_desktop_set_app_property(struct wl_client *client,
747                                struct wl_resource *shell_res,
748                                const char *app_id, uint32_t role,
749                                int x, int y, struct wl_resource *output_res)
750 {
751         struct weston_head *head = weston_head_from_resource(output_res);
752         struct weston_output *woutput = weston_head_get_output(head);
753         struct ivi_output *output = to_ivi_output(woutput);
754
755         switch (role) {
756         case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
757                 ivi_set_pending_desktop_surface_popup(output, x, y, app_id);
758                 break;
759         case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
760                 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
761                 break;
762         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
763         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
764                 ivi_set_pending_desktop_surface_split(output, app_id, role);
765                 break;
766         default:
767                 break;
768         }
769 }
770
771 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
772         .activate_app = shell_desktop_activate_app,
773         .set_app_property = shell_desktop_set_app_property,
774         .deactivate_app = shell_deactivate_app,
775 };
776
777 static void
778 unbind_agl_shell(struct wl_resource *resource)
779 {
780         struct ivi_compositor *ivi;
781         struct ivi_output *output;
782         struct ivi_surface *surf, *surf_tmp;
783
784         ivi = wl_resource_get_user_data(resource);
785         wl_list_for_each(output, &ivi->outputs, link) {
786                 /* reset the active surf if there's one present */
787                 if (output->active) {
788                         output->active->view->is_mapped = false;
789                         output->active->view->surface->is_mapped = false;
790
791                         weston_layer_entry_remove(&output->active->view->layer_link);
792                         output->active = NULL;
793                 }
794
795                 insert_black_surface(output);
796         }
797
798         wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
799                 wl_list_remove(&surf->link);
800                 wl_list_init(&surf->link);
801         }
802
803         wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
804                 wl_list_remove(&surf->link);
805                 wl_list_init(&surf->link);
806         }
807
808         wl_list_init(&ivi->surfaces);
809         wl_list_init(&ivi->pending_surfaces);
810
811         ivi->shell_client.ready = false;
812         ivi->shell_client.resource = NULL;
813         ivi->shell_client.client = NULL;
814 }
815
816 static void
817 bind_agl_shell(struct wl_client *client,
818                void *data, uint32_t version, uint32_t id)
819 {
820         struct ivi_compositor *ivi = data;
821         struct wl_resource *resource;
822
823         resource = wl_resource_create(client, &agl_shell_interface,
824                                       1, id);
825         if (!resource) {
826                 wl_client_post_no_memory(client);
827                 return;
828         }
829
830 #if 0
831         if (ivi->shell_client.client != client) {
832                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
833                                        "client not authorized to use agl_shell");
834                 return;
835         }
836 #endif
837
838         if (ivi->shell_client.resource) {
839                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
840                                        "agl_shell has already been bound");
841                 return;
842         }
843
844         wl_resource_set_implementation(resource, &agl_shell_implementation,
845                                        ivi, unbind_agl_shell);
846         ivi->shell_client.resource = resource;
847 }
848
849 static void
850 unbind_agl_shell_desktop(struct wl_resource *resource)
851 {
852         struct desktop_client *dclient = wl_resource_get_user_data(resource);
853
854         wl_list_remove(&dclient->link);
855         free(dclient);
856 }
857
858 static void
859 bind_agl_shell_desktop(struct wl_client *client,
860                        void *data, uint32_t version, uint32_t id)
861 {
862         struct ivi_compositor *ivi = data;
863         struct wl_resource *resource;
864         struct desktop_client *dclient = zalloc(sizeof(*dclient));
865
866         if (!dclient) {
867                 wl_client_post_no_memory(client);
868                 return;
869         }
870
871         resource = wl_resource_create(client, &agl_shell_desktop_interface,
872                                       version, id);
873         dclient->ivi = ivi;
874         if (!resource) {
875                 wl_client_post_no_memory(client);
876                 return;
877         }
878
879         wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
880                                        dclient, unbind_agl_shell_desktop);
881
882         dclient->resource = resource;
883         wl_list_insert(&ivi->desktop_clients, &dclient->link);
884
885         /* advertise xdg surfaces */
886         ivi_shell_advertise_xdg_surfaces(ivi, resource);
887 }
888
889 int
890 ivi_shell_create_global(struct ivi_compositor *ivi)
891 {
892         ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
893                                           &agl_shell_interface, 1,
894                                           ivi, bind_agl_shell);
895         if (!ivi->agl_shell) {
896                 weston_log("Failed to create wayland global.\n");
897                 return -1;
898         }
899
900         ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
901                                                   &agl_shell_desktop_interface, 1,
902                                                   ivi, bind_agl_shell_desktop);
903         if (!ivi->agl_shell_desktop) {
904                 weston_log("Failed to create wayland global (agl_shell_desktop).\n");
905                 return -1;
906         }
907
908         return 0;
909 }