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