cb6e592ca786fb49959cf9e3e3b3760b4ff90358
[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 <weston/weston.h>
41 #include "shared/os-compatibility.h"
42 #include "shared/helpers.h"
43 #include "shared/process-util.h"
44
45 #include "agl-shell-server-protocol.h"
46 #include "agl-shell-desktop-server-protocol.h"
47
48 #ifdef HAVE_WALTHAM
49 #include <waltham-transmitter/transmitter_api.h>
50 #endif
51
52 static void
53 create_black_curtain_view(struct ivi_output *output);
54
55 void
56 agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi,
57                                            struct ivi_surface *surface)
58 {
59         struct desktop_client *dclient;
60         static bool display_adv = false;
61
62         if (surface->advertised_on_launch)
63                 return;
64
65         /* advertise to all desktop clients the new surface */
66         wl_list_for_each(dclient, &ivi->desktop_clients, link) {
67                 const char *app_id =
68                         weston_desktop_surface_get_app_id(surface->dsurface);
69                 if (app_id == NULL) {
70                         if (!display_adv) {
71                                 weston_log("WARNING app_is is null, unable to advertise\n");
72                                 display_adv = true;
73                         }
74                         return;
75                 }
76                 agl_shell_desktop_send_application(dclient->resource, app_id);
77                 surface->advertised_on_launch = true;
78         }
79 }
80
81 void
82 ivi_set_desktop_surface(struct ivi_surface *surface)
83 {
84         struct ivi_compositor *ivi = surface->ivi;
85         assert(surface->role == IVI_SURFACE_ROLE_NONE);
86
87         surface->role = IVI_SURFACE_ROLE_DESKTOP;
88         wl_list_insert(&surface->ivi->surfaces, &surface->link);
89
90         agl_shell_desktop_advertise_application_id(ivi, surface);
91 }
92
93 static void
94 ivi_set_desktop_surface_popup(struct ivi_surface *surface)
95 {
96         struct ivi_compositor *ivi = surface->ivi;
97         assert(surface->role == IVI_SURFACE_ROLE_NONE);
98
99         surface->role = IVI_SURFACE_ROLE_POPUP;
100         wl_list_insert(&ivi->surfaces, &surface->link);
101
102         agl_shell_desktop_advertise_application_id(ivi, surface);
103 }
104
105 static void
106 ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface)
107 {
108         struct ivi_compositor *ivi = surface->ivi;
109         assert(surface->role == IVI_SURFACE_ROLE_NONE);
110
111         surface->role = IVI_SURFACE_ROLE_FULLSCREEN;
112         wl_list_insert(&ivi->surfaces, &surface->link);
113
114         agl_shell_desktop_advertise_application_id(ivi, surface);
115 }
116
117 #ifdef HAVE_WALTHAM
118 void
119 ivi_destroy_waltham_destroy(struct ivi_surface *surface)
120 {
121         struct ivi_compositor *ivi = surface->ivi;
122         const struct weston_transmitter_api *api =
123                 ivi->waltham_transmitter_api;
124
125         if (!api)
126                 return;
127
128         if (surface->waltham_surface.transmitter_surface)
129                 api->surface_destroy(surface->waltham_surface.transmitter_surface);
130 }
131
132 static void
133 ivi_output_notify_waltham_plugin(struct ivi_surface *surface)
134 {
135         struct ivi_compositor *ivi = surface->ivi;
136         const struct weston_transmitter_api *api = ivi->waltham_transmitter_api;
137         struct weston_transmitter *transmitter;
138         struct weston_transmitter_remote *trans_remote;
139         struct weston_surface *weston_surface;
140         struct weston_output *woutput = surface->remote.output->output;
141         const char *app_id;
142
143         if (!api)
144                 return;
145
146         transmitter = api->transmitter_get(ivi->compositor);
147         if (!transmitter)
148                 return;
149
150         trans_remote = api->get_transmitter_remote(woutput->name, transmitter);
151         if (!trans_remote) {
152                 weston_log("Could not find a valie weston_transmitter_remote "
153                                 "that matches the output %s\n", woutput->name);
154                 return;
155         }
156
157         app_id = weston_desktop_surface_get_app_id(surface->dsurface);
158         weston_surface =
159                 weston_desktop_surface_get_surface(surface->dsurface);
160
161         weston_log("Forwarding app_id %s to remote %s\n", app_id, woutput->name);
162
163         /* this will have the effect of informing the remote side to create a
164          * surface with the name app_id. W/ xdg-shell the following happens:
165          *
166          * compositor (server):
167          * surface_push_to_remote():
168          *      waltham-transmitter plug-in
169          *              -> wthp_ivi_app_id_surface_create()
170          *
171          * client -- on the receiver side:
172          *      -> wthp_ivi_app_id_surface_create()
173          *              -> wth_receiver_weston_main()
174          *                      -> wl_compositor_create_surface()
175          *                      -> xdg_wm_base_get_xdg_surface
176          *                      -> xdg_toplevel_set_app_id()
177          *                      -> gst_init()
178          *                      -> gst_parse_launch()
179          *
180          * wth_receiver_weston_main() will be invoked from the handler of
181          * wthp_ivi_app_id_surface_create() and is responsible for setting-up
182          * the gstreamer pipeline as well.
183          */
184         surface->waltham_surface.transmitter_surface =
185             api->surface_push_to_remote(weston_surface, app_id, trans_remote, NULL);
186 }
187
188 #else
189 void
190 ivi_destroy_waltham_destroy(struct ivi_surface *surface)
191 {
192 }
193 static void
194 ivi_output_notify_waltham_plugin(struct ivi_surface *surface)
195 {
196 }
197 #endif
198
199 static void
200 ivi_set_desktop_surface_remote(struct ivi_surface *surface)
201 {
202         struct ivi_compositor *ivi = surface->ivi;
203         struct weston_view *view;
204         struct ivi_output *output = surface->remote.output;
205
206         assert(surface->role == IVI_SURFACE_ROLE_NONE);
207
208         /* remote type are the same as desktop just that client can tell
209          * the compositor to start on another output */
210         surface->role = IVI_SURFACE_ROLE_REMOTE;
211
212         /* if thew black surface view is mapped on the mean we need
213          * to remove it in order to start showing the 'remote' surface
214          * just being added */
215         view = output->fullscreen_view.fs->view;
216         if (view->is_mapped || view->surface->is_mapped)
217                 remove_black_curtain(output);
218
219         if (output->type == OUTPUT_WALTHAM)
220                 ivi_output_notify_waltham_plugin(surface);
221
222         wl_list_insert(&ivi->surfaces, &surface->link);
223 }
224
225
226 static void
227 ivi_set_desktop_surface_split(struct ivi_surface *surface)
228 {
229         struct ivi_compositor *ivi = surface->ivi;
230         assert(surface->role == IVI_SURFACE_ROLE_NONE);
231
232         if (surface->split.orientation == AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL)
233                 surface->role = IVI_SURFACE_ROLE_SPLIT_V;
234         else
235                 surface->role = IVI_SURFACE_ROLE_SPLIT_H;
236
237         wl_list_insert(&ivi->surfaces, &surface->link);
238
239         agl_shell_desktop_advertise_application_id(ivi, surface);
240 }
241
242 static struct pending_popup *
243 ivi_ensure_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
244                  int width, int height, const char *app_id)
245 {
246         struct pending_popup *p_popup = zalloc(sizeof(*p_popup));
247         size_t len_app_id = strlen(app_id);
248
249         if (!p_popup)
250                 return NULL;
251         p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
252         if (!p_popup->app_id) {
253                 free(p_popup);
254                 return NULL;
255         }
256         memcpy(p_popup->app_id, app_id, len_app_id);
257         p_popup->ioutput = ioutput;
258         p_popup->x = x;
259         p_popup->y = y;
260
261         p_popup->bb.x = bx;
262         p_popup->bb.y = by;
263         p_popup->bb.width = width;
264         p_popup->bb.height = height;
265
266         return p_popup;
267 }
268
269 static void
270 ivi_update_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
271                  int width, int height, const char *app_id, struct pending_popup *p_popup)
272 {
273         size_t len_app_id = strlen(app_id);
274
275         wl_list_remove(&p_popup->link);
276         wl_list_init(&p_popup->link);
277
278         memset(p_popup->app_id, 0, strlen(app_id) + 1);
279         free(p_popup->app_id);
280
281         p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
282         if (!p_popup->app_id)
283                 return;
284         memcpy(p_popup->app_id, app_id, len_app_id);
285
286         p_popup->ioutput = ioutput;
287         p_popup->x = x;
288         p_popup->y = y;
289
290         p_popup->bb.x = bx;
291         p_popup->bb.y = by;
292         p_popup->bb.width = width;
293         p_popup->bb.height = height;
294 }
295
296 static struct pending_fullscreen *
297 ivi_ensure_fullscreen(struct ivi_output *ioutput, const char *app_id)
298 {
299         struct pending_fullscreen *p_fullscreen = zalloc(sizeof(*p_fullscreen));
300         size_t len_app_id = strlen(app_id);
301
302         if (!p_fullscreen)
303                 return NULL;
304         p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
305         if (!p_fullscreen->app_id) {
306                 free(p_fullscreen);
307                 return NULL;
308         }
309         memcpy(p_fullscreen->app_id, app_id, len_app_id);
310
311         p_fullscreen->ioutput = ioutput;
312         return p_fullscreen;
313 }
314
315 static void
316 ivi_update_fullscreen(struct ivi_output *ioutput, const char *app_id,
317                       struct pending_fullscreen *p_fullscreen)
318 {
319         size_t len_app_id = strlen(app_id);
320
321         wl_list_remove(&p_fullscreen->link);
322         wl_list_init(&p_fullscreen->link);
323
324         memset(p_fullscreen->app_id, 0, strlen(app_id) + 1);
325         free(p_fullscreen->app_id);
326
327         p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
328         if (!p_fullscreen->app_id)
329                 return;
330         memcpy(p_fullscreen->app_id, app_id, len_app_id);
331
332         p_fullscreen->ioutput = ioutput;
333 }
334
335 static struct pending_remote *
336 ivi_ensure_remote(struct ivi_output *ioutput, const char *app_id)
337 {
338         struct pending_remote *p_remote = zalloc(sizeof(*p_remote));
339         size_t len_app_id = strlen(app_id);
340
341         if (!p_remote)
342                 return NULL;
343         p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
344         if (!p_remote->app_id) {
345                 free(p_remote);
346                 return NULL;
347         }
348         memcpy(p_remote->app_id, app_id, len_app_id);
349
350         p_remote->ioutput = ioutput;
351         return p_remote;
352 }
353
354 static void
355 ivi_update_remote(struct ivi_output *ioutput, const char *app_id,
356                       struct pending_remote *p_remote)
357 {
358         size_t len_app_id = strlen(app_id);
359
360         wl_list_remove(&p_remote->link);
361         wl_list_init(&p_remote->link);
362
363         memset(p_remote->app_id, 0, strlen(app_id) + 1);
364         free(p_remote->app_id);
365
366         p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
367         if (!p_remote->app_id)
368                 return;
369         memcpy(p_remote->app_id, app_id, len_app_id);
370
371         p_remote->ioutput = ioutput;
372 }
373
374 static void
375 ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput, int x, int y, int bx,
376                                       int by, int width, int height, const char *app_id)
377 {
378         struct ivi_compositor *ivi = ioutput->ivi;
379         struct pending_popup *p_popup = NULL;
380         struct pending_popup *popup;
381
382         wl_list_for_each(popup, &ivi->popup_pending_apps, link)
383                 if (!strcmp(app_id, popup->app_id))
384                         p_popup = popup;
385
386         if (!p_popup)
387                 p_popup = ivi_ensure_popup(ioutput, x, y, bx, by, width, height, app_id);
388         else
389                 ivi_update_popup(ioutput, x, y, bx, by, width, height, app_id, p_popup);
390         if (!p_popup)
391                 return;
392
393         wl_list_insert(&ivi->popup_pending_apps, &p_popup->link);
394 }
395
396 static void
397 ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput,
398                                            const char *app_id)
399 {
400         struct ivi_compositor *ivi = ioutput->ivi;
401         struct pending_fullscreen *p_fullscreen = NULL;
402         struct pending_fullscreen *fullscreen;
403
404         wl_list_for_each(fullscreen, &ivi->fullscreen_pending_apps, link)
405                 if (!strcmp(app_id, fullscreen->app_id))
406                         p_fullscreen = fullscreen;
407
408         if (!p_fullscreen)
409                 p_fullscreen = ivi_ensure_fullscreen(ioutput, app_id);
410         else
411                 ivi_update_fullscreen(ioutput, app_id, p_fullscreen);
412
413         if (!p_fullscreen)
414                 return;
415         wl_list_insert(&ivi->fullscreen_pending_apps, &p_fullscreen->link);
416 }
417
418 static void
419 ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput,
420                                       const char *app_id, uint32_t orientation)
421 {
422         struct ivi_compositor *ivi = ioutput->ivi;
423         struct ivi_surface *surf;
424         size_t len_app_id = strlen(app_id);
425         struct pending_split *split;
426
427         if (orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL &&
428             orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL)
429                 return;
430
431         /* more than one is un-supported, do note we need to do
432          * conversion for surface roles instead of using the protocol ones */
433         wl_list_for_each(surf, &ivi->surfaces, link)
434                 if (surf->role == IVI_SURFACE_ROLE_SPLIT_V ||
435                     surf->role == IVI_SURFACE_ROLE_SPLIT_H)
436                         return;
437
438         split = zalloc(sizeof(*split));
439         if (!split)
440                 return;
441         split->app_id = zalloc(sizeof(char) * (len_app_id + 1));
442         if (!split->app_id) {
443                 free(split);
444                 return;
445         }
446         memcpy(split->app_id, app_id, len_app_id);
447
448         split->ioutput = ioutput;
449         split->orientation = orientation;
450
451         wl_list_insert(&ivi->split_pending_apps, &split->link);
452 }
453
454 void
455 ivi_set_pending_desktop_surface_remote(struct ivi_output *ioutput,
456                 const char *app_id)
457 {
458         struct ivi_compositor *ivi = ioutput->ivi;
459         struct pending_remote *remote;
460         struct pending_remote *p_remote = NULL;
461
462         wl_list_for_each(remote, &ivi->remote_pending_apps, link)
463                 if (!strcmp(app_id, remote->app_id))
464                         p_remote = remote;
465
466         if (!p_remote)
467                 p_remote = ivi_ensure_remote(ioutput, app_id);
468         else
469                 ivi_update_remote(ioutput, app_id, p_remote);
470         if (!p_remote)
471                 return;
472
473         wl_list_insert(&ivi->remote_pending_apps, &p_remote->link);
474 }
475
476
477 static void
478 ivi_remove_pending_desktop_surface_split(struct pending_split *split)
479 {
480         free(split->app_id);
481         wl_list_remove(&split->link);
482         free(split);
483 }
484
485 static void
486 ivi_remove_pending_desktop_surface_fullscreen(struct pending_fullscreen *fs)
487 {
488         free(fs->app_id);
489         wl_list_remove(&fs->link);
490         free(fs);
491 }
492
493 static void
494 ivi_remove_pending_desktop_surface_popup(struct pending_popup *p_popup)
495 {
496         free(p_popup->app_id);
497         wl_list_remove(&p_popup->link);
498         free(p_popup);
499 }
500
501 static void
502 ivi_remove_pending_desktop_surface_remote(struct pending_remote *remote)
503 {
504         free(remote->app_id);
505         wl_list_remove(&remote->link);
506         free(remote);
507 }
508
509 static bool
510 ivi_compositor_keep_pending_surfaces(struct ivi_surface *surface)
511 {
512         return surface->ivi->keep_pending_surfaces;
513 }
514
515 static bool
516 ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface)
517 {
518         struct ivi_compositor *ivi = surface->ivi;
519         struct pending_popup *p_popup, *next_p_popup;
520         const char *_app_id =
521                         weston_desktop_surface_get_app_id(surface->dsurface);
522
523         if (wl_list_empty(&ivi->popup_pending_apps) || !_app_id)
524                 return false;
525
526         wl_list_for_each_safe(p_popup, next_p_popup,
527                               &ivi->popup_pending_apps, link) {
528                 if (!strcmp(_app_id, p_popup->app_id)) {
529                         surface->popup.output = p_popup->ioutput;
530                         surface->popup.x = p_popup->x;
531                         surface->popup.y = p_popup->y;
532
533                         surface->popup.bb.x = p_popup->bb.x;
534                         surface->popup.bb.y = p_popup->bb.y;
535                         surface->popup.bb.width = p_popup->bb.width;
536                         surface->popup.bb.height = p_popup->bb.height;
537
538                         if (!ivi_compositor_keep_pending_surfaces(surface))
539                                 ivi_remove_pending_desktop_surface_popup(p_popup);
540                         return true;
541                 }
542         }
543
544         return false;
545 }
546
547 static bool
548 ivi_check_pending_desktop_surface_split(struct ivi_surface *surface)
549 {
550         struct pending_split *split_surf, *next_split_surf;
551         struct ivi_compositor *ivi = surface->ivi;
552         const char *_app_id =
553                         weston_desktop_surface_get_app_id(surface->dsurface);
554
555         if (wl_list_empty(&ivi->split_pending_apps) || !_app_id)
556                 return false;
557
558         wl_list_for_each_safe(split_surf, next_split_surf,
559                               &ivi->split_pending_apps, link) {
560                 if (!strcmp(_app_id, split_surf->app_id)) {
561                         surface->split.output = split_surf->ioutput;
562                         surface->split.orientation = split_surf->orientation;
563                         if (!ivi_compositor_keep_pending_surfaces(surface))
564                                 ivi_remove_pending_desktop_surface_split(split_surf);
565                         return true;
566                 }
567         }
568
569         return false;
570 }
571
572 static bool
573 ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface)
574 {
575         struct pending_fullscreen *fs_surf, *next_fs_surf;
576         struct ivi_compositor *ivi = surface->ivi;
577         const char *_app_id =
578                         weston_desktop_surface_get_app_id(surface->dsurface);
579
580         if (wl_list_empty(&ivi->fullscreen_pending_apps) || !_app_id)
581                 return false;
582
583         wl_list_for_each_safe(fs_surf, next_fs_surf,
584                               &ivi->fullscreen_pending_apps, link) {
585                 if (!strcmp(_app_id, fs_surf->app_id)) {
586                         surface->fullscreen.output = fs_surf->ioutput;
587                         if (!ivi_compositor_keep_pending_surfaces(surface))
588                                 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
589                         return true;
590                 }
591         }
592
593         return false;
594 }
595
596 static bool
597 ivi_check_pending_desktop_surface_remote(struct ivi_surface *surface)
598 {
599         struct pending_remote *remote_surf, *next_remote_surf;
600         struct ivi_compositor *ivi = surface->ivi;
601         const char *_app_id =
602                 weston_desktop_surface_get_app_id(surface->dsurface);
603
604         if (wl_list_empty(&ivi->remote_pending_apps) || !_app_id)
605                 return false;
606
607         wl_list_for_each_safe(remote_surf, next_remote_surf,
608                               &ivi->remote_pending_apps, link) {
609                 if (!strcmp(_app_id, remote_surf->app_id)) {
610                         surface->remote.output = remote_surf->ioutput;
611                         if (!ivi_compositor_keep_pending_surfaces(surface))
612                                 ivi_remove_pending_desktop_surface_remote(remote_surf);
613                         return true;
614                 }
615         }
616
617         return false;
618 }
619 void
620 ivi_check_pending_surface_desktop(struct ivi_surface *surface,
621                                   enum ivi_surface_role *role)
622 {
623         struct ivi_compositor *ivi = surface->ivi;
624         struct wl_list *role_pending_list;
625         struct pending_popup *p_popup;
626         struct pending_split *p_split;
627         struct pending_fullscreen *p_fullscreen;
628         struct pending_remote *p_remote;
629         const char *app_id =
630                 weston_desktop_surface_get_app_id(surface->dsurface);
631
632         role_pending_list = &ivi->popup_pending_apps;
633         wl_list_for_each(p_popup, role_pending_list, link) {
634                 if (app_id && !strcmp(app_id, p_popup->app_id)) {
635                         *role = IVI_SURFACE_ROLE_POPUP;
636                         return;
637                 }
638         }
639
640         role_pending_list = &ivi->split_pending_apps;
641         wl_list_for_each(p_split, role_pending_list, link) {
642                 if (app_id && !strcmp(app_id, p_split->app_id)) {
643                         *role = IVI_SURFACE_ROLE_SPLIT_V;
644                         return;
645                 }
646         }
647
648         role_pending_list = &ivi->fullscreen_pending_apps;
649         wl_list_for_each(p_fullscreen, role_pending_list, link) {
650                 if (app_id && !strcmp(app_id, p_fullscreen->app_id)) {
651                         *role = IVI_SURFACE_ROLE_FULLSCREEN;
652                         return;
653                 }
654         }
655
656         role_pending_list = &ivi->remote_pending_apps;
657         wl_list_for_each(p_remote, role_pending_list, link) {
658                 if (app_id && !strcmp(app_id, p_remote->app_id)) {
659                         *role = IVI_SURFACE_ROLE_REMOTE;
660                         return;
661                 }
662         }
663
664         /* else, we are a regular desktop surface */
665         *role = IVI_SURFACE_ROLE_DESKTOP;
666 }
667
668
669 void
670 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
671 {
672         bool ret = false;
673
674         ret = ivi_check_pending_desktop_surface_popup(surface);
675         if (ret) {
676                 ivi_set_desktop_surface_popup(surface);
677                 ivi_layout_popup_committed(surface);
678                 return;
679         }
680
681         ret = ivi_check_pending_desktop_surface_split(surface);
682         if (ret) {
683                 ivi_set_desktop_surface_split(surface);
684                 ivi_layout_split_committed(surface);
685                 return;
686         }
687
688         ret = ivi_check_pending_desktop_surface_fullscreen(surface);
689         if (ret) {
690                 ivi_set_desktop_surface_fullscreen(surface);
691                 ivi_layout_fullscreen_committed(surface);
692                 return;
693         }
694
695         ret = ivi_check_pending_desktop_surface_remote(surface);
696         if (ret) {
697                 ivi_set_desktop_surface_remote(surface);
698                 ivi_layout_desktop_committed(surface);
699                 return;
700         }
701
702         /* if we end up here means we have a regular desktop app and
703          * try to activate it */
704         ivi_set_desktop_surface(surface);
705         ivi_layout_desktop_committed(surface);
706 }
707
708 void
709 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
710 {
711         struct ivi_output *out;
712
713         wl_list_for_each(out, &ivi->outputs, link) {
714                 create_black_curtain_view(out);
715                 insert_black_curtain(out);
716         }
717 }
718
719 int
720 ivi_shell_init(struct ivi_compositor *ivi)
721 {
722         weston_layer_init(&ivi->hidden, ivi->compositor);
723         weston_layer_init(&ivi->background, ivi->compositor);
724         weston_layer_init(&ivi->normal, ivi->compositor);
725         weston_layer_init(&ivi->panel, ivi->compositor);
726         weston_layer_init(&ivi->popup, ivi->compositor);
727         weston_layer_init(&ivi->fullscreen, ivi->compositor);
728
729         weston_layer_set_position(&ivi->hidden,
730                                   WESTON_LAYER_POSITION_HIDDEN);
731         weston_layer_set_position(&ivi->background,
732                                   WESTON_LAYER_POSITION_BACKGROUND);
733         weston_layer_set_position(&ivi->normal,
734                                   WESTON_LAYER_POSITION_NORMAL);
735         weston_layer_set_position(&ivi->panel,
736                                   WESTON_LAYER_POSITION_UI);
737         weston_layer_set_position(&ivi->popup,
738                                   WESTON_LAYER_POSITION_TOP_UI);
739         weston_layer_set_position(&ivi->fullscreen,
740                                   WESTON_LAYER_POSITION_FULLSCREEN);
741
742         return 0;
743 }
744
745
746 static void
747 ivi_surf_destroy(struct ivi_surface *surf)
748 {
749         struct weston_surface *wsurface = surf->view->surface;
750
751         if (weston_surface_is_mapped(wsurface)) {
752                 weston_desktop_surface_unlink_view(surf->view);
753                 weston_view_destroy(surf->view);
754         }
755
756         wl_list_remove(&surf->link);
757         free(surf);
758 }
759
760 static void
761 ivi_shell_destroy_views_on_layer(struct weston_layer *layer)
762 {
763         struct weston_view *view, *view_next;
764
765         wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) {
766                 struct ivi_surface *ivi_surf =
767                         get_ivi_shell_surface(view->surface);
768                 if (ivi_surf)
769                         ivi_surf_destroy(ivi_surf);
770         }
771 }
772
773 void
774 ivi_shell_finalize(struct ivi_compositor *ivi)
775 {
776         struct ivi_output *output;
777
778         ivi_shell_destroy_views_on_layer(&ivi->hidden);
779         weston_layer_fini(&ivi->hidden);
780
781         ivi_shell_destroy_views_on_layer(&ivi->background);
782         weston_layer_fini(&ivi->background);
783
784         ivi_shell_destroy_views_on_layer(&ivi->normal);
785         weston_layer_fini(&ivi->normal);
786
787         ivi_shell_destroy_views_on_layer(&ivi->panel);
788         weston_layer_fini(&ivi->panel);
789
790         ivi_shell_destroy_views_on_layer(&ivi->popup);
791         weston_layer_fini(&ivi->popup);
792
793         wl_list_for_each(output, &ivi->outputs, link) {
794                 if (output->fullscreen_view.fs->view) {
795                         weston_surface_destroy(output->fullscreen_view.fs->view->surface);
796                         output->fullscreen_view.fs->view = NULL;
797                 }
798         }
799         weston_layer_fini(&ivi->fullscreen);
800 }
801
802 static void
803 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
804 {
805         struct ivi_surface *surface;
806
807         wl_list_for_each(surface, &ivi->surfaces, link) {
808                 const char *app_id =
809                         weston_desktop_surface_get_app_id(surface->dsurface);
810                 if (app_id == NULL) {
811                         weston_log("WARNING app_is is null, unable to advertise\n");
812                         return;
813                 }
814                 agl_shell_desktop_send_application(resource, app_id);
815         }
816 }
817
818 static struct wl_client *
819 client_launch(struct weston_compositor *compositor,
820                      struct weston_process *proc,
821                      const char *path,
822                      weston_process_cleanup_func_t cleanup)
823 {
824         struct wl_client *client = NULL;
825         struct custom_env child_env;
826         struct fdstr wayland_socket;
827         const char *fail_cloexec = "Couldn't unset CLOEXEC on client socket";
828         const char *fail_seteuid = "Couldn't call seteuid";
829         char *fail_exec;
830         char * const *argp;
831         char * const *envp;
832         sigset_t allsigs;
833         pid_t pid;
834         bool ret;
835         struct ivi_compositor *ivi;
836         size_t written __attribute__((unused));
837
838         weston_log("launching '%s'\n", path);
839         str_printf(&fail_exec, "Error: Couldn't launch client '%s'\n", path);
840
841         custom_env_init_from_environ(&child_env);
842         custom_env_add_from_exec_string(&child_env, path);
843
844         if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0,
845                                   wayland_socket.fds) < 0) {
846                 weston_log("client_launch: "
847                            "socketpair failed while launching '%s': %s\n",
848                            path, strerror(errno));
849                 custom_env_fini(&child_env);
850                 return NULL;
851         }
852         fdstr_update_str1(&wayland_socket);
853         custom_env_set_env_var(&child_env, "WAYLAND_SOCKET",
854                                wayland_socket.str1);
855
856         argp = custom_env_get_argp(&child_env);
857         envp = custom_env_get_envp(&child_env);
858
859         pid = fork();
860         switch (pid) {
861         case 0:
862                 /* Put the client in a new session so it won't catch signals
863                  * intended for the parent. Sharing a session can be
864                  * confusing when launching weston under gdb, as the ctrl-c
865                  * intended for gdb will pass to the child, and weston
866                  * will cleanly shut down when the child exits.
867                  */
868                 setsid();
869
870                 /* do not give our signal mask to the new process */
871                 sigfillset(&allsigs);
872                 sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
873
874                 /* Launch clients as the user. Do not launch clients with wrong euid. */
875                 if (seteuid(getuid()) == -1) {
876                         written = write(STDERR_FILENO, fail_seteuid, strlen(fail_seteuid));
877                         _exit(EXIT_FAILURE);
878                 }
879
880                 ret = fdstr_clear_cloexec_fd1(&wayland_socket);
881                 if (!ret) {
882                         written = write(STDERR_FILENO, fail_cloexec, strlen(fail_cloexec));
883                         _exit(EXIT_FAILURE);
884                 }
885
886                 execve(argp[0], argp, envp);
887
888                 if (fail_exec)
889                         written = write(STDERR_FILENO, fail_exec, strlen(fail_exec));
890                 _exit(EXIT_FAILURE);
891
892         default:
893                 close(wayland_socket.fds[1]);
894                 ivi = weston_compositor_get_user_data(compositor);
895                 client = wl_client_create(compositor->wl_display,
896                                           wayland_socket.fds[0]);
897                 if (!client) {
898                         custom_env_fini(&child_env);
899                         close(wayland_socket.fds[0]);
900                         free(fail_exec);
901                         weston_log("client_launch: "
902                                 "wl_client_create failed while launching '%s'.\n",
903                                 path);
904                         return NULL;
905                 }
906
907                 proc->pid = pid;
908                 proc->cleanup = cleanup;
909                 wl_list_insert(&ivi->child_process_list, &proc->link);
910                 break;
911
912         case -1:
913                 fdstr_close_all(&wayland_socket);
914                 weston_log("client_launch: "
915                            "fork failed while launching '%s': %s\n", path,
916                            strerror(errno));
917                 break;
918         }
919
920         custom_env_fini(&child_env);
921         free(fail_exec);
922
923         return client;
924 }
925
926 struct process_info {
927         struct weston_process proc;
928         char *path;
929 };
930
931 static void
932 process_handle_sigchld(struct weston_process *process, int status)
933 {
934         struct process_info *pinfo =
935                 container_of(process, struct process_info, proc);
936
937         /*
938          * There are no guarantees whether this runs before or after
939          * the wl_client destructor.
940          */
941
942         if (WIFEXITED(status)) {
943                 weston_log("%s exited with status %d\n", pinfo->path,
944                            WEXITSTATUS(status));
945         } else if (WIFSIGNALED(status)) {
946                 weston_log("%s died on signal %d\n", pinfo->path,
947                            WTERMSIG(status));
948         } else {
949                 weston_log("%s disappeared\n", pinfo->path);
950         }
951
952         free(pinfo->path);
953         free(pinfo);
954 }
955
956 int
957 ivi_launch_shell_client(struct ivi_compositor *ivi)
958 {
959         struct process_info *pinfo;
960         struct weston_config_section *section;
961         char *command = NULL;
962
963         section = weston_config_get_section(ivi->config, "shell-client",
964                                             NULL, NULL);
965         if (section)
966                 weston_config_section_get_string(section, "command",
967                                                  &command, NULL);
968
969         if (!command)
970                 return -1;
971
972         pinfo = zalloc(sizeof *pinfo);
973         if (!pinfo)
974                 return -1;
975
976         pinfo->path = strdup(command);
977         if (!pinfo->path)
978                 goto out_free;
979
980         ivi->shell_client.client = client_launch(ivi->compositor, &pinfo->proc,
981                                                  command, process_handle_sigchld);
982         if (!ivi->shell_client.client)
983                 goto out_str;
984
985         return 0;
986
987 out_str:
988         free(pinfo->path);
989
990 out_free:
991         free(pinfo);
992
993         return -1;
994 }
995
996 static void
997 destroy_black_curtain_view(struct wl_listener *listener, void *data)
998 {
999         struct fullscreen_view *fs =
1000                 wl_container_of(listener, fs, fs_destroy);
1001
1002
1003         if (fs && fs->fs) {
1004                 wl_list_remove(&fs->fs_destroy.link);
1005                 free(fs->fs);
1006         }
1007 }
1008
1009
1010 static void
1011 create_black_curtain_view(struct ivi_output *output)
1012 {
1013         struct weston_surface *surface = NULL;
1014         struct weston_view *view;
1015         struct ivi_compositor *ivi = output->ivi;
1016         struct weston_compositor *wc= ivi->compositor;
1017         struct weston_output *woutput = output->output;
1018
1019         if (!woutput)
1020                 return;
1021
1022         surface = weston_surface_create(wc);
1023         if (!surface)
1024                 return;
1025         view = weston_view_create(surface);
1026         if (!view) {
1027                 weston_surface_destroy(surface);
1028                 return;
1029         }
1030
1031         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
1032         weston_surface_set_size(surface, woutput->width, woutput->height);
1033         weston_view_set_position(view, woutput->x, woutput->y);
1034
1035         output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
1036         if (!output->fullscreen_view.fs) {
1037                 weston_surface_destroy(surface);
1038                 return;
1039         }
1040         output->fullscreen_view.fs->view = view;
1041
1042         output->fullscreen_view.fs_destroy.notify = destroy_black_curtain_view;
1043         wl_signal_add(&woutput->destroy_signal,
1044                       &output->fullscreen_view.fs_destroy);
1045 }
1046
1047 bool
1048 output_has_black_curtain(struct ivi_output *output)
1049 {
1050         return (output->fullscreen_view.fs->view &&
1051                 output->fullscreen_view.fs->view->is_mapped &&
1052                 output->fullscreen_view.fs->view->surface->is_mapped);
1053 }
1054
1055 void
1056 remove_black_curtain(struct ivi_output *output)
1057 {
1058         struct weston_view *view;
1059
1060         if (!output &&
1061             !output->fullscreen_view.fs &&
1062             !output->fullscreen_view.fs->view) {
1063                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1064                 return;
1065         }
1066
1067         view = output->fullscreen_view.fs->view;
1068         assert(view->is_mapped == true ||
1069                view->surface->is_mapped == true);
1070
1071         view->is_mapped = false;
1072         view->surface->is_mapped = false;
1073
1074         weston_layer_entry_remove(&view->layer_link);
1075         weston_view_update_transform(view);
1076
1077         weston_view_damage_below(view);
1078
1079         weston_log("Removed black curtain from output %s\n", output->output->name);
1080 }
1081
1082 void
1083 insert_black_curtain(struct ivi_output *output)
1084 {
1085         struct weston_view *view;
1086
1087         if ((!output &&
1088             !output->fullscreen_view.fs &&
1089             !output->fullscreen_view.fs->view) || !output->output) {
1090                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1091                 return;
1092         }
1093
1094         view = output->fullscreen_view.fs->view;
1095         if (view->is_mapped || view->surface->is_mapped)
1096                 return;
1097
1098         weston_layer_entry_remove(&view->layer_link);
1099         weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
1100                                   &view->layer_link);
1101
1102         view->is_mapped = true;
1103         view->surface->is_mapped = true;
1104
1105         weston_view_update_transform(view);
1106         weston_view_damage_below(view);
1107
1108         weston_log("Added black curtain to output %s\n", output->output->name);
1109 }
1110
1111 static void
1112 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
1113 {
1114         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1115         struct ivi_output *output;
1116         struct ivi_surface *surface, *tmp;
1117
1118         if (ivi->shell_client.resource &&
1119             ivi->shell_client.status == BOUND_FAILED) {
1120                 wl_resource_post_error(shell_res,
1121                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1122                                        "agl_shell has already been bound. "
1123                                        "Check out bound_fail event");
1124                 return;
1125         }
1126
1127         /* Init already finished. Do nothing */
1128         if (ivi->shell_client.ready)
1129                 return;
1130
1131
1132         ivi->shell_client.ready = true;
1133
1134         wl_list_for_each(output, &ivi->outputs, link) {
1135                 if (output->background)
1136                         remove_black_curtain(output);
1137                 ivi_layout_init(ivi, output);
1138         }
1139
1140         wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
1141                 const char *app_id;
1142
1143                 wl_list_remove(&surface->link);
1144                 wl_list_init(&surface->link);
1145                 ivi_check_pending_desktop_surface(surface);
1146                 surface->checked_pending = true;
1147                 app_id = weston_desktop_surface_get_app_id(surface->dsurface);
1148
1149                 if (app_id &&
1150                     wl_resource_get_version(ivi->shell_client.resource) >=
1151                     AGL_SHELL_APP_STATE_SINCE_VERSION)
1152                         agl_shell_send_app_state(ivi->shell_client.resource,
1153                                                  app_id, AGL_SHELL_APP_STATE_STARTED);
1154         }
1155 }
1156
1157 static void
1158 shell_set_background(struct wl_client *client,
1159                      struct wl_resource *shell_res,
1160                      struct wl_resource *surface_res,
1161                      struct wl_resource *output_res)
1162 {
1163         struct weston_head *head = weston_head_from_resource(output_res);
1164         struct weston_output *woutput = weston_head_get_output(head);
1165         struct ivi_output *output = to_ivi_output(woutput);
1166         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1167         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1168         struct weston_desktop_surface *dsurface;
1169         struct ivi_surface *surface;
1170
1171         if (ivi->shell_client.resource &&
1172             ivi->shell_client.status == BOUND_FAILED) {
1173                 wl_resource_post_error(shell_res,
1174                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1175                                        "agl_shell has already been bound. "
1176                                        "Check out bound_fail event");
1177                 return;
1178         }
1179
1180         dsurface = weston_surface_get_desktop_surface(wsurface);
1181         if (!dsurface) {
1182                 wl_resource_post_error(shell_res,
1183                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1184                                        "surface must be a desktop surface");
1185                 return;
1186         }
1187
1188         surface = weston_desktop_surface_get_user_data(dsurface);
1189         if (surface->role != IVI_SURFACE_ROLE_NONE) {
1190                 wl_resource_post_error(shell_res,
1191                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1192                                        "surface already has another ivi role");
1193                 return;
1194         }
1195
1196         if (output->background) {
1197                 wl_resource_post_error(shell_res,
1198                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1199                                        "output already has background");
1200                 return;
1201         }
1202
1203         surface->checked_pending = true;
1204         surface->role = IVI_SURFACE_ROLE_BACKGROUND;
1205         surface->bg.output = output;
1206         wl_list_remove(&surface->link);
1207         wl_list_init(&surface->link);
1208
1209         output->background = surface;
1210
1211         weston_desktop_surface_set_maximized(dsurface, true);
1212         weston_desktop_surface_set_size(dsurface,
1213                                         output->output->width,
1214                                         output->output->height);
1215 }
1216
1217 static void
1218 shell_set_panel(struct wl_client *client,
1219                 struct wl_resource *shell_res,
1220                 struct wl_resource *surface_res,
1221                 struct wl_resource *output_res,
1222                 uint32_t edge)
1223 {
1224         struct weston_head *head = weston_head_from_resource(output_res);
1225         struct weston_output *woutput = weston_head_get_output(head);
1226         struct ivi_output *output = to_ivi_output(woutput);
1227         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1228         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1229         struct weston_desktop_surface *dsurface;
1230         struct ivi_surface *surface;
1231         struct ivi_surface **member;
1232         int32_t width = 0, height = 0;
1233
1234         if (ivi->shell_client.resource &&
1235             ivi->shell_client.status == BOUND_FAILED) {
1236                 wl_resource_post_error(shell_res,
1237                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1238                                        "agl_shell has already been bound. "
1239                                        "Check out bound_fail event");
1240                 return;
1241         }
1242
1243         dsurface = weston_surface_get_desktop_surface(wsurface);
1244         if (!dsurface) {
1245                 wl_resource_post_error(shell_res,
1246                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1247                                        "surface must be a desktop surface");
1248                 return;
1249         }
1250
1251         surface = weston_desktop_surface_get_user_data(dsurface);
1252         if (surface->role != IVI_SURFACE_ROLE_NONE) {
1253                 wl_resource_post_error(shell_res,
1254                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1255                                        "surface already has another ivi role");
1256                 return;
1257         }
1258
1259         switch (edge) {
1260         case AGL_SHELL_EDGE_TOP:
1261                 member = &output->top;
1262                 break;
1263         case AGL_SHELL_EDGE_BOTTOM:
1264                 member = &output->bottom;
1265                 break;
1266         case AGL_SHELL_EDGE_LEFT:
1267                 member = &output->left;
1268                 break;
1269         case AGL_SHELL_EDGE_RIGHT:
1270                 member = &output->right;
1271                 break;
1272         default:
1273                 wl_resource_post_error(shell_res,
1274                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1275                                        "invalid edge for panel");
1276                 return;
1277         }
1278
1279         if (*member) {
1280                 wl_resource_post_error(shell_res,
1281                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1282                                        "output already has panel on this edge");
1283                 return;
1284         }
1285
1286         surface->checked_pending = true;
1287         surface->role = IVI_SURFACE_ROLE_PANEL;
1288         surface->panel.output = output;
1289         surface->panel.edge = edge;
1290         wl_list_remove(&surface->link);
1291         wl_list_init(&surface->link);
1292
1293         *member = surface;
1294
1295         switch (surface->panel.edge) {
1296         case AGL_SHELL_EDGE_TOP:
1297         case AGL_SHELL_EDGE_BOTTOM:
1298                 width = woutput->width;
1299                 break;
1300         case AGL_SHELL_EDGE_LEFT:
1301         case AGL_SHELL_EDGE_RIGHT:
1302                 height = woutput->height;
1303                 break;
1304         }
1305
1306         weston_desktop_surface_set_size(dsurface, width, height);
1307 }
1308
1309 void
1310 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
1311                           const char *data, uint32_t app_state)
1312 {
1313         struct desktop_client *dclient;
1314         uint32_t app_role;
1315         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1316         struct ivi_policy *policy = ivi->policy;
1317
1318         /* FIXME: should queue it here and see when binding agl-shell-desktop
1319          * if there are any to be sent */
1320         if (!surf)
1321                 return;
1322
1323         if (!app_id)
1324                 return;
1325
1326         if (policy && policy->api.surface_advertise_state_change &&
1327             !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
1328                 return;
1329         }
1330
1331         app_role = surf->role;
1332         if (app_role == IVI_SURFACE_ROLE_POPUP)
1333                 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
1334
1335         wl_list_for_each(dclient, &ivi->desktop_clients, link)
1336                 agl_shell_desktop_send_state_app(dclient->resource, app_id,
1337                                                  data, app_state, app_role);
1338 }
1339
1340 static void
1341 shell_activate_app(struct wl_client *client,
1342                    struct wl_resource *shell_res,
1343                    const char *app_id,
1344                    struct wl_resource *output_res)
1345 {
1346         struct weston_head *head = weston_head_from_resource(output_res);
1347         struct weston_output *woutput = weston_head_get_output(head);
1348         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1349         struct ivi_output *output = to_ivi_output(woutput);
1350
1351         if (ivi->shell_client.resource &&
1352             ivi->shell_client.status == BOUND_FAILED) {
1353                 wl_resource_post_error(shell_res,
1354                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1355                                        "agl_shell has already been bound. "
1356                                        "Check out bound_fail event");
1357                 return;
1358         }
1359
1360         ivi_layout_activate(output, app_id);
1361 }
1362
1363 static void
1364 shell_desktop_activate_app(struct wl_client *client,
1365                            struct wl_resource *shell_res,
1366                            const char *app_id, const char *data,
1367                            struct wl_resource *output_res)
1368 {
1369         struct weston_head *head = weston_head_from_resource(output_res);
1370         struct weston_output *woutput = weston_head_get_output(head);
1371         struct ivi_output *output = to_ivi_output(woutput);
1372
1373         ivi_layout_activate(output, app_id);
1374         shell_advertise_app_state(output->ivi, app_id,
1375                                   data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
1376 }
1377
1378 static void
1379 shell_deactivate_app(struct wl_client *client,
1380                    struct wl_resource *shell_res,
1381                    const char *app_id)
1382 {
1383         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1384         struct ivi_compositor *ivi = dclient->ivi;
1385
1386         ivi_layout_deactivate(ivi, app_id);
1387         shell_advertise_app_state(ivi, app_id,
1388                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
1389 }
1390
1391 /* stub, no usage for the time being */
1392 static void
1393 shell_destroy(struct wl_client *client, struct wl_resource *res)
1394 {
1395 }
1396
1397 static const struct agl_shell_interface agl_shell_implementation = {
1398         .destroy = shell_destroy,
1399         .ready = shell_ready,
1400         .set_background = shell_set_background,
1401         .set_panel = shell_set_panel,
1402         .activate_app = shell_activate_app,
1403 };
1404
1405 static void
1406 shell_desktop_set_app_property(struct wl_client *client,
1407                                struct wl_resource *shell_res,
1408                                const char *app_id, uint32_t role,
1409                                int x, int y, int bx, int by,
1410                                int width, int height,
1411                                struct wl_resource *output_res)
1412 {
1413         struct weston_head *head = weston_head_from_resource(output_res);
1414         struct weston_output *woutput = weston_head_get_output(head);
1415         struct ivi_output *output = to_ivi_output(woutput);
1416
1417         switch (role) {
1418         case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
1419                 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
1420                                                       width, height, app_id);
1421                 break;
1422         case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
1423                 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
1424                 break;
1425         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
1426         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
1427                 ivi_set_pending_desktop_surface_split(output, app_id, role);
1428                 break;
1429         case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
1430                 ivi_set_pending_desktop_surface_remote(output, app_id);
1431                 break;
1432         default:
1433                 break;
1434         }
1435 }
1436
1437 void
1438 ivi_compositor_destroy_pending_surfaces(struct ivi_compositor *ivi)
1439 {
1440         struct pending_popup *p_popup, *next_p_popup;
1441         struct pending_split *split_surf, *next_split_surf;
1442         struct pending_fullscreen *fs_surf, *next_fs_surf;
1443         struct pending_remote *remote_surf, *next_remote_surf;
1444
1445         wl_list_for_each_safe(p_popup, next_p_popup,
1446                               &ivi->popup_pending_apps, link)
1447                 ivi_remove_pending_desktop_surface_popup(p_popup);
1448
1449         wl_list_for_each_safe(split_surf, next_split_surf,
1450                               &ivi->split_pending_apps, link)
1451                 ivi_remove_pending_desktop_surface_split(split_surf);
1452
1453         wl_list_for_each_safe(fs_surf, next_fs_surf,
1454                               &ivi->fullscreen_pending_apps, link)
1455                 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
1456
1457         wl_list_for_each_safe(remote_surf, next_remote_surf,
1458                               &ivi->remote_pending_apps, link)
1459                 ivi_remove_pending_desktop_surface_remote(remote_surf);
1460 }
1461
1462 static void
1463 shell_desktop_set_app_property_mode(struct wl_client *client,
1464                                     struct wl_resource *shell_res, uint32_t perm)
1465 {
1466         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1467         if (perm) {
1468                 dclient->ivi->keep_pending_surfaces = true;
1469         } else {
1470                 dclient->ivi->keep_pending_surfaces = false;
1471                 /* remove any previous pending surfaces */
1472                 ivi_compositor_destroy_pending_surfaces(dclient->ivi);
1473         }
1474 }
1475
1476 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
1477         .activate_app = shell_desktop_activate_app,
1478         .set_app_property = shell_desktop_set_app_property,
1479         .deactivate_app = shell_deactivate_app,
1480         .set_app_property_mode = shell_desktop_set_app_property_mode,
1481 };
1482
1483 static void
1484 unbind_agl_shell(struct wl_resource *resource)
1485 {
1486         struct ivi_compositor *ivi;
1487         struct ivi_output *output;
1488         struct ivi_surface *surf, *surf_tmp;
1489
1490         ivi = wl_resource_get_user_data(resource);
1491
1492         /* reset status to allow other clients issue legit requests */
1493         if (ivi->shell_client.resource &&
1494             ivi->shell_client.status == BOUND_FAILED) {
1495                 ivi->shell_client.status = BOUND_OK;
1496                 return;
1497         }
1498
1499         wl_list_for_each(output, &ivi->outputs, link) {
1500                 /* reset the active surf if there's one present */
1501                 if (output->active) {
1502                         output->active->view->is_mapped = false;
1503                         output->active->view->surface->is_mapped = false;
1504
1505                         weston_layer_entry_remove(&output->active->view->layer_link);
1506                         output->active = NULL;
1507                 }
1508
1509                 insert_black_curtain(output);
1510         }
1511
1512         wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
1513                 wl_list_remove(&surf->link);
1514                 wl_list_init(&surf->link);
1515         }
1516
1517         wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
1518                 wl_list_remove(&surf->link);
1519                 wl_list_init(&surf->link);
1520         }
1521
1522         wl_list_init(&ivi->surfaces);
1523         wl_list_init(&ivi->pending_surfaces);
1524
1525         ivi->shell_client.ready = false;
1526         ivi->shell_client.resource = NULL;
1527         ivi->shell_client.client = NULL;
1528 }
1529
1530 static void
1531 bind_agl_shell(struct wl_client *client,
1532                void *data, uint32_t version, uint32_t id)
1533 {
1534         struct ivi_compositor *ivi = data;
1535         struct wl_resource *resource;
1536         struct ivi_policy *policy;
1537         void *interface;
1538
1539         policy = ivi->policy;
1540         interface = (void *) &agl_shell_interface;
1541         if (policy && policy->api.shell_bind_interface &&
1542             !policy->api.shell_bind_interface(client, interface)) {
1543                 wl_client_post_implementation_error(client,
1544                                        "client not authorized to use agl_shell");
1545                 return;
1546         }
1547
1548         resource = wl_resource_create(client, &agl_shell_interface, version, id);
1549         if (!resource) {
1550                 wl_client_post_no_memory(client);
1551                 return;
1552         }
1553
1554         if (ivi->shell_client.resource) {
1555                 if (wl_resource_get_version(resource) == 1) {
1556                         wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1557                                                "agl_shell has already been bound");
1558                         return;
1559                 }
1560
1561                 agl_shell_send_bound_fail(resource);
1562                 ivi->shell_client.status = BOUND_FAILED;
1563         }
1564
1565         wl_resource_set_implementation(resource, &agl_shell_implementation,
1566                                        ivi, unbind_agl_shell);
1567         ivi->shell_client.resource = resource;
1568
1569         if (ivi->shell_client.status == BOUND_OK &&
1570             wl_resource_get_version(resource) >= AGL_SHELL_BOUND_OK_SINCE_VERSION)
1571                 agl_shell_send_bound_ok(ivi->shell_client.resource);
1572 }
1573
1574 static void
1575 unbind_agl_shell_desktop(struct wl_resource *resource)
1576 {
1577         struct desktop_client *dclient = wl_resource_get_user_data(resource);
1578
1579         wl_list_remove(&dclient->link);
1580         free(dclient);
1581 }
1582
1583 static void
1584 bind_agl_shell_desktop(struct wl_client *client,
1585                        void *data, uint32_t version, uint32_t id)
1586 {
1587         struct ivi_compositor *ivi = data;
1588         struct wl_resource *resource;
1589         struct ivi_policy *policy;
1590         struct desktop_client *dclient;
1591         void *interface;
1592
1593         policy = ivi->policy;
1594         interface  = (void *) &agl_shell_desktop_interface;
1595         if (policy && policy->api.shell_bind_interface &&
1596             !policy->api.shell_bind_interface(client, interface)) {
1597                 wl_client_post_implementation_error(client,
1598                                 "client not authorized to use agl_shell_desktop");
1599                 return;
1600         }
1601
1602         dclient = zalloc(sizeof(*dclient));
1603         if (!dclient) {
1604                 wl_client_post_no_memory(client);
1605                 return;
1606         }
1607
1608         resource = wl_resource_create(client, &agl_shell_desktop_interface,
1609                                       version, id);
1610         dclient->ivi = ivi;
1611         if (!resource) {
1612                 wl_client_post_no_memory(client);
1613                 return;
1614         }
1615
1616         wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
1617                                        dclient, unbind_agl_shell_desktop);
1618
1619         dclient->resource = resource;
1620         wl_list_insert(&ivi->desktop_clients, &dclient->link);
1621
1622         /* advertise xdg surfaces */
1623         ivi_shell_advertise_xdg_surfaces(ivi, resource);
1624 }
1625
1626 int
1627 ivi_shell_create_global(struct ivi_compositor *ivi)
1628 {
1629         ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
1630                                           &agl_shell_interface, 3,
1631                                           ivi, bind_agl_shell);
1632         if (!ivi->agl_shell) {
1633                 weston_log("Failed to create wayland global.\n");
1634                 return -1;
1635         }
1636
1637         ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
1638                                                   &agl_shell_desktop_interface, 2,
1639                                                   ivi, bind_agl_shell_desktop);
1640         if (!ivi->agl_shell_desktop) {
1641                 weston_log("Failed to create wayland global (agl_shell_desktop).\n");
1642                 return -1;
1643         }
1644
1645         return 0;
1646 }