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