shell: Reset active view to allow further activation
[src/agl-compositor.git] / src / shell.c
1 /*
2  * Copyright © 2019, 2022 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 <sys/wait.h>
37 #include <unistd.h>
38 #include <libweston/libweston.h>
39 #include <libweston/config-parser.h>
40
41 #include <weston.h>
42 #include "shared/os-compatibility.h"
43 #include "shared/helpers.h"
44 #include "shared/process-util.h"
45
46 #include "agl-shell-server-protocol.h"
47 #include "agl-shell-desktop-server-protocol.h"
48
49 static void
50 create_black_curtain_view(struct ivi_output *output);
51
52 static void
53 _ivi_set_shell_surface_split(struct ivi_surface *surface, struct ivi_output *output,
54                              uint32_t orientation, bool to_activate);
55
56 static uint32_t
57 reverse_orientation(uint32_t orientation);
58
59 void
60 agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi,
61                                            struct ivi_surface *surface)
62 {
63         struct desktop_client *dclient;
64         static bool display_adv = false;
65
66         if (surface->advertised_on_launch)
67                 return;
68
69         /* advertise to all desktop clients the new surface */
70         wl_list_for_each(dclient, &ivi->desktop_clients, link) {
71                 const char *app_id =
72                         weston_desktop_surface_get_app_id(surface->dsurface);
73                 if (app_id == NULL) {
74                         if (!display_adv) {
75                                 weston_log("WARNING app_is is null, unable to advertise\n");
76                                 display_adv = true;
77                         }
78                         return;
79                 }
80                 agl_shell_desktop_send_application(dclient->resource, app_id);
81                 surface->advertised_on_launch = true;
82         }
83 }
84
85 void
86 ivi_set_desktop_surface(struct ivi_surface *surface)
87 {
88         struct ivi_compositor *ivi = surface->ivi;
89         assert(surface->role == IVI_SURFACE_ROLE_NONE);
90
91         surface->role = IVI_SURFACE_ROLE_DESKTOP;
92         wl_list_insert(&surface->ivi->surfaces, &surface->link);
93
94         agl_shell_desktop_advertise_application_id(ivi, surface);
95 }
96
97 static void
98 ivi_set_background_surface(struct ivi_surface *surface)
99 {
100         struct ivi_compositor *ivi = surface->ivi;
101         assert(surface->role == IVI_SURFACE_ROLE_BACKGROUND);
102
103         wl_list_insert(&surface->ivi->surfaces, &surface->link);
104         agl_shell_desktop_advertise_application_id(ivi, surface);
105 }
106
107 static void
108 ivi_set_desktop_surface_popup(struct ivi_surface *surface)
109 {
110         struct ivi_compositor *ivi = surface->ivi;
111         assert(surface->role == IVI_SURFACE_ROLE_NONE);
112
113         surface->role = IVI_SURFACE_ROLE_POPUP;
114         wl_list_insert(&ivi->surfaces, &surface->link);
115
116         agl_shell_desktop_advertise_application_id(ivi, surface);
117 }
118
119 static void
120 ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface)
121 {
122         struct ivi_compositor *ivi = surface->ivi;
123         assert(surface->role == IVI_SURFACE_ROLE_NONE);
124
125         surface->role = IVI_SURFACE_ROLE_FULLSCREEN;
126         wl_list_insert(&ivi->surfaces, &surface->link);
127
128         agl_shell_desktop_advertise_application_id(ivi, surface);
129 }
130
131 static void
132 ivi_set_desktop_surface_remote(struct ivi_surface *surface)
133 {
134         struct ivi_compositor *ivi = surface->ivi;
135         struct weston_view *view;
136         struct ivi_output *output = surface->remote.output;
137
138         assert(surface->role == IVI_SURFACE_ROLE_NONE);
139
140         /* remote type are the same as desktop just that client can tell
141          * the compositor to start on another output */
142         surface->role = IVI_SURFACE_ROLE_REMOTE;
143
144         /* if thew black surface view is mapped on the mean we need
145          * to remove it in order to start showing the 'remote' surface
146          * just being added */
147         view = output->fullscreen_view.fs->view;
148         if (view->is_mapped || view->surface->is_mapped)
149                 remove_black_curtain(output);
150
151         wl_list_insert(&ivi->surfaces, &surface->link);
152 }
153
154
155 static void
156 ivi_set_desktop_surface_split(struct ivi_surface *surface)
157 {
158         struct ivi_compositor *ivi = surface->ivi;
159         assert(surface->role == IVI_SURFACE_ROLE_NONE);
160
161         if (surface->split.orientation == AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL)
162                 surface->role = IVI_SURFACE_ROLE_SPLIT_V;
163         else
164                 surface->role = IVI_SURFACE_ROLE_SPLIT_H;
165
166         wl_list_insert(&ivi->surfaces, &surface->link);
167
168         agl_shell_desktop_advertise_application_id(ivi, surface);
169 }
170
171 static struct pending_popup *
172 ivi_ensure_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
173                  int width, int height, const char *app_id)
174 {
175         struct pending_popup *p_popup = zalloc(sizeof(*p_popup));
176         size_t len_app_id = strlen(app_id);
177
178         if (!p_popup)
179                 return NULL;
180         p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
181         if (!p_popup->app_id) {
182                 free(p_popup);
183                 return NULL;
184         }
185         memcpy(p_popup->app_id, app_id, len_app_id);
186         p_popup->ioutput = ioutput;
187         p_popup->x = x;
188         p_popup->y = y;
189
190         p_popup->bb.x = bx;
191         p_popup->bb.y = by;
192         p_popup->bb.width = width;
193         p_popup->bb.height = height;
194
195         return p_popup;
196 }
197
198 static void
199 ivi_update_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
200                  int width, int height, const char *app_id, struct pending_popup *p_popup)
201 {
202         size_t len_app_id = strlen(app_id);
203
204         wl_list_remove(&p_popup->link);
205         wl_list_init(&p_popup->link);
206
207         memset(p_popup->app_id, 0, strlen(app_id) + 1);
208         free(p_popup->app_id);
209
210         p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
211         if (!p_popup->app_id)
212                 return;
213         memcpy(p_popup->app_id, app_id, len_app_id);
214
215         p_popup->ioutput = ioutput;
216         p_popup->x = x;
217         p_popup->y = y;
218
219         p_popup->bb.x = bx;
220         p_popup->bb.y = by;
221         p_popup->bb.width = width;
222         p_popup->bb.height = height;
223 }
224
225 static struct pending_fullscreen *
226 ivi_ensure_fullscreen(struct ivi_output *ioutput, const char *app_id)
227 {
228         struct pending_fullscreen *p_fullscreen = zalloc(sizeof(*p_fullscreen));
229         size_t len_app_id = strlen(app_id);
230
231         if (!p_fullscreen)
232                 return NULL;
233         p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
234         if (!p_fullscreen->app_id) {
235                 free(p_fullscreen);
236                 return NULL;
237         }
238         memcpy(p_fullscreen->app_id, app_id, len_app_id);
239
240         p_fullscreen->ioutput = ioutput;
241         return p_fullscreen;
242 }
243
244 static void
245 ivi_update_fullscreen(struct ivi_output *ioutput, const char *app_id,
246                       struct pending_fullscreen *p_fullscreen)
247 {
248         size_t len_app_id = strlen(app_id);
249
250         wl_list_remove(&p_fullscreen->link);
251         wl_list_init(&p_fullscreen->link);
252
253         memset(p_fullscreen->app_id, 0, strlen(app_id) + 1);
254         free(p_fullscreen->app_id);
255
256         p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
257         if (!p_fullscreen->app_id)
258                 return;
259         memcpy(p_fullscreen->app_id, app_id, len_app_id);
260
261         p_fullscreen->ioutput = ioutput;
262 }
263
264 static struct pending_remote *
265 ivi_ensure_remote(struct ivi_output *ioutput, const char *app_id)
266 {
267         struct pending_remote *p_remote = zalloc(sizeof(*p_remote));
268         size_t len_app_id = strlen(app_id);
269
270         if (!p_remote)
271                 return NULL;
272         p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
273         if (!p_remote->app_id) {
274                 free(p_remote);
275                 return NULL;
276         }
277         memcpy(p_remote->app_id, app_id, len_app_id);
278
279         p_remote->ioutput = ioutput;
280         return p_remote;
281 }
282
283 static void
284 ivi_update_remote(struct ivi_output *ioutput, const char *app_id,
285                       struct pending_remote *p_remote)
286 {
287         size_t len_app_id = strlen(app_id);
288
289         wl_list_remove(&p_remote->link);
290         wl_list_init(&p_remote->link);
291
292         memset(p_remote->app_id, 0, strlen(app_id) + 1);
293         free(p_remote->app_id);
294
295         p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
296         if (!p_remote->app_id)
297                 return;
298         memcpy(p_remote->app_id, app_id, len_app_id);
299
300         p_remote->ioutput = ioutput;
301 }
302
303 static void
304 ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput, int x, int y, int bx,
305                                       int by, int width, int height, const char *app_id)
306 {
307         struct ivi_compositor *ivi = ioutput->ivi;
308         struct pending_popup *p_popup = NULL;
309         struct pending_popup *popup;
310
311         wl_list_for_each(popup, &ivi->popup_pending_apps, link)
312                 if (!strcmp(app_id, popup->app_id))
313                         p_popup = popup;
314
315         if (!p_popup)
316                 p_popup = ivi_ensure_popup(ioutput, x, y, bx, by, width, height, app_id);
317         else
318                 ivi_update_popup(ioutput, x, y, bx, by, width, height, app_id, p_popup);
319         if (!p_popup)
320                 return;
321
322         wl_list_insert(&ivi->popup_pending_apps, &p_popup->link);
323 }
324
325 static void
326 ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput,
327                                            const char *app_id)
328 {
329         struct ivi_compositor *ivi = ioutput->ivi;
330         struct pending_fullscreen *p_fullscreen = NULL;
331         struct pending_fullscreen *fullscreen;
332
333         wl_list_for_each(fullscreen, &ivi->fullscreen_pending_apps, link)
334                 if (!strcmp(app_id, fullscreen->app_id))
335                         p_fullscreen = fullscreen;
336
337         if (!p_fullscreen)
338                 p_fullscreen = ivi_ensure_fullscreen(ioutput, app_id);
339         else
340                 ivi_update_fullscreen(ioutput, app_id, p_fullscreen);
341
342         if (!p_fullscreen)
343                 return;
344         wl_list_insert(&ivi->fullscreen_pending_apps, &p_fullscreen->link);
345 }
346
347 static void
348 ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput,
349                                       const char *app_id, uint32_t orientation)
350 {
351         struct ivi_compositor *ivi = ioutput->ivi;
352         struct ivi_surface *surf;
353         size_t len_app_id = strlen(app_id);
354         struct pending_split *split;
355
356         if (orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL &&
357             orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL)
358                 return;
359
360         /* more than one is un-supported, do note we need to do
361          * conversion for surface roles instead of using the protocol ones */
362         wl_list_for_each(surf, &ivi->surfaces, link)
363                 if (surf->role == IVI_SURFACE_ROLE_SPLIT_V ||
364                     surf->role == IVI_SURFACE_ROLE_SPLIT_H)
365                         return;
366
367         split = zalloc(sizeof(*split));
368         if (!split)
369                 return;
370         split->app_id = zalloc(sizeof(char) * (len_app_id + 1));
371         if (!split->app_id) {
372                 free(split);
373                 return;
374         }
375         memcpy(split->app_id, app_id, len_app_id);
376
377         split->ioutput = ioutput;
378         split->orientation = orientation;
379
380         wl_list_insert(&ivi->split_pending_apps, &split->link);
381 }
382
383 void
384 ivi_set_pending_desktop_surface_remote(struct ivi_output *ioutput,
385                 const char *app_id)
386 {
387         struct ivi_compositor *ivi = ioutput->ivi;
388         struct pending_remote *remote;
389         struct pending_remote *p_remote = NULL;
390
391         wl_list_for_each(remote, &ivi->remote_pending_apps, link)
392                 if (!strcmp(app_id, remote->app_id))
393                         p_remote = remote;
394
395         if (!p_remote)
396                 p_remote = ivi_ensure_remote(ioutput, app_id);
397         else
398                 ivi_update_remote(ioutput, app_id, p_remote);
399         if (!p_remote)
400                 return;
401
402         wl_list_insert(&ivi->remote_pending_apps, &p_remote->link);
403 }
404
405
406 static void
407 ivi_remove_pending_desktop_surface_split(struct pending_split *split)
408 {
409         free(split->app_id);
410         wl_list_remove(&split->link);
411         free(split);
412 }
413
414 static void
415 ivi_remove_pending_desktop_surface_fullscreen(struct pending_fullscreen *fs)
416 {
417         free(fs->app_id);
418         wl_list_remove(&fs->link);
419         free(fs);
420 }
421
422 static void
423 ivi_remove_pending_desktop_surface_popup(struct pending_popup *p_popup)
424 {
425         free(p_popup->app_id);
426         wl_list_remove(&p_popup->link);
427         free(p_popup);
428 }
429
430 static void
431 ivi_remove_pending_desktop_surface_remote(struct pending_remote *remote)
432 {
433         free(remote->app_id);
434         wl_list_remove(&remote->link);
435         free(remote);
436 }
437
438 static bool
439 ivi_compositor_keep_pending_surfaces(struct ivi_surface *surface)
440 {
441         return surface->ivi->keep_pending_surfaces;
442 }
443
444 static bool
445 ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface)
446 {
447         struct ivi_compositor *ivi = surface->ivi;
448         struct pending_popup *p_popup, *next_p_popup;
449         const char *_app_id =
450                         weston_desktop_surface_get_app_id(surface->dsurface);
451
452         if (wl_list_empty(&ivi->popup_pending_apps) || !_app_id)
453                 return false;
454
455         wl_list_for_each_safe(p_popup, next_p_popup,
456                               &ivi->popup_pending_apps, link) {
457                 if (!strcmp(_app_id, p_popup->app_id)) {
458                         surface->popup.output = p_popup->ioutput;
459                         surface->popup.x = p_popup->x;
460                         surface->popup.y = p_popup->y;
461
462                         surface->popup.bb.x = p_popup->bb.x;
463                         surface->popup.bb.y = p_popup->bb.y;
464                         surface->popup.bb.width = p_popup->bb.width;
465                         surface->popup.bb.height = p_popup->bb.height;
466
467                         if (!ivi_compositor_keep_pending_surfaces(surface))
468                                 ivi_remove_pending_desktop_surface_popup(p_popup);
469                         return true;
470                 }
471         }
472
473         return false;
474 }
475
476 static bool
477 ivi_check_pending_desktop_surface_split(struct ivi_surface *surface)
478 {
479         struct pending_split *split_surf, *next_split_surf;
480         struct ivi_compositor *ivi = surface->ivi;
481         const char *_app_id =
482                         weston_desktop_surface_get_app_id(surface->dsurface);
483
484         if (wl_list_empty(&ivi->split_pending_apps) || !_app_id)
485                 return false;
486
487         wl_list_for_each_safe(split_surf, next_split_surf,
488                               &ivi->split_pending_apps, link) {
489                 if (!strcmp(_app_id, split_surf->app_id)) {
490                         surface->split.output = split_surf->ioutput;
491                         surface->split.orientation = split_surf->orientation;
492                         if (!ivi_compositor_keep_pending_surfaces(surface))
493                                 ivi_remove_pending_desktop_surface_split(split_surf);
494                         return true;
495                 }
496         }
497
498         return false;
499 }
500
501 static bool
502 ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface)
503 {
504         struct pending_fullscreen *fs_surf, *next_fs_surf;
505         struct ivi_compositor *ivi = surface->ivi;
506         const char *_app_id =
507                         weston_desktop_surface_get_app_id(surface->dsurface);
508
509         if (wl_list_empty(&ivi->fullscreen_pending_apps) || !_app_id)
510                 return false;
511
512         wl_list_for_each_safe(fs_surf, next_fs_surf,
513                               &ivi->fullscreen_pending_apps, link) {
514                 if (!strcmp(_app_id, fs_surf->app_id)) {
515                         surface->fullscreen.output = fs_surf->ioutput;
516                         if (!ivi_compositor_keep_pending_surfaces(surface))
517                                 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
518                         return true;
519                 }
520         }
521
522         return false;
523 }
524
525 static bool
526 ivi_check_pending_desktop_surface_remote(struct ivi_surface *surface)
527 {
528         struct pending_remote *remote_surf, *next_remote_surf;
529         struct ivi_compositor *ivi = surface->ivi;
530         const char *_app_id =
531                 weston_desktop_surface_get_app_id(surface->dsurface);
532
533         if (wl_list_empty(&ivi->remote_pending_apps) || !_app_id)
534                 return false;
535
536         wl_list_for_each_safe(remote_surf, next_remote_surf,
537                               &ivi->remote_pending_apps, link) {
538                 if (!strcmp(_app_id, remote_surf->app_id)) {
539                         surface->remote.output = remote_surf->ioutput;
540                         if (!ivi_compositor_keep_pending_surfaces(surface))
541                                 ivi_remove_pending_desktop_surface_remote(remote_surf);
542                         return true;
543                 }
544         }
545
546         return false;
547 }
548 void
549 ivi_check_pending_surface_desktop(struct ivi_surface *surface,
550                                   enum ivi_surface_role *role)
551 {
552         struct ivi_compositor *ivi = surface->ivi;
553         struct wl_list *role_pending_list;
554         struct pending_popup *p_popup;
555         struct pending_split *p_split;
556         struct pending_fullscreen *p_fullscreen;
557         struct pending_remote *p_remote;
558         const char *app_id =
559                 weston_desktop_surface_get_app_id(surface->dsurface);
560
561         role_pending_list = &ivi->popup_pending_apps;
562         wl_list_for_each(p_popup, role_pending_list, link) {
563                 if (app_id && !strcmp(app_id, p_popup->app_id)) {
564                         *role = IVI_SURFACE_ROLE_POPUP;
565                         return;
566                 }
567         }
568
569         role_pending_list = &ivi->split_pending_apps;
570         wl_list_for_each(p_split, role_pending_list, link) {
571                 if (app_id && !strcmp(app_id, p_split->app_id)) {
572                         *role = IVI_SURFACE_ROLE_SPLIT_V;
573                         return;
574                 }
575         }
576
577         role_pending_list = &ivi->fullscreen_pending_apps;
578         wl_list_for_each(p_fullscreen, role_pending_list, link) {
579                 if (app_id && !strcmp(app_id, p_fullscreen->app_id)) {
580                         *role = IVI_SURFACE_ROLE_FULLSCREEN;
581                         return;
582                 }
583         }
584
585         role_pending_list = &ivi->remote_pending_apps;
586         wl_list_for_each(p_remote, role_pending_list, link) {
587                 if (app_id && !strcmp(app_id, p_remote->app_id)) {
588                         *role = IVI_SURFACE_ROLE_REMOTE;
589                         return;
590                 }
591         }
592
593         /* else, we are a regular desktop surface */
594         *role = IVI_SURFACE_ROLE_DESKTOP;
595 }
596
597 struct pending_app *
598 ivi_check_pending_app_type(struct ivi_surface *surface, enum ivi_surface_role role)
599 {
600         struct pending_app *papp;
601         const char *app_id = NULL;
602
603         app_id = weston_desktop_surface_get_app_id(surface->dsurface);
604         if (!app_id)
605                 return NULL;
606
607         wl_list_for_each(papp, &surface->ivi->pending_apps, link) {
608                 if (strcmp(app_id, papp->app_id) == 0 && papp->role == role)
609                         return papp;
610         }
611
612         return NULL;
613 }
614  
615
616 void
617 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
618 {
619         bool ret = false;
620
621         ret = ivi_check_pending_desktop_surface_popup(surface);
622         if (ret) {
623                 ivi_set_desktop_surface_popup(surface);
624                 ivi_layout_popup_committed(surface);
625                 return;
626         }
627
628         ret = ivi_check_pending_desktop_surface_split(surface);
629         if (ret) {
630                 ivi_set_desktop_surface_split(surface);
631                 ivi_layout_split_committed(surface);
632                 return;
633         }
634
635         ret = ivi_check_pending_desktop_surface_fullscreen(surface);
636         if (ret) {
637                 ivi_set_desktop_surface_fullscreen(surface);
638                 ivi_layout_fullscreen_committed(surface);
639                 return;
640         }
641
642         ret = ivi_check_pending_desktop_surface_remote(surface);
643         if (ret) {
644                 ivi_set_desktop_surface_remote(surface);
645                 ivi_layout_remote_committed(surface);
646                 return;
647         }
648
649         /* new way of doing it */
650         struct pending_app *papp =
651                 ivi_check_pending_app_type(surface, IVI_SURFACE_ROLE_TILE);
652         if (papp) {
653                 struct pending_app_tile *papp_tile =
654                         container_of(papp, struct pending_app_tile, base);
655
656                 // handle the currently active surface
657                 if (papp->ioutput->active) {
658                         _ivi_set_shell_surface_split(papp->ioutput->active, NULL,
659                                         reverse_orientation(papp_tile->orientation), false);
660                 }
661
662                 surface->role = IVI_SURFACE_ROLE_TILE;
663                 surface->current_completed_output = papp->ioutput;
664                 wl_list_insert(&surface->ivi->surfaces, &surface->link);
665
666                 _ivi_set_shell_surface_split(surface, papp->ioutput,
667                                 papp_tile->orientation, true);
668
669                 /* remove it from pending */
670                 wl_list_remove(&papp->link);
671                 free(papp->app_id);
672                 free(papp);
673
674                 return;
675         }
676
677         /* if we end up here means we have a regular desktop app and
678          * try to activate it */
679         ivi_set_desktop_surface(surface);
680         ivi_layout_desktop_committed(surface);
681 }
682
683 void
684 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
685 {
686         struct ivi_output *out;
687
688         wl_list_for_each(out, &ivi->outputs, link) {
689                 create_black_curtain_view(out);
690                 insert_black_curtain(out);
691         }
692 }
693
694 int
695 ivi_shell_init(struct ivi_compositor *ivi)
696 {
697         weston_layer_init(&ivi->hidden, ivi->compositor);
698         weston_layer_init(&ivi->background, ivi->compositor);
699         weston_layer_init(&ivi->normal, ivi->compositor);
700         weston_layer_init(&ivi->panel, ivi->compositor);
701         weston_layer_init(&ivi->popup, ivi->compositor);
702         weston_layer_init(&ivi->fullscreen, ivi->compositor);
703
704         weston_layer_set_position(&ivi->hidden,
705                                   WESTON_LAYER_POSITION_HIDDEN);
706         weston_layer_set_position(&ivi->background,
707                                   WESTON_LAYER_POSITION_BACKGROUND);
708         weston_layer_set_position(&ivi->normal,
709                                   WESTON_LAYER_POSITION_NORMAL);
710         weston_layer_set_position(&ivi->panel,
711                                   WESTON_LAYER_POSITION_UI);
712         weston_layer_set_position(&ivi->popup,
713                                   WESTON_LAYER_POSITION_TOP_UI);
714         weston_layer_set_position(&ivi->fullscreen,
715                                   WESTON_LAYER_POSITION_FULLSCREEN);
716
717         return 0;
718 }
719
720
721 static void
722 ivi_surf_destroy(struct ivi_surface *surf)
723 {
724         struct weston_surface *wsurface = surf->view->surface;
725
726         if (weston_surface_is_mapped(wsurface)) {
727                 weston_desktop_surface_unlink_view(surf->view);
728                 weston_view_destroy(surf->view);
729         }
730
731         wl_list_remove(&surf->link);
732         free(surf);
733 }
734
735 static void
736 ivi_shell_destroy_views_on_layer(struct weston_layer *layer)
737 {
738         struct weston_view *view, *view_next;
739
740         wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) {
741                 struct ivi_surface *ivi_surf =
742                         get_ivi_shell_surface(view->surface);
743                 if (ivi_surf)
744                         ivi_surf_destroy(ivi_surf);
745         }
746 }
747
748 void
749 ivi_shell_finalize(struct ivi_compositor *ivi)
750 {
751         struct ivi_output *output;
752
753         ivi_shell_destroy_views_on_layer(&ivi->hidden);
754         weston_layer_fini(&ivi->hidden);
755
756         ivi_shell_destroy_views_on_layer(&ivi->background);
757         weston_layer_fini(&ivi->background);
758
759         ivi_shell_destroy_views_on_layer(&ivi->normal);
760         weston_layer_fini(&ivi->normal);
761
762         ivi_shell_destroy_views_on_layer(&ivi->panel);
763         weston_layer_fini(&ivi->panel);
764
765         ivi_shell_destroy_views_on_layer(&ivi->popup);
766         weston_layer_fini(&ivi->popup);
767
768         wl_list_for_each(output, &ivi->outputs, link) {
769                 if (output->fullscreen_view.fs &&
770                     output->fullscreen_view.fs->view) {
771                         weston_surface_destroy(output->fullscreen_view.fs->view->surface);
772                         output->fullscreen_view.fs->view = NULL;
773                 }
774         }
775         weston_layer_fini(&ivi->fullscreen);
776 }
777
778 static void
779 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
780 {
781         struct ivi_surface *surface;
782
783         wl_list_for_each(surface, &ivi->surfaces, link) {
784                 const char *app_id =
785                         weston_desktop_surface_get_app_id(surface->dsurface);
786                 if (app_id == NULL) {
787                         weston_log("WARNING app_is is null, unable to advertise\n");
788                         return;
789                 }
790                 agl_shell_desktop_send_application(resource, app_id);
791         }
792 }
793
794 static struct wl_client *
795 client_launch(struct weston_compositor *compositor,
796                      struct weston_process *proc,
797                      const char *path,
798                      weston_process_cleanup_func_t cleanup)
799 {
800         struct wl_client *client = NULL;
801         struct custom_env child_env;
802         struct fdstr wayland_socket;
803         const char *fail_cloexec = "Couldn't unset CLOEXEC on client socket";
804         const char *fail_seteuid = "Couldn't call seteuid";
805         char *fail_exec;
806         char * const *argp;
807         char * const *envp;
808         sigset_t allsigs;
809         pid_t pid;
810         bool ret;
811         struct ivi_compositor *ivi;
812         size_t written __attribute__((unused));
813
814         weston_log("launching '%s'\n", path);
815         str_printf(&fail_exec, "Error: Couldn't launch client '%s'\n", path);
816
817         custom_env_init_from_environ(&child_env);
818         custom_env_add_from_exec_string(&child_env, path);
819
820         if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0,
821                                   wayland_socket.fds) < 0) {
822                 weston_log("client_launch: "
823                            "socketpair failed while launching '%s': %s\n",
824                            path, strerror(errno));
825                 custom_env_fini(&child_env);
826                 return NULL;
827         }
828         fdstr_update_str1(&wayland_socket);
829         custom_env_set_env_var(&child_env, "WAYLAND_SOCKET",
830                                wayland_socket.str1);
831
832         argp = custom_env_get_argp(&child_env);
833         envp = custom_env_get_envp(&child_env);
834
835         pid = fork();
836         switch (pid) {
837         case 0:
838                 /* Put the client in a new session so it won't catch signals
839                  * intended for the parent. Sharing a session can be
840                  * confusing when launching weston under gdb, as the ctrl-c
841                  * intended for gdb will pass to the child, and weston
842                  * will cleanly shut down when the child exits.
843                  */
844                 setsid();
845
846                 /* do not give our signal mask to the new process */
847                 sigfillset(&allsigs);
848                 sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
849
850                 /* Launch clients as the user. Do not launch clients with wrong euid. */
851                 if (seteuid(getuid()) == -1) {
852                         written = write(STDERR_FILENO, fail_seteuid, strlen(fail_seteuid));
853                         _exit(EXIT_FAILURE);
854                 }
855
856                 ret = fdstr_clear_cloexec_fd1(&wayland_socket);
857                 if (!ret) {
858                         written = write(STDERR_FILENO, fail_cloexec, strlen(fail_cloexec));
859                         _exit(EXIT_FAILURE);
860                 }
861
862                 execve(argp[0], argp, envp);
863
864                 if (fail_exec)
865                         written = write(STDERR_FILENO, fail_exec, strlen(fail_exec));
866                 _exit(EXIT_FAILURE);
867
868         default:
869                 close(wayland_socket.fds[1]);
870                 ivi = weston_compositor_get_user_data(compositor);
871                 client = wl_client_create(compositor->wl_display,
872                                           wayland_socket.fds[0]);
873                 if (!client) {
874                         custom_env_fini(&child_env);
875                         close(wayland_socket.fds[0]);
876                         free(fail_exec);
877                         weston_log("client_launch: "
878                                 "wl_client_create failed while launching '%s'.\n",
879                                 path);
880                         return NULL;
881                 }
882
883                 proc->pid = pid;
884                 proc->cleanup = cleanup;
885                 wl_list_insert(&ivi->child_process_list, &proc->link);
886                 break;
887
888         case -1:
889                 fdstr_close_all(&wayland_socket);
890                 weston_log("client_launch: "
891                            "fork failed while launching '%s': %s\n", path,
892                            strerror(errno));
893                 break;
894         }
895
896         custom_env_fini(&child_env);
897         free(fail_exec);
898
899         return client;
900 }
901
902 struct process_info {
903         struct weston_process proc;
904         char *path;
905 };
906
907 int
908 sigchld_handler(int signal_number, void *data)
909 {
910         struct weston_process *p;
911         struct ivi_compositor *ivi = data;
912         int status;
913         pid_t pid;
914
915         while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
916                 wl_list_for_each(p, &ivi->child_process_list, link) {
917                         if (p->pid == pid)
918                                 break;
919                 }
920
921                 if (&p->link == &ivi->child_process_list) {
922                         weston_log("unknown child process exited\n");
923                         continue;
924                 }
925
926                 wl_list_remove(&p->link);
927                 wl_list_init(&p->link);
928                 p->cleanup(p, status);
929         }
930
931         if (pid < 0 && errno != ECHILD)
932                 weston_log("waitpid error %s\n", strerror(errno));
933
934         return 1;
935 }
936
937
938 static void
939 process_handle_sigchld(struct weston_process *process, int status)
940 {
941         struct process_info *pinfo =
942                 container_of(process, struct process_info, proc);
943
944         /*
945          * There are no guarantees whether this runs before or after
946          * the wl_client destructor.
947          */
948
949         if (WIFEXITED(status)) {
950                 weston_log("%s exited with status %d\n", pinfo->path,
951                            WEXITSTATUS(status));
952         } else if (WIFSIGNALED(status)) {
953                 weston_log("%s died on signal %d\n", pinfo->path,
954                            WTERMSIG(status));
955         } else {
956                 weston_log("%s disappeared\n", pinfo->path);
957         }
958
959         free(pinfo->path);
960         free(pinfo);
961 }
962
963 int
964 ivi_launch_shell_client(struct ivi_compositor *ivi, const char *cmd_section,
965                         struct wl_client **client)
966 {
967         struct process_info *pinfo;
968         struct weston_config_section *section;
969         char *command = NULL;
970
971         section = weston_config_get_section(ivi->config, cmd_section, NULL, NULL);
972         if (section)
973                 weston_config_section_get_string(section, "command", &command, NULL);
974
975         if (!command)
976                 return -1;
977
978         pinfo = zalloc(sizeof *pinfo);
979         if (!pinfo)
980                 return -1;
981
982         pinfo->path = strdup(command);
983         if (!pinfo->path)
984                 goto out_free;
985
986         *client = client_launch(ivi->compositor, &pinfo->proc, command, process_handle_sigchld);
987         if (!*client)
988                 goto out_str;
989
990         return 0;
991
992 out_str:
993         free(pinfo->path);
994
995 out_free:
996         free(pinfo);
997
998         return -1;
999 }
1000
1001 static void
1002 destroy_black_curtain_view(struct wl_listener *listener, void *data)
1003 {
1004         struct fullscreen_view *fs =
1005                 wl_container_of(listener, fs, fs_destroy);
1006
1007
1008         if (fs && fs->fs) {
1009                 wl_list_remove(&fs->fs_destroy.link);
1010                 free(fs->fs);
1011         }
1012 }
1013
1014
1015 static void
1016 create_black_curtain_view(struct ivi_output *output)
1017 {
1018         struct weston_surface *surface = NULL;
1019         struct weston_view *view;
1020         struct ivi_compositor *ivi = output->ivi;
1021         struct weston_compositor *wc= ivi->compositor;
1022         struct weston_output *woutput = output->output;
1023
1024         if (!woutput)
1025                 return;
1026
1027         surface = weston_surface_create(wc);
1028         if (!surface)
1029                 return;
1030         view = weston_view_create(surface);
1031         if (!view) {
1032                 weston_surface_destroy(surface);
1033                 return;
1034         }
1035
1036         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
1037         weston_surface_set_size(surface, woutput->width, woutput->height);
1038         weston_view_set_position(view, woutput->x, woutput->y);
1039
1040         output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
1041         if (!output->fullscreen_view.fs) {
1042                 weston_surface_destroy(surface);
1043                 return;
1044         }
1045         output->fullscreen_view.fs->view = view;
1046
1047         output->fullscreen_view.fs_destroy.notify = destroy_black_curtain_view;
1048         wl_signal_add(&woutput->destroy_signal,
1049                       &output->fullscreen_view.fs_destroy);
1050 }
1051
1052 bool
1053 output_has_black_curtain(struct ivi_output *output)
1054 {
1055         return (output->fullscreen_view.fs &&
1056                 output->fullscreen_view.fs->view &&
1057                 output->fullscreen_view.fs->view->is_mapped &&
1058                 output->fullscreen_view.fs->view->surface->is_mapped);
1059 }
1060
1061 void
1062 remove_black_curtain(struct ivi_output *output)
1063 {
1064         struct weston_view *view;
1065
1066         if ((!output &&
1067             !output->fullscreen_view.fs &&
1068             !output->fullscreen_view.fs->view) ||
1069             !output->fullscreen_view.fs) {
1070                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1071                 return;
1072         }
1073
1074         view = output->fullscreen_view.fs->view;
1075         assert(view->is_mapped == true ||
1076                view->surface->is_mapped == true);
1077
1078         view->is_mapped = false;
1079         view->surface->is_mapped = false;
1080
1081         weston_layer_entry_remove(&view->layer_link);
1082         weston_view_update_transform(view);
1083
1084         weston_view_damage_below(view);
1085
1086         weston_log("Removed black curtain from output %s\n", output->output->name);
1087 }
1088
1089 void
1090 insert_black_curtain(struct ivi_output *output)
1091 {
1092         struct weston_view *view;
1093
1094         if ((!output &&
1095             !output->fullscreen_view.fs &&
1096             !output->fullscreen_view.fs->view) || !output->output ||
1097             !output->fullscreen_view.fs) {
1098                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1099                 return;
1100         }
1101
1102         view = output->fullscreen_view.fs->view;
1103         if (view->is_mapped || view->surface->is_mapped)
1104                 return;
1105
1106         weston_layer_entry_remove(&view->layer_link);
1107         weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
1108                                   &view->layer_link);
1109
1110         view->is_mapped = true;
1111         view->surface->is_mapped = true;
1112
1113         weston_view_update_transform(view);
1114         weston_view_damage_below(view);
1115
1116         weston_log("Added black curtain to output %s\n", output->output->name);
1117 }
1118
1119 void
1120 shell_send_app_state(struct ivi_compositor *ivi, const char *app_id,
1121                      enum agl_shell_app_state state)
1122 {
1123         if (app_id && wl_resource_get_version(ivi->shell_client.resource) >=
1124             AGL_SHELL_APP_STATE_SINCE_VERSION) {
1125
1126                 agl_shell_send_app_state(ivi->shell_client.resource,
1127                                          app_id, state);
1128
1129                 if (ivi->shell_client.resource_ext)
1130                         agl_shell_send_app_state(ivi->shell_client.resource_ext,
1131                                                  app_id, state);
1132         }
1133 }
1134
1135 void
1136 shell_send_app_on_output(struct ivi_compositor *ivi, const char *app_id,
1137                          const char *output_name)
1138 {
1139         if (app_id && ivi->shell_client.resource &&
1140             wl_resource_get_version(ivi->shell_client.resource) >=
1141             AGL_SHELL_APP_ON_OUTPUT_SINCE_VERSION) {
1142
1143                 agl_shell_send_app_on_output(ivi->shell_client.resource,
1144                                          app_id, output_name);
1145
1146                 if (ivi->shell_client.resource_ext)
1147                         agl_shell_send_app_on_output(ivi->shell_client.resource_ext,
1148                                                  app_id, output_name);
1149         }
1150 }
1151
1152 static void
1153 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
1154 {
1155         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1156         struct ivi_output *output;
1157         struct ivi_surface *surface, *tmp;
1158
1159         if (wl_resource_get_version(shell_res) >=
1160             AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1161             ivi->shell_client.status == BOUND_FAILED) {
1162                 wl_resource_post_error(shell_res,
1163                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1164                                        "agl_shell (ready quest) has already "
1165                                        "been bound. Check out bound_fail event");
1166                 return;
1167         }
1168
1169         /* Init already finished. Do nothing */
1170         if (ivi->shell_client.ready)
1171                 return;
1172
1173
1174         ivi->shell_client.ready = true;
1175
1176         wl_list_for_each(output, &ivi->outputs, link) {
1177                 if (output->background &&
1178                     output->background->role == IVI_SURFACE_ROLE_BACKGROUND) {
1179                         /* track the background surface role as a "regular"
1180                          * surface so we can activate it */
1181                         ivi_set_background_surface(output->background);
1182                         remove_black_curtain(output);
1183                 }
1184
1185                 ivi_layout_init(ivi, output);
1186         }
1187
1188         wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
1189                 const char *app_id;
1190
1191                 wl_list_remove(&surface->link);
1192                 wl_list_init(&surface->link);
1193                 ivi_check_pending_desktop_surface(surface);
1194                 surface->checked_pending = true;
1195                 app_id = weston_desktop_surface_get_app_id(surface->dsurface);
1196
1197                 shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_STARTED);
1198         }
1199 }
1200
1201 static void
1202 shell_set_background(struct wl_client *client,
1203                      struct wl_resource *shell_res,
1204                      struct wl_resource *surface_res,
1205                      struct wl_resource *output_res)
1206 {
1207         struct weston_head *head = weston_head_from_resource(output_res);
1208         struct weston_output *woutput = weston_head_get_output(head);
1209         struct ivi_output *output = to_ivi_output(woutput);
1210         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1211         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1212         struct weston_desktop_surface *dsurface;
1213         struct ivi_surface *surface;
1214
1215         if ((wl_resource_get_version(shell_res) >=
1216             AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1217             ivi->shell_client.status == BOUND_FAILED) ||
1218             ivi->shell_client.resource_ext == shell_res) {
1219                 wl_resource_post_error(shell_res,
1220                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1221                                        "agl_shell (set_background) has already "
1222                                        "been bound. Check out bound_fail event");
1223                 return;
1224         }
1225
1226         dsurface = weston_surface_get_desktop_surface(wsurface);
1227         if (!dsurface) {
1228                 wl_resource_post_error(shell_res,
1229                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1230                                        "surface must be a desktop surface");
1231                 return;
1232         }
1233
1234         surface = weston_desktop_surface_get_user_data(dsurface);
1235         if (surface->role != IVI_SURFACE_ROLE_NONE) {
1236                 wl_resource_post_error(shell_res,
1237                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1238                                        "surface already has another ivi role");
1239                 return;
1240         }
1241
1242         if (output->background) {
1243                 wl_resource_post_error(shell_res,
1244                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1245                                        "output already has background");
1246                 return;
1247         }
1248
1249         surface->checked_pending = true;
1250         surface->role = IVI_SURFACE_ROLE_BACKGROUND;
1251         surface->bg.output = output;
1252         wl_list_remove(&surface->link);
1253         wl_list_init(&surface->link);
1254
1255         output->background = surface;
1256
1257         weston_desktop_surface_set_maximized(dsurface, true);
1258         weston_desktop_surface_set_size(dsurface,
1259                                         output->output->width,
1260                                         output->output->height);
1261 }
1262
1263 static void
1264 shell_set_panel(struct wl_client *client,
1265                 struct wl_resource *shell_res,
1266                 struct wl_resource *surface_res,
1267                 struct wl_resource *output_res,
1268                 uint32_t edge)
1269 {
1270         struct weston_head *head = weston_head_from_resource(output_res);
1271         struct weston_output *woutput = weston_head_get_output(head);
1272         struct ivi_output *output = to_ivi_output(woutput);
1273         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1274         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1275         struct weston_desktop_surface *dsurface;
1276         struct ivi_surface *surface;
1277         struct ivi_surface **member;
1278         int32_t width = 0, height = 0;
1279
1280         if ((wl_resource_get_version(shell_res) >=
1281              AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1282              ivi->shell_client.status == BOUND_FAILED) ||
1283             ivi->shell_client.resource_ext == shell_res) {
1284                 wl_resource_post_error(shell_res,
1285                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1286                                        "agl_shell (set_panel) has already been bound. "
1287                                        "Check out bound_fail event");
1288                 return;
1289         }
1290
1291         dsurface = weston_surface_get_desktop_surface(wsurface);
1292         if (!dsurface) {
1293                 wl_resource_post_error(shell_res,
1294                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1295                                        "surface must be a desktop surface");
1296                 return;
1297         }
1298
1299         surface = weston_desktop_surface_get_user_data(dsurface);
1300         if (surface->role != IVI_SURFACE_ROLE_NONE) {
1301                 wl_resource_post_error(shell_res,
1302                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1303                                        "surface already has another ivi role");
1304                 return;
1305         }
1306
1307         switch (edge) {
1308         case AGL_SHELL_EDGE_TOP:
1309                 member = &output->top;
1310                 break;
1311         case AGL_SHELL_EDGE_BOTTOM:
1312                 member = &output->bottom;
1313                 break;
1314         case AGL_SHELL_EDGE_LEFT:
1315                 member = &output->left;
1316                 break;
1317         case AGL_SHELL_EDGE_RIGHT:
1318                 member = &output->right;
1319                 break;
1320         default:
1321                 wl_resource_post_error(shell_res,
1322                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
1323                                        "invalid edge for panel");
1324                 return;
1325         }
1326
1327         if (*member) {
1328                 wl_resource_post_error(shell_res,
1329                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1330                                        "output already has panel on this edge");
1331                 return;
1332         }
1333
1334         surface->checked_pending = true;
1335         surface->role = IVI_SURFACE_ROLE_PANEL;
1336         surface->panel.output = output;
1337         surface->panel.edge = edge;
1338         wl_list_remove(&surface->link);
1339         wl_list_init(&surface->link);
1340
1341         *member = surface;
1342
1343         switch (surface->panel.edge) {
1344         case AGL_SHELL_EDGE_TOP:
1345         case AGL_SHELL_EDGE_BOTTOM:
1346                 width = woutput->width;
1347                 break;
1348         case AGL_SHELL_EDGE_LEFT:
1349         case AGL_SHELL_EDGE_RIGHT:
1350                 height = woutput->height;
1351                 break;
1352         }
1353
1354         weston_desktop_surface_set_size(dsurface, width, height);
1355 }
1356
1357 void
1358 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
1359                           const char *data, uint32_t app_state)
1360 {
1361         struct desktop_client *dclient;
1362         uint32_t app_role;
1363         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1364         struct ivi_policy *policy = ivi->policy;
1365
1366         /* FIXME: should queue it here and see when binding agl-shell-desktop
1367          * if there are any to be sent */
1368         if (!surf)
1369                 return;
1370
1371         if (!app_id)
1372                 return;
1373
1374         if (policy && policy->api.surface_advertise_state_change &&
1375             !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
1376                 return;
1377         }
1378
1379         app_role = surf->role;
1380         if (app_role == IVI_SURFACE_ROLE_POPUP)
1381                 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
1382
1383         wl_list_for_each(dclient, &ivi->desktop_clients, link)
1384                 agl_shell_desktop_send_state_app(dclient->resource, app_id,
1385                                                  data, app_state, app_role);
1386 }
1387
1388 static void
1389 shell_activate_app(struct wl_client *client,
1390                    struct wl_resource *shell_res,
1391                    const char *app_id,
1392                    struct wl_resource *output_res)
1393 {
1394         struct weston_head *head;
1395         struct weston_output *woutput;
1396         struct ivi_compositor *ivi;
1397         struct ivi_output *output;
1398
1399         head = weston_head_from_resource(output_res);
1400         if (!head) {
1401                 weston_log("Invalid output to activate '%s' on\n", app_id);
1402                 return;
1403         }
1404
1405         woutput = weston_head_get_output(head);
1406         ivi = wl_resource_get_user_data(shell_res);
1407         output = to_ivi_output(woutput);
1408
1409         if (wl_resource_get_version(shell_res) >=
1410             AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1411             ivi->shell_client.status == BOUND_FAILED) {
1412                 wl_resource_post_error(shell_res,
1413                                        WL_DISPLAY_ERROR_INVALID_OBJECT,
1414                                        "agl_shell has already been bound. "
1415                                        "Check out bound_fail event");
1416                 return;
1417         }
1418
1419         ivi_layout_activate(output, app_id);
1420 }
1421
1422 static void
1423 shell_new_deactivate_app(struct wl_client *client, struct wl_resource *shell_res,
1424                          const char *app_id)
1425 {
1426         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1427
1428         ivi_layout_deactivate(ivi, app_id);
1429 }
1430
1431 static void
1432 shell_set_app_float(struct wl_client *client, struct wl_resource *shell_res,
1433                    const char *app_id, int32_t x_pos, int32_t y_pos)
1434 {
1435         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1436         struct weston_output *output = get_focused_output(ivi->compositor);
1437         struct ivi_output *ivi_output;
1438         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1439
1440         if (!output)
1441                 output = get_default_output(ivi->compositor);
1442
1443         ivi_output = to_ivi_output(output);
1444
1445         /* verify if already mapped as desktop role, regular, unmap it, so we
1446          * can make it float */
1447         if (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1448                 struct weston_view *ev = surf->view;
1449                 struct weston_desktop_surface *dsurf = surf->dsurface;
1450                 struct ivi_bounding_box bb = {};
1451                 const char *prev_activate_app_id = NULL;
1452
1453                 /* XXX: if this is useful we could bring it as active then make
1454                  * it float, but avoid doing it for the moment */
1455                 if (surf != ivi_output->active)
1456                         return;
1457
1458                 if (ivi_output->previous_active)
1459                         prev_activate_app_id =
1460                                 weston_desktop_surface_get_app_id(ivi_output->previous_active->dsurface);
1461
1462                 /* only deactivate if previous_active is different, otherwise
1463                  * this will blow up, because we're trying to activate the same
1464                  * app_id as the this one! */
1465                 if (prev_activate_app_id && strcmp(app_id, prev_activate_app_id)) {
1466                         ivi_layout_deactivate(ivi, app_id);
1467                 } else if (prev_activate_app_id) {
1468                         weston_layer_entry_remove(&ev->layer_link);
1469                         weston_view_geometry_dirty(ev);
1470                         weston_surface_damage(ev->surface);
1471                 }
1472
1473                 surf->hidden_layer_output = ivi_output;
1474
1475                 /* set attributes */
1476                 surf->popup.output = ivi_output;
1477
1478                 surf->popup.x = x_pos;
1479                 surf->popup.y = y_pos;
1480                 surf->popup.bb = bb;
1481
1482
1483                 /* change the role */
1484                 surf->role = IVI_SURFACE_ROLE_NONE;
1485
1486                 wl_list_remove(&surf->link);
1487                 wl_list_init(&surf->link);
1488
1489                 ivi_set_desktop_surface_popup(surf);
1490
1491                 weston_desktop_surface_set_maximized(dsurf, false);
1492                 weston_desktop_surface_set_size(dsurf, 0, 0);
1493
1494                 /* add to hidden layer */
1495                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
1496                 weston_compositor_schedule_repaint(ivi->compositor);
1497
1498         } else if (!surf || (surf && surf->role != IVI_SURFACE_ROLE_POPUP)) {
1499                 ivi_set_pending_desktop_surface_popup(ivi_output, x_pos, y_pos, 
1500                                                       0, 0, 0, 0, app_id);
1501         }
1502 }
1503
1504 static void
1505 shell_set_app_fullscreen(struct wl_client *client,
1506                          struct wl_resource *shell_res, const char *app_id)
1507 {
1508         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1509         struct weston_output *output = get_focused_output(ivi->compositor);
1510         struct ivi_output *ivi_output;
1511         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1512
1513         if (!output)
1514                 output = get_default_output(ivi->compositor);
1515
1516         ivi_output = to_ivi_output(output);
1517
1518         if (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1519                 struct weston_view *ev = surf->view;
1520                 struct weston_desktop_surface *dsurf = surf->dsurface;
1521
1522                 if (surf != ivi_output->active)
1523                         return;
1524
1525                 weston_layer_entry_remove(&surf->view->layer_link);
1526                 weston_view_geometry_dirty(surf->view);
1527                 weston_surface_damage(surf->view->surface);
1528
1529                 surf->hidden_layer_output = ivi_output;
1530
1531                 /* set attributes */
1532                 surf->fullscreen.output = ivi_output;
1533
1534                 /* change the role */
1535                 surf->role = IVI_SURFACE_ROLE_NONE;
1536
1537                 wl_list_remove(&surf->link);
1538                 wl_list_init(&surf->link);
1539
1540                 ivi_set_desktop_surface_fullscreen(surf);
1541
1542                 weston_desktop_surface_set_maximized(dsurf, false);
1543                 weston_desktop_surface_set_fullscreen(dsurf, true);
1544                 weston_desktop_surface_set_size(dsurf,
1545                                                 ivi_output->output->width,
1546                                                 ivi_output->output->height);
1547
1548                 /* add to hidden layer */
1549                 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
1550                 weston_compositor_schedule_repaint(ivi->compositor);
1551         } else if (!surf || (surf && surf->role != IVI_SURFACE_ROLE_FULLSCREEN)) {
1552                 ivi_set_pending_desktop_surface_fullscreen(ivi_output, app_id);
1553         }
1554 }
1555
1556
1557 static void
1558 shell_set_app_normal(struct wl_client *client, struct wl_resource *shell_res,
1559                      const char *app_id)
1560 {
1561         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1562         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1563         struct weston_output *output = get_focused_output(ivi->compositor);
1564         struct ivi_output *ivi_output;
1565         struct weston_desktop_surface *dsurf;
1566         struct weston_geometry area = {};
1567
1568
1569         if (!surf || (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP))
1570                 return;
1571
1572         if (!output)
1573                 output = get_default_output(ivi->compositor);
1574
1575         dsurf = surf->dsurface;
1576         ivi_output = to_ivi_output(output);
1577
1578         weston_layer_entry_remove(&surf->view->layer_link);
1579         weston_view_geometry_dirty(surf->view);
1580         weston_surface_damage(surf->view->surface);
1581
1582         /* change the role */
1583         surf->role = IVI_SURFACE_ROLE_NONE;
1584         surf->state = NORMAL;
1585         surf->desktop.pending_output = ivi_output;
1586
1587         wl_list_remove(&surf->link);
1588         wl_list_init(&surf->link);
1589
1590         ivi_set_desktop_surface(surf);
1591
1592         if (ivi_output->area_activation.width ||
1593             ivi_output->area_activation.height)
1594                 area = ivi_output->area_activation;
1595         else
1596                 area = ivi_output->area;
1597
1598         if (weston_desktop_surface_get_fullscreen(dsurf))
1599                 weston_desktop_surface_set_fullscreen(dsurf, false);
1600
1601         weston_desktop_surface_set_maximized(dsurf, true);
1602         weston_desktop_surface_set_size(dsurf, area.width, area.height);
1603
1604         /* add to hidden layer */
1605         weston_layer_entry_insert(&ivi->hidden.view_list,
1606                                   &surf->view->layer_link);
1607         weston_compositor_schedule_repaint(ivi->compositor);
1608
1609 }
1610
1611 static void
1612 shell_desktop_activate_app(struct wl_client *client,
1613                            struct wl_resource *shell_res,
1614                            const char *app_id, const char *data,
1615                            struct wl_resource *output_res)
1616 {
1617         struct weston_head *head = weston_head_from_resource(output_res);
1618         struct weston_output *woutput = weston_head_get_output(head);
1619         struct ivi_output *output = to_ivi_output(woutput);
1620
1621         ivi_layout_activate(output, app_id);
1622         shell_advertise_app_state(output->ivi, app_id,
1623                                   data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
1624 }
1625
1626 static void
1627 shell_deactivate_app(struct wl_client *client,
1628                    struct wl_resource *shell_res,
1629                    const char *app_id)
1630 {
1631         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1632         struct ivi_compositor *ivi = dclient->ivi;
1633
1634         ivi_layout_deactivate(ivi, app_id);
1635         shell_advertise_app_state(ivi, app_id,
1636                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
1637 }
1638
1639 static void
1640 shell_destroy(struct wl_client *client, struct wl_resource *res)
1641 {
1642         struct  ivi_compositor *ivi = wl_resource_get_user_data(res);
1643
1644         /* reset status in case bind_fail was sent */
1645         if (wl_resource_get_version(res) >= AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1646             ivi->shell_client.status == BOUND_FAILED)
1647                 ivi->shell_client.status = BOUND_OK;
1648 }
1649
1650 static void
1651 shell_set_activate_region(struct wl_client *client, struct wl_resource *res,
1652                          struct wl_resource *output, int x, int y,
1653                          int width, int height)
1654 {
1655        struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1656        struct weston_head *head = weston_head_from_resource(output);
1657        struct weston_output *woutput = weston_head_get_output(head);
1658        struct ivi_output *ioutput = to_ivi_output(woutput);
1659
1660        struct weston_geometry area = { .x = x, .y = y,
1661                                        .width = width,
1662                                        .height = height };
1663        if (ivi->shell_client.ready)
1664                return;
1665
1666        ioutput->area_activation = area;
1667 }
1668
1669 static void
1670 shell_set_app_output(struct wl_client *client, struct wl_resource *res,
1671                     const char *app_id, struct wl_resource *output)
1672 {
1673         struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1674         struct weston_head *head = weston_head_from_resource(output);
1675         struct weston_output *woutput = weston_head_get_output(head);
1676         struct ivi_output *ioutput = to_ivi_output(woutput);
1677         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1678         struct ivi_output *desktop_last_output;
1679         struct ivi_output *current_completed_output;
1680
1681         if (!app_id || !ioutput)
1682                 return;
1683
1684         /* handle the case we're not mapped at all */
1685         if (!surf) {
1686                 ivi_set_pending_desktop_surface_remote(ioutput, app_id);
1687                 shell_send_app_on_output(ivi, app_id, woutput->name);
1688                 return;
1689         }
1690
1691         desktop_last_output = surf->desktop.last_output;
1692         current_completed_output = surf->current_completed_output;
1693
1694         if (surf->remote.output)
1695                 surf->hidden_layer_output = surf->remote.output;
1696         else
1697                 surf->hidden_layer_output = desktop_last_output;
1698         assert(surf->hidden_layer_output);
1699
1700         if (ivi_surface_count_one(current_completed_output, IVI_SURFACE_ROLE_REMOTE) ||
1701             ivi_surface_count_one(current_completed_output, IVI_SURFACE_ROLE_DESKTOP)) {
1702                 if (!current_completed_output->background)
1703                         insert_black_curtain(current_completed_output);
1704         } else {
1705                 ivi_layout_deactivate(ivi, app_id);
1706         }
1707
1708         /* update the remote output */
1709         surf->remote.output = ioutput;
1710
1711         if (surf->role != IVI_SURFACE_ROLE_REMOTE) {
1712                 wl_list_remove(&surf->link);
1713                 wl_list_init(&surf->link);
1714
1715                 surf->role = IVI_SURFACE_ROLE_NONE;
1716                 ivi_set_desktop_surface_remote(surf);
1717         }
1718
1719         shell_send_app_on_output(ivi, app_id, woutput->name);
1720 }
1721
1722 static void
1723 shell_set_app_position(struct wl_client *client, struct wl_resource *res,
1724                     const char *app_id, int32_t x, int32_t y)
1725 {
1726         struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1727         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1728
1729         if (!surf || !app_id || surf->role != IVI_SURFACE_ROLE_POPUP)
1730                 return;
1731
1732         weston_view_set_position(surf->view, x, y);
1733         weston_compositor_schedule_repaint(ivi->compositor);
1734 }
1735
1736 static void
1737 shell_set_app_scale(struct wl_client *client, struct wl_resource *res,
1738                     const char *app_id, int32_t width, int32_t height)
1739 {
1740
1741         struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1742         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1743
1744         if (!surf || !app_id || surf->role != IVI_SURFACE_ROLE_POPUP)
1745                 return;
1746
1747         weston_desktop_surface_set_size(surf->dsurface, width, height);
1748         weston_compositor_schedule_repaint(ivi->compositor);
1749 }
1750
1751 static void
1752 _ivi_set_pending_desktop_surface_split(struct wl_resource *output,
1753                                        const char *app_id, uint32_t orientation)
1754 {
1755         weston_log("%s() added split surface for app_id '%s' with "
1756                 "orientation %d to pending\n", __func__, app_id, orientation);
1757
1758         struct weston_head *head = weston_head_from_resource(output);
1759         struct weston_output *woutput = weston_head_get_output(head);
1760         struct ivi_output *ivi_output = to_ivi_output(woutput);
1761
1762         struct pending_app_tile *app_tile = zalloc(sizeof(*app_tile));
1763
1764         app_tile->base.app_id = strdup(app_id);
1765         app_tile->base.ioutput = ivi_output;
1766         app_tile->base.role = IVI_SURFACE_ROLE_TILE;
1767
1768         app_tile->orientation = orientation;
1769         wl_list_insert(&ivi_output->ivi->pending_apps, &app_tile->base.link);
1770 }
1771
1772
1773 static uint32_t
1774 reverse_orientation(uint32_t orientation)
1775 {
1776
1777         switch (orientation) {
1778         case AGL_SHELL_TILE_ORIENTATION_LEFT:
1779                 return AGL_SHELL_TILE_ORIENTATION_RIGHT;
1780         break;
1781         case AGL_SHELL_TILE_ORIENTATION_RIGHT:
1782                 return AGL_SHELL_TILE_ORIENTATION_LEFT;
1783         break;
1784         case AGL_SHELL_TILE_ORIENTATION_TOP:
1785                 return AGL_SHELL_TILE_ORIENTATION_BOTTOM;
1786         break;
1787         case AGL_SHELL_TILE_ORIENTATION_BOTTOM:
1788                 return AGL_SHELL_TILE_ORIENTATION_TOP;
1789         break;
1790         default:
1791                 return AGL_SHELL_TILE_ORIENTATION_NONE;
1792         }
1793 }
1794
1795 static void
1796 _ivi_set_shell_surface_split(struct ivi_surface *surface, struct ivi_output *ioutput,
1797                              uint32_t orientation, bool to_activate)
1798 {
1799         struct ivi_compositor *ivi = surface->ivi;
1800         struct weston_geometry geom = {};
1801         struct ivi_output *output = NULL;
1802
1803         int width, height;
1804         int x, y;
1805
1806         geom = weston_desktop_surface_get_geometry(surface->dsurface);
1807         output = ivi_layout_get_output_from_surface(surface);
1808
1809         if (!output)
1810                 output = ioutput;
1811
1812         width = output->area.width;
1813         height = output->area.height;
1814
1815         switch (orientation) {
1816         case AGL_SHELL_TILE_ORIENTATION_LEFT:
1817         case AGL_SHELL_TILE_ORIENTATION_RIGHT:
1818                 width /= 2;
1819         break;
1820         case AGL_SHELL_TILE_ORIENTATION_TOP:
1821         case AGL_SHELL_TILE_ORIENTATION_BOTTOM:
1822                 height /= 2;
1823         break;
1824         case AGL_SHELL_TILE_ORIENTATION_NONE:
1825         break;
1826         default:
1827                 /* nothing */
1828                 assert(!"Invalid orientation passed");
1829
1830         }
1831
1832         x = output->area.x - geom.x;
1833         y = output->area.y - geom.y;
1834
1835         if (orientation == AGL_SHELL_TILE_ORIENTATION_RIGHT)
1836                 x += width;
1837         else if (orientation == AGL_SHELL_TILE_ORIENTATION_BOTTOM)
1838                 y += height;
1839
1840         if (to_activate) {
1841                 struct weston_view *ev = surface->view;
1842                 struct ivi_shell_seat *ivi_seat = NULL;
1843                 struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
1844
1845                 if (wseat)
1846                         ivi_seat = get_ivi_shell_seat(wseat);
1847
1848                 if (!weston_view_is_mapped(ev))
1849                         weston_view_update_transform(ev);
1850                 else
1851                         weston_layer_entry_remove(&ev->layer_link);
1852
1853
1854                 // mark view as mapped
1855                 ev->is_mapped = true;
1856                 ev->surface->is_mapped = true;
1857                 surface->mapped = true;
1858
1859                 // update older/new active surface
1860                 output->previous_active = output->active;
1861                 output->active = surface;
1862
1863                 // add to the layer and inflict damage
1864                 weston_view_set_output(ev, output->output);
1865                 weston_layer_entry_insert(&ivi->normal.view_list, &ev->layer_link);
1866                 weston_view_geometry_dirty(ev);
1867                 weston_surface_damage(ev->surface);
1868
1869                 // handle input / keyboard
1870                 if (ivi_seat)
1871                         ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
1872         }
1873
1874         weston_view_set_position(surface->view, x, y);
1875         weston_desktop_surface_set_size(surface->dsurface, width, height);
1876         weston_desktop_surface_set_orientation(surface->dsurface, orientation);
1877         surface->orientation = orientation;
1878
1879         weston_compositor_schedule_repaint(ivi->compositor);
1880
1881         weston_log("%s() Setting to x=%d, y=%d, width=%d, height=%d, orientation=%d\n",
1882                         __func__, x, y, width, height, orientation);
1883
1884 }
1885
1886 static int
1887 shell_ivi_surf_count_split_surfaces(struct ivi_compositor *ivi)
1888 {
1889         int count = 0;
1890         struct ivi_surface *surf;
1891
1892         wl_list_for_each(surf, &ivi->surfaces, link) {
1893                 if (surf->orientation > AGL_SHELL_TILE_ORIENTATION_NONE)
1894                         count++;
1895         }
1896
1897         return count;
1898 }
1899
1900
1901 static
1902 void shell_set_app_split(struct wl_client *client, struct wl_resource *res,
1903                          const char *app_id, uint32_t orientation,
1904                          struct wl_resource *output_res)
1905 {
1906         struct ivi_surface *surf;
1907         struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1908
1909         struct weston_head *head = weston_head_from_resource(output_res);
1910         struct weston_output *woutput = weston_head_get_output(head);
1911         struct ivi_output *output = to_ivi_output(woutput);
1912
1913         if (!app_id)
1914                 return;
1915
1916         if (shell_ivi_surf_count_split_surfaces(ivi) > 2) {
1917                 weston_log("Found more than two split surfaces in tile orientation.\n");
1918                 return;
1919         }
1920
1921         /* add it as pending until */
1922         surf = ivi_find_app(ivi, app_id);
1923         if (!surf) {
1924                 _ivi_set_pending_desktop_surface_split(output_res, app_id, orientation);
1925                 return;
1926         }
1927
1928         /* otherwise, take actions now */
1929         weston_log("%s() added split surface for app_id '%s' with orientation %d\n",
1930                         __func__, app_id, orientation);
1931
1932         if (output->previous_active) {
1933                 struct weston_view *ev = output->previous_active->view;
1934
1935                 if (!weston_view_is_mapped(ev))
1936                         weston_view_update_transform(ev);
1937                 else
1938                         weston_layer_entry_remove(&ev->layer_link);
1939
1940                 ev->is_mapped = true;
1941                 ev->surface->is_mapped = true;
1942                 output->previous_active->mapped = true;
1943
1944                 weston_view_set_output(ev, woutput);
1945
1946                 weston_layer_entry_insert(&ivi->normal.view_list, &ev->layer_link);
1947
1948                 _ivi_set_shell_surface_split(output->previous_active, NULL,
1949                                              reverse_orientation(orientation), false);
1950
1951                 if (orientation == AGL_SHELL_TILE_ORIENTATION_NONE &&
1952                     output->active == surf) {
1953                         output->active = output->previous_active;
1954                 }
1955         }
1956
1957         _ivi_set_shell_surface_split(surf, NULL, orientation, false);
1958 }
1959
1960 static void
1961 shell_ext_destroy(struct wl_client *client, struct wl_resource *res)
1962 {
1963         struct  ivi_compositor *ivi = wl_resource_get_user_data(res);
1964
1965         ivi->shell_client_ext.doas_requested = false;
1966         wl_resource_destroy(res);
1967 }
1968
1969 static void
1970 shell_ext_doas(struct wl_client *client, struct wl_resource *res)
1971 {
1972         struct  ivi_compositor *ivi = wl_resource_get_user_data(res);
1973
1974         ivi->shell_client_ext.doas_requested = true;
1975
1976         if (ivi->shell_client_ext.resource && ivi->shell_client.resource) {
1977                 ivi->shell_client_ext.doas_requested_pending_bind = true;
1978
1979                 agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource,
1980                                              AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS);
1981         } else {
1982                 agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource,
1983                                              AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_FAILED);
1984         }
1985
1986 }
1987
1988 static const struct agl_shell_interface agl_shell_implementation = {
1989         .ready = shell_ready,
1990         .set_background = shell_set_background,
1991         .set_panel = shell_set_panel,
1992         .activate_app = shell_activate_app,
1993         .destroy = shell_destroy,
1994         .set_activate_region = shell_set_activate_region,
1995         .deactivate_app = shell_new_deactivate_app,
1996         .set_app_float = shell_set_app_float,
1997         .set_app_normal = shell_set_app_normal,
1998         .set_app_fullscreen = shell_set_app_fullscreen,
1999         .set_app_output = shell_set_app_output,
2000         .set_app_position = shell_set_app_position,
2001         .set_app_scale = shell_set_app_scale,
2002         .set_app_split = shell_set_app_split,
2003 };
2004
2005 static const struct agl_shell_ext_interface agl_shell_ext_implementation = {
2006         .destroy = shell_ext_destroy,
2007         .doas_shell_client = shell_ext_doas,
2008 };
2009
2010 static void
2011 shell_desktop_set_app_property(struct wl_client *client,
2012                                struct wl_resource *shell_res,
2013                                const char *app_id, uint32_t role,
2014                                int x, int y, int bx, int by,
2015                                int width, int height,
2016                                struct wl_resource *output_res)
2017 {
2018         struct weston_head *head = weston_head_from_resource(output_res);
2019         struct weston_output *woutput = weston_head_get_output(head);
2020         struct ivi_output *output = to_ivi_output(woutput);
2021
2022         switch (role) {
2023         case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
2024                 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
2025                                                       width, height, app_id);
2026                 break;
2027         case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
2028                 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
2029                 break;
2030         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
2031         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
2032                 ivi_set_pending_desktop_surface_split(output, app_id, role);
2033                 break;
2034         case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
2035                 ivi_set_pending_desktop_surface_remote(output, app_id);
2036                 break;
2037         default:
2038                 break;
2039         }
2040 }
2041
2042 void
2043 ivi_compositor_destroy_pending_surfaces(struct ivi_compositor *ivi)
2044 {
2045         struct pending_popup *p_popup, *next_p_popup;
2046         struct pending_split *split_surf, *next_split_surf;
2047         struct pending_fullscreen *fs_surf, *next_fs_surf;
2048         struct pending_remote *remote_surf, *next_remote_surf;
2049
2050         wl_list_for_each_safe(p_popup, next_p_popup,
2051                               &ivi->popup_pending_apps, link)
2052                 ivi_remove_pending_desktop_surface_popup(p_popup);
2053
2054         wl_list_for_each_safe(split_surf, next_split_surf,
2055                               &ivi->split_pending_apps, link)
2056                 ivi_remove_pending_desktop_surface_split(split_surf);
2057
2058         wl_list_for_each_safe(fs_surf, next_fs_surf,
2059                               &ivi->fullscreen_pending_apps, link)
2060                 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
2061
2062         wl_list_for_each_safe(remote_surf, next_remote_surf,
2063                               &ivi->remote_pending_apps, link)
2064                 ivi_remove_pending_desktop_surface_remote(remote_surf);
2065 }
2066
2067 static void
2068 shell_desktop_set_app_property_mode(struct wl_client *client,
2069                                     struct wl_resource *shell_res, uint32_t perm)
2070 {
2071         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
2072         if (perm) {
2073                 dclient->ivi->keep_pending_surfaces = true;
2074         } else {
2075                 dclient->ivi->keep_pending_surfaces = false;
2076                 /* remove any previous pending surfaces */
2077                 ivi_compositor_destroy_pending_surfaces(dclient->ivi);
2078         }
2079 }
2080
2081 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
2082         .activate_app = shell_desktop_activate_app,
2083         .set_app_property = shell_desktop_set_app_property,
2084         .deactivate_app = shell_deactivate_app,
2085         .set_app_property_mode = shell_desktop_set_app_property_mode,
2086 };
2087
2088 static void
2089 unbind_agl_shell(struct wl_resource *resource)
2090 {
2091         struct ivi_compositor *ivi;
2092         struct ivi_output *output;
2093         struct ivi_surface *surf, *surf_tmp;
2094
2095         ivi = wl_resource_get_user_data(resource);
2096
2097         /* reset status to allow other clients issue legit requests */
2098         if (wl_resource_get_version(resource) >=
2099             AGL_SHELL_BOUND_OK_SINCE_VERSION &&
2100             ivi->shell_client.status == BOUND_FAILED) {
2101                 ivi->shell_client.status = BOUND_OK;
2102                 return;
2103         }
2104
2105         wl_list_for_each(output, &ivi->outputs, link) {
2106
2107                 /* reset the active surf if there's one present */
2108                 if (output->active) {
2109                         struct weston_geometry area = {};
2110
2111                         output->active->view->is_mapped = false;
2112                         output->active->view->surface->is_mapped = false;
2113
2114                         weston_layer_entry_remove(&output->active->view->layer_link);
2115                         output->active = NULL;
2116
2117                         output->area_activation = area;
2118                 }
2119
2120                 insert_black_curtain(output);
2121         }
2122
2123         wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
2124                 wl_list_remove(&surf->link);
2125                 wl_list_init(&surf->link);
2126         }
2127
2128         wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
2129                 wl_list_remove(&surf->link);
2130                 wl_list_init(&surf->link);
2131         }
2132
2133         wl_list_init(&ivi->surfaces);
2134         wl_list_init(&ivi->pending_surfaces);
2135
2136         ivi->shell_client.ready = false;
2137         ivi->shell_client.resource = NULL;
2138         ivi->shell_client.resource_ext = NULL;
2139         ivi->shell_client.client = NULL;
2140 }
2141
2142 static void
2143 unbind_agl_shell_ext(struct wl_resource *resource)
2144 {
2145         struct ivi_compositor *ivi = wl_resource_get_user_data(resource);
2146
2147         ivi->shell_client_ext.resource = NULL;
2148         ivi->shell_client.resource_ext = NULL;
2149         ivi->shell_client_ext.doas_requested = false;
2150 }
2151
2152 static void
2153 bind_agl_shell(struct wl_client *client,
2154                void *data, uint32_t version, uint32_t id)
2155 {
2156         struct ivi_compositor *ivi = data;
2157         struct wl_resource *resource;
2158         struct ivi_policy *policy;
2159         void *interface;
2160
2161         policy = ivi->policy;
2162         interface = (void *) &agl_shell_interface;
2163         if (policy && policy->api.shell_bind_interface &&
2164             !policy->api.shell_bind_interface(client, interface)) {
2165                 wl_client_post_implementation_error(client,
2166                                        "client not authorized to use agl_shell");
2167                 return;
2168         }
2169
2170         resource = wl_resource_create(client, &agl_shell_interface, version, id);
2171         if (!resource) {
2172                 wl_client_post_no_memory(client);
2173                 return;
2174         }
2175
2176         if (ivi->shell_client.resource && wl_resource_get_version(resource) == 1) {
2177                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2178                                 "agl_shell has already been bound (version 1)");
2179                 wl_resource_destroy(resource);
2180                 return;
2181         }
2182
2183         // for agl_shell client proxy
2184         if (ivi->shell_client.resource &&
2185             ivi->shell_client_ext.doas_requested_pending_bind) {
2186
2187                 ivi->shell_client_ext.doas_requested_pending_bind = false;
2188
2189                 // if there's one connected
2190                 if (ivi->shell_client.resource_ext) {
2191                         ivi->shell_client_ext.status = BOUND_FAILED;
2192                         agl_shell_send_bound_fail(ivi->shell_client.resource_ext);
2193                         wl_resource_destroy(resource);
2194                         return;
2195                 }
2196
2197                 wl_resource_set_implementation(resource, &agl_shell_implementation,
2198                                                ivi, NULL);
2199                 ivi->shell_client.resource_ext = resource;
2200                 ivi->shell_client_ext.status = BOUND_OK;
2201                 agl_shell_send_bound_ok(ivi->shell_client.resource_ext);
2202                 return;
2203         }
2204
2205
2206         // if we already have an agl_shell client
2207         if (ivi->shell_client.resource) {
2208                 agl_shell_send_bound_fail(resource);
2209                 ivi->shell_client.status = BOUND_FAILED;
2210                 wl_resource_destroy(resource);
2211                 return;
2212         }
2213
2214         // default agl_shell client
2215         wl_resource_set_implementation(resource, &agl_shell_implementation,
2216                                        ivi, unbind_agl_shell);
2217         ivi->shell_client.resource = resource;
2218
2219         if (wl_resource_get_version(resource) >=
2220             AGL_SHELL_BOUND_OK_SINCE_VERSION) {
2221                 /* if we land here we'll have BOUND_OK by default,
2222                    but still do the assignment */
2223                 ivi->shell_client.status = BOUND_OK;
2224                 agl_shell_send_bound_ok(ivi->shell_client.resource);
2225         }
2226 }
2227
2228 static void
2229 bind_agl_shell_ext(struct wl_client *client,
2230                    void *data, uint32_t version, uint32_t id)
2231 {
2232         struct ivi_compositor *ivi = data;
2233         struct wl_resource *resource;
2234
2235         resource = wl_resource_create(client, &agl_shell_ext_interface, version, id);
2236         if (!resource) {
2237                 wl_client_post_no_memory(client);
2238                 return;
2239         }
2240
2241         if (ivi->shell_client_ext.resource) {
2242                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2243                                        "agl_shell_ext has already been bound");
2244                 return;
2245         }
2246
2247         wl_resource_set_implementation(resource, &agl_shell_ext_implementation,
2248                                        ivi, unbind_agl_shell_ext);
2249         ivi->shell_client_ext.resource = resource;
2250 }
2251
2252 static void
2253 unbind_agl_shell_desktop(struct wl_resource *resource)
2254 {
2255         struct desktop_client *dclient = wl_resource_get_user_data(resource);
2256
2257         wl_list_remove(&dclient->link);
2258         free(dclient);
2259 }
2260
2261 static void
2262 bind_agl_shell_desktop(struct wl_client *client,
2263                        void *data, uint32_t version, uint32_t id)
2264 {
2265         struct ivi_compositor *ivi = data;
2266         struct wl_resource *resource;
2267         struct ivi_policy *policy;
2268         struct desktop_client *dclient;
2269         void *interface;
2270
2271         policy = ivi->policy;
2272         interface  = (void *) &agl_shell_desktop_interface;
2273         if (policy && policy->api.shell_bind_interface &&
2274             !policy->api.shell_bind_interface(client, interface)) {
2275                 wl_client_post_implementation_error(client,
2276                                 "client not authorized to use agl_shell_desktop");
2277                 return;
2278         }
2279
2280         dclient = zalloc(sizeof(*dclient));
2281         if (!dclient) {
2282                 wl_client_post_no_memory(client);
2283                 return;
2284         }
2285
2286         resource = wl_resource_create(client, &agl_shell_desktop_interface,
2287                                       version, id);
2288         dclient->ivi = ivi;
2289         if (!resource) {
2290                 wl_client_post_no_memory(client);
2291                 return;
2292         }
2293
2294         wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
2295                                        dclient, unbind_agl_shell_desktop);
2296
2297         dclient->resource = resource;
2298         wl_list_insert(&ivi->desktop_clients, &dclient->link);
2299
2300         /* advertise xdg surfaces */
2301         ivi_shell_advertise_xdg_surfaces(ivi, resource);
2302 }
2303
2304 int
2305 ivi_shell_create_global(struct ivi_compositor *ivi)
2306 {
2307         ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
2308                                           &agl_shell_interface, 11,
2309                                           ivi, bind_agl_shell);
2310         if (!ivi->agl_shell) {
2311                 weston_log("Failed to create wayland global.\n");
2312                 return -1;
2313         }
2314
2315         ivi->agl_shell_ext = wl_global_create(ivi->compositor->wl_display,
2316                                               &agl_shell_ext_interface, 1,
2317                                               ivi, bind_agl_shell_ext);
2318         if (!ivi->agl_shell_ext) {
2319                 weston_log("Failed to create agl_shell_ext global.\n");
2320                 return -1;
2321         }
2322
2323         ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
2324                                                   &agl_shell_desktop_interface, 2,
2325                                                   ivi, bind_agl_shell_desktop);
2326         if (!ivi->agl_shell_desktop) {
2327                 weston_log("Failed to create wayland global (agl_shell_desktop).\n");
2328                 return -1;
2329         }
2330
2331         return 0;
2332 }