shell: Determine the role type
[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 and
280          * try to activate it */
281         ivi_set_desktop_surface(surface);
282         ivi_layout_desktop_committed(surface);
283 }
284
285 void
286 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
287 {
288         struct ivi_output *out;
289
290         wl_list_for_each(out, &ivi->outputs, link) {
291                 create_black_surface_view(out);
292                 insert_black_surface(out);
293         }
294 }
295
296 int
297 ivi_shell_init(struct ivi_compositor *ivi)
298 {
299         weston_layer_init(&ivi->hidden, ivi->compositor);
300         weston_layer_init(&ivi->background, ivi->compositor);
301         weston_layer_init(&ivi->normal, ivi->compositor);
302         weston_layer_init(&ivi->panel, ivi->compositor);
303         weston_layer_init(&ivi->popup, ivi->compositor);
304         weston_layer_init(&ivi->fullscreen, ivi->compositor);
305
306         weston_layer_set_position(&ivi->hidden,
307                                   WESTON_LAYER_POSITION_HIDDEN);
308         weston_layer_set_position(&ivi->background,
309                                   WESTON_LAYER_POSITION_BACKGROUND);
310         weston_layer_set_position(&ivi->normal,
311                                   WESTON_LAYER_POSITION_NORMAL);
312         weston_layer_set_position(&ivi->panel,
313                                   WESTON_LAYER_POSITION_UI);
314         weston_layer_set_position(&ivi->popup,
315                                   WESTON_LAYER_POSITION_TOP_UI);
316         weston_layer_set_position(&ivi->fullscreen,
317                                   WESTON_LAYER_POSITION_FULLSCREEN);
318
319         return 0;
320 }
321
322 static void
323 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
324 {
325         struct ivi_surface *surface;
326
327         wl_list_for_each(surface, &ivi->surfaces, link) {
328                 const char *app_id =
329                         weston_desktop_surface_get_app_id(surface->dsurface);
330                 agl_shell_desktop_send_application(resource, app_id);
331         }
332 }
333
334 static void
335 client_exec(const char *command, int fd)
336 {
337         sigset_t sig;
338         char s[32];
339
340         /* Don't give the child our signal mask */
341         sigfillset(&sig);
342         sigprocmask(SIG_UNBLOCK, &sig, NULL);
343
344         /* Launch clients as the user; don't give them the wrong euid */
345         if (seteuid(getuid()) == -1) {
346                 weston_log("seteuid failed: %s\n", strerror(errno));
347                 return;
348         }
349
350         /* Duplicate fd to unset the CLOEXEC flag. We don't need to worry about
351          * clobbering fd, as we'll exit/exec either way.
352          */
353         fd = dup(fd);
354         if (fd == -1) {
355                 weston_log("dup failed: %s\n", strerror(errno));
356                 return;
357         }
358
359         snprintf(s, sizeof s, "%d", fd);
360         setenv("WAYLAND_SOCKET", s, 1);
361
362         execl("/bin/sh", "/bin/sh", "-c", command, NULL);
363         weston_log("executing '%s' failed: %s", command, strerror(errno));
364 }
365
366 static struct wl_client *
367 launch_shell_client(struct ivi_compositor *ivi, const char *command)
368 {
369         struct wl_client *client;
370         int sock[2];
371         pid_t pid;
372
373         weston_log("launching' %s'\n", command);
374
375         if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
376                 weston_log("socketpair failed while launching '%s': %s\n",
377                            command, strerror(errno));
378                 return NULL;
379         }
380
381         pid = fork();
382         if (pid == -1) {
383                 close(sock[0]);
384                 close(sock[1]);
385                 weston_log("fork failed while launching '%s': %s\n",
386                            command, strerror(errno));
387                 return NULL;
388         }
389
390         if (pid == 0) {
391                 client_exec(command, sock[1]);
392                 _Exit(EXIT_FAILURE);
393         }
394         close(sock[1]);
395
396         client = wl_client_create(ivi->compositor->wl_display, sock[0]);
397         if (!client) {
398                 close(sock[0]);
399                 weston_log("Failed to create wayland client for '%s'",
400                            command);
401                 return NULL;
402         }
403
404         return client;
405 }
406
407 int
408 ivi_launch_shell_client(struct ivi_compositor *ivi)
409 {
410         struct weston_config_section *section;
411         char *command = NULL;
412
413         section = weston_config_get_section(ivi->config, "shell-client",
414                                             NULL, NULL);
415         if (section)
416                 weston_config_section_get_string(section, "command",
417                                                  &command, NULL);
418
419         if (!command)
420                 return -1;
421
422         ivi->shell_client.client = launch_shell_client(ivi, command);
423         if (!ivi->shell_client.client)
424                 return -1;
425
426         return 0;
427 }
428
429 static void
430 destroy_black_view(struct wl_listener *listener, void *data)
431 {
432         struct fullscreen_view *fs =
433                 wl_container_of(listener, fs, fs_destroy);
434
435
436         if (fs && fs->fs) {
437                 if (fs->fs->view && fs->fs->view->surface) {
438                         weston_surface_destroy(fs->fs->view->surface);
439                         fs->fs->view = NULL;
440                 }
441
442                 free(fs->fs);
443                 wl_list_remove(&fs->fs_destroy.link);
444         }
445 }
446
447
448 static void
449 create_black_surface_view(struct ivi_output *output)
450 {
451         struct weston_surface *surface = NULL;
452         struct weston_view *view;
453         struct ivi_compositor *ivi = output->ivi;
454         struct weston_compositor *wc= ivi->compositor;
455         struct weston_output *woutput = output->output;
456
457         surface = weston_surface_create(wc);
458         view = weston_view_create(surface);
459
460         assert(view || surface);
461
462         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
463         weston_surface_set_size(surface, woutput->width, woutput->height);
464         weston_view_set_position(view, woutput->x, woutput->y);
465
466         output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
467         output->fullscreen_view.fs->view = view;
468
469         output->fullscreen_view.fs_destroy.notify = destroy_black_view;
470         wl_signal_add(&woutput->destroy_signal,
471                       &output->fullscreen_view.fs_destroy);
472 }
473
474 static void
475 remove_black_surface(struct ivi_output *output)
476 {
477         struct weston_view *view = output->fullscreen_view.fs->view;
478
479         assert(view->is_mapped == true ||
480                view->surface->is_mapped == true);
481
482         view->is_mapped = false;
483         view->surface->is_mapped = false;
484
485         weston_layer_entry_remove(&view->layer_link);
486         weston_view_update_transform(view);
487
488         weston_output_damage(output->output);
489 }
490
491 static void
492 insert_black_surface(struct ivi_output *output)
493 {
494         struct weston_view *view = output->fullscreen_view.fs->view;
495
496         if (view->is_mapped || view->surface->is_mapped)
497                 return;
498
499         weston_layer_entry_remove(&view->layer_link);
500         weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
501                                   &view->layer_link);
502
503         view->is_mapped = true;
504         view->surface->is_mapped = true;
505
506         weston_view_update_transform(view);
507         weston_output_damage(output->output);
508 }
509
510 static void
511 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
512 {
513         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
514         struct ivi_output *output;
515         struct ivi_surface *surface, *tmp;
516
517         /* Init already finished. Do nothing */
518         if (ivi->shell_client.ready)
519                 return;
520
521         ivi->shell_client.ready = true;
522
523         wl_list_for_each(output, &ivi->outputs, link) {
524                 remove_black_surface(output);
525                 ivi_layout_init(ivi, output);
526         }
527
528         wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
529                 wl_list_remove(&surface->link);
530                 ivi_check_pending_desktop_surface(surface);
531         }
532 }
533
534 static void
535 shell_set_background(struct wl_client *client,
536                      struct wl_resource *shell_res,
537                      struct wl_resource *surface_res,
538                      struct wl_resource *output_res)
539 {
540         struct weston_head *head = weston_head_from_resource(output_res);
541         struct weston_output *woutput = weston_head_get_output(head);
542         struct ivi_output *output = to_ivi_output(woutput);
543         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
544         struct weston_desktop_surface *dsurface;
545         struct ivi_surface *surface;
546
547         dsurface = weston_surface_get_desktop_surface(wsurface);
548         if (!dsurface) {
549                 wl_resource_post_error(shell_res,
550                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
551                                        "surface must be a desktop surface");
552                 return;
553         }
554
555         surface = weston_desktop_surface_get_user_data(dsurface);
556         if (surface->role != IVI_SURFACE_ROLE_NONE) {
557                 wl_resource_post_error(shell_res,
558                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
559                                        "surface already has another ivi role");
560                 return;
561         }
562
563         if (output->background) {
564                 wl_resource_post_error(shell_res,
565                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
566                                        "output already has background");
567                 return;
568         }
569
570         surface->role = IVI_SURFACE_ROLE_BACKGROUND;
571         surface->bg.output = output;
572         wl_list_remove(&surface->link);
573         wl_list_init(&surface->link);
574
575         output->background = surface;
576
577         weston_desktop_surface_set_maximized(dsurface, true);
578         weston_desktop_surface_set_size(dsurface,
579                                         output->output->width,
580                                         output->output->height);
581 }
582
583 static void
584 shell_set_panel(struct wl_client *client,
585                 struct wl_resource *shell_res,
586                 struct wl_resource *surface_res,
587                 struct wl_resource *output_res,
588                 uint32_t edge)
589 {
590         struct weston_head *head = weston_head_from_resource(output_res);
591         struct weston_output *woutput = weston_head_get_output(head);
592         struct ivi_output *output = to_ivi_output(woutput);
593         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
594         struct weston_desktop_surface *dsurface;
595         struct ivi_surface *surface;
596         struct ivi_surface **member;
597         int32_t width = 0, height = 0;
598
599         dsurface = weston_surface_get_desktop_surface(wsurface);
600         if (!dsurface) {
601                 wl_resource_post_error(shell_res,
602                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
603                                        "surface must be a desktop surface");
604                 return;
605         }
606
607         surface = weston_desktop_surface_get_user_data(dsurface);
608         if (surface->role != IVI_SURFACE_ROLE_NONE) {
609                 wl_resource_post_error(shell_res,
610                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
611                                        "surface already has another ivi role");
612                 return;
613         }
614
615         switch (edge) {
616         case AGL_SHELL_EDGE_TOP:
617                 member = &output->top;
618                 break;
619         case AGL_SHELL_EDGE_BOTTOM:
620                 member = &output->bottom;
621                 break;
622         case AGL_SHELL_EDGE_LEFT:
623                 member = &output->left;
624                 break;
625         case AGL_SHELL_EDGE_RIGHT:
626                 member = &output->right;
627                 break;
628         default:
629                 wl_resource_post_error(shell_res,
630                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
631                                        "invalid edge for panel");
632                 return;
633         }
634
635         if (*member) {
636                 wl_resource_post_error(shell_res,
637                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
638                                        "output already has panel on this edge");
639                 return;
640         }
641
642         surface->role = IVI_SURFACE_ROLE_PANEL;
643         surface->panel.output = output;
644         surface->panel.edge = edge;
645         wl_list_remove(&surface->link);
646         wl_list_init(&surface->link);
647
648         *member = surface;
649
650         switch (surface->panel.edge) {
651         case AGL_SHELL_EDGE_TOP:
652         case AGL_SHELL_EDGE_BOTTOM:
653                 width = woutput->width;
654                 break;
655         case AGL_SHELL_EDGE_LEFT:
656         case AGL_SHELL_EDGE_RIGHT:
657                 height = woutput->height;
658                 break;
659         }
660
661         weston_desktop_surface_set_size(dsurface, width, height);
662 }
663
664
665 static void
666 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
667                           const char *data, uint32_t app_state)
668 {
669         struct desktop_client *dclient;
670         uint32_t app_role;
671         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
672         struct ivi_policy *policy = ivi->policy;
673
674         /* FIXME: should queue it here and see when binding agl-shell-desktop
675          * if there are any to be sent */
676         if (!surf)
677                 return;
678
679         if (policy && policy->api.surface_advertise_state_change &&
680             !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
681                 return;
682         }
683
684         app_role = surf->role;
685         if (app_role == IVI_SURFACE_ROLE_POPUP)
686                 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
687
688         wl_list_for_each(dclient, &ivi->desktop_clients, link)
689                 agl_shell_desktop_send_state_app(dclient->resource, app_id,
690                                                  data, app_state, app_role);
691 }
692
693 static void
694 shell_activate_app(struct wl_client *client,
695                    struct wl_resource *shell_res,
696                    const char *app_id,
697                    struct wl_resource *output_res)
698 {
699         struct weston_head *head = weston_head_from_resource(output_res);
700         struct weston_output *woutput = weston_head_get_output(head);
701         struct ivi_output *output = to_ivi_output(woutput);
702
703         ivi_layout_activate(output, app_id);
704 }
705
706 static void
707 shell_desktop_activate_app(struct wl_client *client,
708                            struct wl_resource *shell_res,
709                            const char *app_id, const char *data,
710                            struct wl_resource *output_res)
711 {
712         struct weston_head *head = weston_head_from_resource(output_res);
713         struct weston_output *woutput = weston_head_get_output(head);
714         struct ivi_output *output = to_ivi_output(woutput);
715
716         ivi_layout_activate(output, app_id);
717         shell_advertise_app_state(output->ivi, app_id,
718                                   data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
719 }
720
721 static void
722 shell_deactivate_app(struct wl_client *client,
723                    struct wl_resource *shell_res,
724                    const char *app_id)
725 {
726         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
727         struct ivi_compositor *ivi = dclient->ivi;
728
729         ivi_layout_deactivate(ivi, app_id);
730         shell_advertise_app_state(ivi, app_id,
731                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
732 }
733
734 static const struct agl_shell_interface agl_shell_implementation = {
735         .ready = shell_ready,
736         .set_background = shell_set_background,
737         .set_panel = shell_set_panel,
738         .activate_app = shell_activate_app,
739 };
740
741 static void
742 shell_desktop_set_app_property(struct wl_client *client,
743                                struct wl_resource *shell_res,
744                                const char *app_id, uint32_t role,
745                                int x, int y, struct wl_resource *output_res)
746 {
747         struct weston_head *head = weston_head_from_resource(output_res);
748         struct weston_output *woutput = weston_head_get_output(head);
749         struct ivi_output *output = to_ivi_output(woutput);
750
751         switch (role) {
752         case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
753                 ivi_set_pending_desktop_surface_popup(output, x, y, app_id);
754                 break;
755         case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
756                 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
757                 break;
758         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
759         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
760                 ivi_set_pending_desktop_surface_split(output, app_id, role);
761                 break;
762         default:
763                 break;
764         }
765 }
766
767 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
768         .activate_app = shell_desktop_activate_app,
769         .set_app_property = shell_desktop_set_app_property,
770         .deactivate_app = shell_deactivate_app,
771 };
772
773 static void
774 unbind_agl_shell(struct wl_resource *resource)
775 {
776         struct ivi_compositor *ivi;
777         struct ivi_output *output;
778         struct ivi_surface *surf, *surf_tmp;
779
780         ivi = wl_resource_get_user_data(resource);
781         wl_list_for_each(output, &ivi->outputs, link) {
782                 /* reset the active surf if there's one present */
783                 if (output->active) {
784                         output->active->view->is_mapped = false;
785                         output->active->view->surface->is_mapped = false;
786
787                         weston_layer_entry_remove(&output->active->view->layer_link);
788                         output->active = NULL;
789                 }
790
791                 insert_black_surface(output);
792         }
793
794         wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
795                 wl_list_remove(&surf->link);
796                 wl_list_init(&surf->link);
797         }
798
799         wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
800                 wl_list_remove(&surf->link);
801                 wl_list_init(&surf->link);
802         }
803
804         wl_list_init(&ivi->surfaces);
805         wl_list_init(&ivi->pending_surfaces);
806
807         ivi->shell_client.ready = false;
808         ivi->shell_client.resource = NULL;
809         ivi->shell_client.client = NULL;
810 }
811
812 static void
813 bind_agl_shell(struct wl_client *client,
814                void *data, uint32_t version, uint32_t id)
815 {
816         struct ivi_compositor *ivi = data;
817         struct wl_resource *resource;
818
819         resource = wl_resource_create(client, &agl_shell_interface,
820                                       1, id);
821         if (!resource) {
822                 wl_client_post_no_memory(client);
823                 return;
824         }
825
826 #if 0
827         if (ivi->shell_client.client != client) {
828                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
829                                        "client not authorized to use agl_shell");
830                 return;
831         }
832 #endif
833
834         if (ivi->shell_client.resource) {
835                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
836                                        "agl_shell has already been bound");
837                 return;
838         }
839
840         wl_resource_set_implementation(resource, &agl_shell_implementation,
841                                        ivi, unbind_agl_shell);
842         ivi->shell_client.resource = resource;
843 }
844
845 static void
846 unbind_agl_shell_desktop(struct wl_resource *resource)
847 {
848         struct desktop_client *dclient = wl_resource_get_user_data(resource);
849
850         wl_list_remove(&dclient->link);
851         free(dclient);
852 }
853
854 static void
855 bind_agl_shell_desktop(struct wl_client *client,
856                        void *data, uint32_t version, uint32_t id)
857 {
858         struct ivi_compositor *ivi = data;
859         struct wl_resource *resource;
860         struct desktop_client *dclient = zalloc(sizeof(*dclient));
861
862         if (!dclient) {
863                 wl_client_post_no_memory(client);
864                 return;
865         }
866
867         resource = wl_resource_create(client, &agl_shell_desktop_interface,
868                                       version, id);
869         dclient->ivi = ivi;
870         if (!resource) {
871                 wl_client_post_no_memory(client);
872                 return;
873         }
874
875         wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
876                                        dclient, unbind_agl_shell_desktop);
877
878         dclient->resource = resource;
879         wl_list_insert(&ivi->desktop_clients, &dclient->link);
880
881         /* advertise xdg surfaces */
882         ivi_shell_advertise_xdg_surfaces(ivi, resource);
883 }
884
885 int
886 ivi_shell_create_global(struct ivi_compositor *ivi)
887 {
888         ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
889                                           &agl_shell_interface, 1,
890                                           ivi, bind_agl_shell);
891         if (!ivi->agl_shell) {
892                 weston_log("Failed to create wayland global.\n");
893                 return -1;
894         }
895
896         ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
897                                                   &agl_shell_desktop_interface, 1,
898                                                   ivi, bind_agl_shell_desktop);
899         if (!ivi->agl_shell_desktop) {
900                 weston_log("Failed to create wayland global (agl_shell_desktop).\n");
901                 return -1;
902         }
903
904         return 0;
905 }