build/: Allow to build the compositor w/o waltham
[src/agl-compositor.git] / src / shell.c
1 /*
2  * Copyright © 2019 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "ivi-compositor.h"
27 #include "policy.h"
28
29 #include <assert.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <libweston/libweston.h>
38 #include <libweston/config-parser.h>
39
40 #include "shared/os-compatibility.h"
41
42 #include "agl-shell-server-protocol.h"
43 #include "agl-shell-desktop-server-protocol.h"
44
45 #ifdef HAVE_WALTHAM
46 #include <waltham-transmitter/transmitter_api.h>
47 #endif
48
49 static void
50 create_black_surface_view(struct ivi_output *output);
51
52 void
53 agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi,
54                                            struct ivi_surface *surface)
55 {
56         struct desktop_client *dclient;
57
58         if (surface->advertised_on_launch)
59                 return;
60
61         /* advertise to all desktop clients the new surface */
62         wl_list_for_each(dclient, &ivi->desktop_clients, link) {
63                 const char *app_id =
64                         weston_desktop_surface_get_app_id(surface->dsurface);
65                 if (app_id == NULL) {
66                         weston_log("WARNING app_is is null, unable to advertise\n");
67                         return;
68                 }
69                 agl_shell_desktop_send_application(dclient->resource, app_id);
70                 surface->advertised_on_launch = true;
71         }
72 }
73
74 void
75 ivi_set_desktop_surface(struct ivi_surface *surface)
76 {
77         struct ivi_compositor *ivi = surface->ivi;
78         assert(surface->role == IVI_SURFACE_ROLE_NONE);
79
80         surface->role = IVI_SURFACE_ROLE_DESKTOP;
81         wl_list_insert(&surface->ivi->surfaces, &surface->link);
82
83         agl_shell_desktop_advertise_application_id(ivi, surface);
84 }
85
86 static void
87 ivi_set_desktop_surface_popup(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_POPUP;
93         wl_list_insert(&ivi->surfaces, &surface->link);
94
95         agl_shell_desktop_advertise_application_id(ivi, surface);
96 }
97
98 static void
99 ivi_set_desktop_surface_fullscreen(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_FULLSCREEN;
105         wl_list_insert(&ivi->surfaces, &surface->link);
106
107         agl_shell_desktop_advertise_application_id(ivi, surface);
108 }
109
110 #ifdef HAVE_WALTHAM
111 void
112 ivi_destroy_waltham_destroy(struct ivi_surface *surface)
113 {
114         struct ivi_compositor *ivi = surface->ivi;
115         const struct weston_transmitter_api *api =
116                 ivi->waltham_transmitter_api;
117
118         if (!api)
119                 return;
120
121         if (surface->waltham_surface.transmitter_surface)
122                 api->surface_destroy(surface->waltham_surface.transmitter_surface);
123 }
124
125 static void
126 ivi_output_notify_waltham_plugin(struct ivi_surface *surface)
127 {
128         struct ivi_compositor *ivi = surface->ivi;
129         const struct weston_transmitter_api *api = ivi->waltham_transmitter_api;
130         struct weston_transmitter *transmitter;
131         struct weston_transmitter_remote *trans_remote;
132         struct weston_surface *weston_surface;
133         struct weston_output *woutput = surface->remote.output->output;
134         const char *app_id;
135
136         if (!api)
137                 return;
138
139         transmitter = api->transmitter_get(ivi->compositor);
140         if (!transmitter)
141                 return;
142
143         trans_remote = api->get_transmitter_remote(woutput->name, transmitter);
144         if (!trans_remote) {
145                 weston_log("Could not find a valie weston_transmitter_remote "
146                                 "that matches the output %s\n", woutput->name);
147                 return;
148         }
149
150         app_id = weston_desktop_surface_get_app_id(surface->dsurface);
151         weston_surface =
152                 weston_desktop_surface_get_surface(surface->dsurface);
153
154         weston_log("Forwarding app_id %s to remote %s\n", app_id, woutput->name);
155
156         /* this will have the effect of informing the remote side to create a
157          * surface with the name app_id. W/ xdg-shell the following happens:
158          *
159          * compositor (server):
160          * surface_push_to_remote():
161          *      waltham-transmitter plug-in
162          *              -> wthp_ivi_app_id_surface_create()
163          *
164          * client -- on the receiver side:
165          *      -> wthp_ivi_app_id_surface_create()
166          *              -> wth_receiver_weston_main()
167          *                      -> wl_compositor_create_surface()
168          *                      -> xdg_wm_base_get_xdg_surface
169          *                      -> xdg_toplevel_set_app_id()
170          *                      -> gst_init()
171          *                      -> gst_parse_launch()
172          *
173          * wth_receiver_weston_main() will be invoked from the handler of
174          * wthp_ivi_app_id_surface_create() and is responsible for setting-up
175          * the gstreamer pipeline as well.
176          */
177         surface->waltham_surface.transmitter_surface =
178             api->surface_push_to_remote(weston_surface, app_id, trans_remote, NULL);
179 }
180
181 #else
182 void
183 ivi_destroy_waltham_destroy(struct ivi_surface *surface)
184 {
185 }
186 static void
187 ivi_output_notify_waltham_plugin(struct ivi_surface *surface)
188 {
189 }
190 #endif
191
192 static void
193 ivi_set_desktop_surface_remote(struct ivi_surface *surface)
194 {
195         struct ivi_compositor *ivi = surface->ivi;
196         struct weston_view *view;
197         struct ivi_output *output = surface->remote.output;
198
199         assert(surface->role == IVI_SURFACE_ROLE_NONE);
200
201         /* remote type are the same as desktop just that client can tell
202          * the compositor to start on another output */
203         surface->role = IVI_SURFACE_ROLE_REMOTE;
204
205         /* if thew black surface view is mapped on the mean we need
206          * to remove it in order to start showing the 'remote' surface
207          * just being added */
208         view = output->fullscreen_view.fs->view;
209         if (view->is_mapped || view->surface->is_mapped)
210                 remove_black_surface(output);
211
212         if (output->type == OUTPUT_WALTHAM)
213                 ivi_output_notify_waltham_plugin(surface);
214
215         wl_list_insert(&ivi->surfaces, &surface->link);
216 }
217
218
219 static void
220 ivi_set_desktop_surface_split(struct ivi_surface *surface)
221 {
222         struct ivi_compositor *ivi = surface->ivi;
223         assert(surface->role == IVI_SURFACE_ROLE_NONE);
224
225         if (surface->split.orientation == AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL)
226                 surface->role = IVI_SURFACE_ROLE_SPLIT_V;
227         else
228                 surface->role = IVI_SURFACE_ROLE_SPLIT_H;
229
230         wl_list_insert(&ivi->surfaces, &surface->link);
231
232         agl_shell_desktop_advertise_application_id(ivi, surface);
233 }
234
235 static void
236 ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput,
237                                       int x, int y, int bx, int by, int width, int height,
238                                       const char *app_id)
239 {
240         struct ivi_compositor *ivi = ioutput->ivi;
241         size_t len_app_id = strlen(app_id);
242
243         struct pending_popup *p_popup = zalloc(sizeof(*p_popup));
244
245         p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
246         memcpy(p_popup->app_id, app_id, len_app_id);
247         p_popup->ioutput = ioutput;
248         p_popup->x = x;
249         p_popup->y = y;
250
251         p_popup->bb.x = bx;
252         p_popup->bb.y = by;
253         p_popup->bb.width = width;
254         p_popup->bb.height = height;
255
256         wl_list_insert(&ivi->popup_pending_apps, &p_popup->link);
257 }
258
259 static void
260 ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput,
261                                            const char *app_id)
262 {
263         struct ivi_compositor *ivi = ioutput->ivi;
264         size_t len_app_id = strlen(app_id);
265
266         struct pending_fullscreen *fs = zalloc(sizeof(*fs));
267
268         fs->app_id = zalloc(sizeof(char) * (len_app_id + 1));
269         memcpy(fs->app_id, app_id, len_app_id);
270
271         fs->ioutput = ioutput;
272
273         wl_list_insert(&ivi->fullscreen_pending_apps, &fs->link);
274 }
275
276 static void
277 ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput,
278                                       const char *app_id, uint32_t orientation)
279 {
280         struct ivi_compositor *ivi = ioutput->ivi;
281         struct ivi_surface *surf;
282         size_t len_app_id = strlen(app_id);
283         struct pending_split *split;
284
285         if (orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL &&
286             orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL)
287                 return;
288
289         /* more than one is un-supported, do note we need to do
290          * conversion for surface roles instead of using the protocol ones */
291         wl_list_for_each(surf, &ivi->surfaces, link)
292                 if (surf->role == IVI_SURFACE_ROLE_SPLIT_V ||
293                     surf->role == IVI_SURFACE_ROLE_SPLIT_H)
294                         return;
295
296         split = zalloc(sizeof(*split));
297         split->app_id = zalloc(sizeof(char) * (len_app_id + 1));
298         memcpy(split->app_id, app_id, len_app_id);
299
300         split->ioutput = ioutput;
301         split->orientation = orientation;
302
303         wl_list_insert(&ivi->split_pending_apps, &split->link);
304 }
305
306 void
307 ivi_set_pending_desktop_surface_remote(struct ivi_output *ioutput,
308                 const char *app_id)
309 {
310         struct ivi_compositor *ivi = ioutput->ivi;
311         size_t len_app_id = strlen(app_id);
312
313         struct pending_remote *remote = zalloc(sizeof(*remote));
314
315         remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
316         memcpy(remote->app_id, app_id, len_app_id);
317
318         remote->ioutput = ioutput;
319
320         wl_list_insert(&ivi->remote_pending_apps, &remote->link);
321 }
322
323
324 static void
325 ivi_remove_pending_desktop_surface_split(struct pending_split *split)
326 {
327         free(split->app_id);
328         wl_list_remove(&split->link);
329         free(split);
330 }
331
332 static void
333 ivi_remove_pending_desktop_surface_fullscreen(struct pending_fullscreen *fs)
334 {
335         free(fs->app_id);
336         wl_list_remove(&fs->link);
337         free(fs);
338 }
339
340 static void
341 ivi_remove_pending_desktop_surface_popup(struct pending_popup *p_popup)
342 {
343         free(p_popup->app_id);
344         wl_list_remove(&p_popup->link);
345         free(p_popup);
346 }
347
348 static void
349 ivi_remove_pending_desktop_surface_remote(struct pending_remote *remote)
350 {
351         free(remote->app_id);
352         wl_list_remove(&remote->link);
353         free(remote);
354 }
355
356 static bool
357 ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface)
358 {
359         struct ivi_compositor *ivi = surface->ivi;
360         struct pending_popup *p_popup, *next_p_popup;
361         const char *_app_id =
362                         weston_desktop_surface_get_app_id(surface->dsurface);
363
364         if (wl_list_empty(&ivi->popup_pending_apps) || !_app_id)
365                 return false;
366
367         wl_list_for_each_safe(p_popup, next_p_popup,
368                               &ivi->popup_pending_apps, link) {
369                 if (!strcmp(_app_id, p_popup->app_id)) {
370                         surface->popup.output = p_popup->ioutput;
371                         surface->popup.x = p_popup->x;
372                         surface->popup.y = p_popup->y;
373
374                         surface->popup.bb.x = p_popup->bb.x;
375                         surface->popup.bb.y = p_popup->bb.y;
376                         surface->popup.bb.width = p_popup->bb.width;
377                         surface->popup.bb.height = p_popup->bb.height;
378
379                         ivi_remove_pending_desktop_surface_popup(p_popup);
380                         return true;
381                 }
382         }
383
384         return false;
385 }
386
387 static bool
388 ivi_check_pending_desktop_surface_split(struct ivi_surface *surface)
389 {
390         struct pending_split *split_surf, *next_split_surf;
391         struct ivi_compositor *ivi = surface->ivi;
392         const char *_app_id =
393                         weston_desktop_surface_get_app_id(surface->dsurface);
394
395         if (wl_list_empty(&ivi->split_pending_apps) || !_app_id)
396                 return false;
397
398         wl_list_for_each_safe(split_surf, next_split_surf,
399                               &ivi->split_pending_apps, link) {
400                 if (!strcmp(_app_id, split_surf->app_id)) {
401                         surface->split.output = split_surf->ioutput;
402                         surface->split.orientation = split_surf->orientation;
403                         ivi_remove_pending_desktop_surface_split(split_surf);
404                         return true;
405                 }
406         }
407
408         return false;
409 }
410
411 static bool
412 ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface)
413 {
414         struct pending_fullscreen *fs_surf, *next_fs_surf;
415         struct ivi_compositor *ivi = surface->ivi;
416         const char *_app_id =
417                         weston_desktop_surface_get_app_id(surface->dsurface);
418
419         if (wl_list_empty(&ivi->fullscreen_pending_apps) || !_app_id)
420                 return false;
421
422         wl_list_for_each_safe(fs_surf, next_fs_surf,
423                               &ivi->fullscreen_pending_apps, link) {
424                 if (!strcmp(_app_id, fs_surf->app_id)) {
425                         surface->fullscreen.output = fs_surf->ioutput;
426                         ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
427                         return true;
428                 }
429         }
430
431         return false;
432 }
433
434 static bool
435 ivi_check_pending_desktop_surface_remote(struct ivi_surface *surface)
436 {
437         struct pending_remote *remote_surf, *next_remote_surf;
438         struct ivi_compositor *ivi = surface->ivi;
439         const char *_app_id =
440                 weston_desktop_surface_get_app_id(surface->dsurface);
441
442         if (wl_list_empty(&ivi->remote_pending_apps) || !_app_id)
443                 return false;
444
445         wl_list_for_each_safe(remote_surf, next_remote_surf,
446                               &ivi->remote_pending_apps, link) {
447                 if (!strcmp(_app_id, remote_surf->app_id)) {
448                         surface->remote.output = remote_surf->ioutput;
449                         ivi_remove_pending_desktop_surface_remote(remote_surf);
450                         return true;
451                 }
452         }
453
454         return false;
455 }
456
457
458 void
459 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
460 {
461         bool ret = false;
462
463         ret = ivi_check_pending_desktop_surface_popup(surface);
464         if (ret) {
465                 ivi_set_desktop_surface_popup(surface);
466                 ivi_layout_popup_committed(surface);
467                 return;
468         }
469
470         ret = ivi_check_pending_desktop_surface_split(surface);
471         if (ret) {
472                 ivi_set_desktop_surface_split(surface);
473                 ivi_layout_split_committed(surface);
474                 return;
475         }
476
477         ret = ivi_check_pending_desktop_surface_fullscreen(surface);
478         if (ret) {
479                 ivi_set_desktop_surface_fullscreen(surface);
480                 ivi_layout_fullscreen_committed(surface);
481                 return;
482         }
483
484         ret = ivi_check_pending_desktop_surface_remote(surface);
485         if (ret) {
486                 ivi_set_desktop_surface_remote(surface);
487                 ivi_layout_desktop_committed(surface);
488                 return;
489         }
490
491         /* if we end up here means we have a regular desktop app and
492          * try to activate it */
493         ivi_set_desktop_surface(surface);
494         ivi_layout_desktop_committed(surface);
495 }
496
497 void
498 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
499 {
500         struct ivi_output *out;
501
502         wl_list_for_each(out, &ivi->outputs, link) {
503                 create_black_surface_view(out);
504                 insert_black_surface(out);
505         }
506 }
507
508 int
509 ivi_shell_init(struct ivi_compositor *ivi)
510 {
511         weston_layer_init(&ivi->hidden, ivi->compositor);
512         weston_layer_init(&ivi->background, ivi->compositor);
513         weston_layer_init(&ivi->normal, ivi->compositor);
514         weston_layer_init(&ivi->panel, ivi->compositor);
515         weston_layer_init(&ivi->popup, ivi->compositor);
516         weston_layer_init(&ivi->fullscreen, ivi->compositor);
517
518         weston_layer_set_position(&ivi->hidden,
519                                   WESTON_LAYER_POSITION_HIDDEN);
520         weston_layer_set_position(&ivi->background,
521                                   WESTON_LAYER_POSITION_BACKGROUND);
522         weston_layer_set_position(&ivi->normal,
523                                   WESTON_LAYER_POSITION_NORMAL);
524         weston_layer_set_position(&ivi->panel,
525                                   WESTON_LAYER_POSITION_UI);
526         weston_layer_set_position(&ivi->popup,
527                                   WESTON_LAYER_POSITION_TOP_UI);
528         weston_layer_set_position(&ivi->fullscreen,
529                                   WESTON_LAYER_POSITION_FULLSCREEN);
530
531         return 0;
532 }
533
534 static void
535 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
536 {
537         struct ivi_surface *surface;
538
539         wl_list_for_each(surface, &ivi->surfaces, link) {
540                 const char *app_id =
541                         weston_desktop_surface_get_app_id(surface->dsurface);
542                 if (app_id == NULL) {
543                         weston_log("WARNING app_is is null, unable to advertise\n");
544                         return;
545                 }
546                 agl_shell_desktop_send_application(resource, app_id);
547         }
548 }
549
550 static void
551 client_exec(const char *command, int fd)
552 {
553         sigset_t sig;
554         char s[32];
555
556         /* Don't give the child our signal mask */
557         sigfillset(&sig);
558         sigprocmask(SIG_UNBLOCK, &sig, NULL);
559
560         /* Launch clients as the user; don't give them the wrong euid */
561         if (seteuid(getuid()) == -1) {
562                 weston_log("seteuid failed: %s\n", strerror(errno));
563                 return;
564         }
565
566         /* Duplicate fd to unset the CLOEXEC flag. We don't need to worry about
567          * clobbering fd, as we'll exit/exec either way.
568          */
569         fd = dup(fd);
570         if (fd == -1) {
571                 weston_log("dup failed: %s\n", strerror(errno));
572                 return;
573         }
574
575         snprintf(s, sizeof s, "%d", fd);
576         setenv("WAYLAND_SOCKET", s, 1);
577
578         execl("/bin/sh", "/bin/sh", "-c", command, NULL);
579         weston_log("executing '%s' failed: %s", command, strerror(errno));
580 }
581
582 static struct wl_client *
583 launch_shell_client(struct ivi_compositor *ivi, const char *command)
584 {
585         struct wl_client *client;
586         int sock[2];
587         pid_t pid;
588
589         weston_log("launching' %s'\n", command);
590
591         if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
592                 weston_log("socketpair failed while launching '%s': %s\n",
593                            command, strerror(errno));
594                 return NULL;
595         }
596
597         pid = fork();
598         if (pid == -1) {
599                 close(sock[0]);
600                 close(sock[1]);
601                 weston_log("fork failed while launching '%s': %s\n",
602                            command, strerror(errno));
603                 return NULL;
604         }
605
606         if (pid == 0) {
607                 client_exec(command, sock[1]);
608                 _Exit(EXIT_FAILURE);
609         }
610         close(sock[1]);
611
612         client = wl_client_create(ivi->compositor->wl_display, sock[0]);
613         if (!client) {
614                 close(sock[0]);
615                 weston_log("Failed to create wayland client for '%s'",
616                            command);
617                 return NULL;
618         }
619
620         return client;
621 }
622
623 int
624 ivi_launch_shell_client(struct ivi_compositor *ivi)
625 {
626         struct weston_config_section *section;
627         char *command = NULL;
628
629         section = weston_config_get_section(ivi->config, "shell-client",
630                                             NULL, NULL);
631         if (section)
632                 weston_config_section_get_string(section, "command",
633                                                  &command, NULL);
634
635         if (!command)
636                 return -1;
637
638         ivi->shell_client.client = launch_shell_client(ivi, command);
639         if (!ivi->shell_client.client)
640                 return -1;
641
642         return 0;
643 }
644
645 static void
646 destroy_black_view(struct wl_listener *listener, void *data)
647 {
648         struct fullscreen_view *fs =
649                 wl_container_of(listener, fs, fs_destroy);
650
651
652         if (fs && fs->fs) {
653                 wl_list_remove(&fs->fs_destroy.link);
654                 free(fs->fs);
655         }
656 }
657
658
659 static void
660 create_black_surface_view(struct ivi_output *output)
661 {
662         struct weston_surface *surface = NULL;
663         struct weston_view *view;
664         struct ivi_compositor *ivi = output->ivi;
665         struct weston_compositor *wc= ivi->compositor;
666         struct weston_output *woutput = output->output;
667
668         if (!woutput)
669                 return;
670
671         surface = weston_surface_create(wc);
672         view = weston_view_create(surface);
673
674         assert(view || surface);
675
676         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
677         weston_surface_set_size(surface, woutput->width, woutput->height);
678         weston_view_set_position(view, woutput->x, woutput->y);
679
680         output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
681         output->fullscreen_view.fs->view = view;
682
683         output->fullscreen_view.fs_destroy.notify = destroy_black_view;
684         wl_signal_add(&woutput->destroy_signal,
685                       &output->fullscreen_view.fs_destroy);
686 }
687
688 void
689 remove_black_surface(struct ivi_output *output)
690 {
691         struct weston_view *view;
692
693         if (!output &&
694             !output->fullscreen_view.fs &&
695             !output->fullscreen_view.fs->view) {
696                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
697                 return;
698         }
699
700         view = output->fullscreen_view.fs->view;
701         assert(view->is_mapped == true ||
702                view->surface->is_mapped == true);
703
704         view->is_mapped = false;
705         view->surface->is_mapped = false;
706
707         weston_layer_entry_remove(&view->layer_link);
708         weston_view_update_transform(view);
709
710         weston_output_damage(output->output);
711 }
712
713 void
714 insert_black_surface(struct ivi_output *output)
715 {
716         struct weston_view *view;
717
718         if ((!output &&
719             !output->fullscreen_view.fs &&
720             !output->fullscreen_view.fs->view) || !output->output) {
721                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
722                 return;
723         }
724
725         view = output->fullscreen_view.fs->view;
726         if (view->is_mapped || view->surface->is_mapped)
727                 return;
728
729         weston_layer_entry_remove(&view->layer_link);
730         weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
731                                   &view->layer_link);
732
733         view->is_mapped = true;
734         view->surface->is_mapped = true;
735
736         weston_view_update_transform(view);
737         weston_output_damage(output->output);
738 }
739
740 static void
741 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
742 {
743         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
744         struct ivi_output *output;
745         struct ivi_surface *surface, *tmp;
746
747         /* Init already finished. Do nothing */
748         if (ivi->shell_client.ready)
749                 return;
750
751         ivi->shell_client.ready = true;
752
753         wl_list_for_each(output, &ivi->outputs, link) {
754                 if (output->background)
755                         remove_black_surface(output);
756                 ivi_layout_init(ivi, output);
757         }
758
759         wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
760                 wl_list_remove(&surface->link);
761                 wl_list_init(&surface->link);
762                 ivi_check_pending_desktop_surface(surface);
763                 surface->checked_pending = true;
764         }
765 }
766
767 static void
768 shell_set_background(struct wl_client *client,
769                      struct wl_resource *shell_res,
770                      struct wl_resource *surface_res,
771                      struct wl_resource *output_res)
772 {
773         struct weston_head *head = weston_head_from_resource(output_res);
774         struct weston_output *woutput = weston_head_get_output(head);
775         struct ivi_output *output = to_ivi_output(woutput);
776         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
777         struct weston_desktop_surface *dsurface;
778         struct ivi_surface *surface;
779
780         dsurface = weston_surface_get_desktop_surface(wsurface);
781         if (!dsurface) {
782                 wl_resource_post_error(shell_res,
783                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
784                                        "surface must be a desktop surface");
785                 return;
786         }
787
788         surface = weston_desktop_surface_get_user_data(dsurface);
789         if (surface->role != IVI_SURFACE_ROLE_NONE) {
790                 wl_resource_post_error(shell_res,
791                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
792                                        "surface already has another ivi role");
793                 return;
794         }
795
796         if (output->background) {
797                 wl_resource_post_error(shell_res,
798                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
799                                        "output already has background");
800                 return;
801         }
802
803         surface->checked_pending = true;
804         surface->role = IVI_SURFACE_ROLE_BACKGROUND;
805         surface->bg.output = output;
806         wl_list_remove(&surface->link);
807         wl_list_init(&surface->link);
808
809         output->background = surface;
810
811         weston_desktop_surface_set_maximized(dsurface, true);
812         weston_desktop_surface_set_size(dsurface,
813                                         output->output->width,
814                                         output->output->height);
815 }
816
817 static void
818 shell_set_panel(struct wl_client *client,
819                 struct wl_resource *shell_res,
820                 struct wl_resource *surface_res,
821                 struct wl_resource *output_res,
822                 uint32_t edge)
823 {
824         struct weston_head *head = weston_head_from_resource(output_res);
825         struct weston_output *woutput = weston_head_get_output(head);
826         struct ivi_output *output = to_ivi_output(woutput);
827         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
828         struct weston_desktop_surface *dsurface;
829         struct ivi_surface *surface;
830         struct ivi_surface **member;
831         int32_t width = 0, height = 0;
832
833         dsurface = weston_surface_get_desktop_surface(wsurface);
834         if (!dsurface) {
835                 wl_resource_post_error(shell_res,
836                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
837                                        "surface must be a desktop surface");
838                 return;
839         }
840
841         surface = weston_desktop_surface_get_user_data(dsurface);
842         if (surface->role != IVI_SURFACE_ROLE_NONE) {
843                 wl_resource_post_error(shell_res,
844                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
845                                        "surface already has another ivi role");
846                 return;
847         }
848
849         switch (edge) {
850         case AGL_SHELL_EDGE_TOP:
851                 member = &output->top;
852                 break;
853         case AGL_SHELL_EDGE_BOTTOM:
854                 member = &output->bottom;
855                 break;
856         case AGL_SHELL_EDGE_LEFT:
857                 member = &output->left;
858                 break;
859         case AGL_SHELL_EDGE_RIGHT:
860                 member = &output->right;
861                 break;
862         default:
863                 wl_resource_post_error(shell_res,
864                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
865                                        "invalid edge for panel");
866                 return;
867         }
868
869         if (*member) {
870                 wl_resource_post_error(shell_res,
871                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
872                                        "output already has panel on this edge");
873                 return;
874         }
875
876         surface->checked_pending = true;
877         surface->role = IVI_SURFACE_ROLE_PANEL;
878         surface->panel.output = output;
879         surface->panel.edge = edge;
880         wl_list_remove(&surface->link);
881         wl_list_init(&surface->link);
882
883         *member = surface;
884
885         switch (surface->panel.edge) {
886         case AGL_SHELL_EDGE_TOP:
887         case AGL_SHELL_EDGE_BOTTOM:
888                 width = woutput->width;
889                 break;
890         case AGL_SHELL_EDGE_LEFT:
891         case AGL_SHELL_EDGE_RIGHT:
892                 height = woutput->height;
893                 break;
894         }
895
896         weston_desktop_surface_set_size(dsurface, width, height);
897 }
898
899 void
900 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
901                           const char *data, uint32_t app_state)
902 {
903         struct desktop_client *dclient;
904         uint32_t app_role;
905         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
906         struct ivi_policy *policy = ivi->policy;
907
908         /* FIXME: should queue it here and see when binding agl-shell-desktop
909          * if there are any to be sent */
910         if (!surf)
911                 return;
912
913         if (!app_id)
914                 return;
915
916         if (policy && policy->api.surface_advertise_state_change &&
917             !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
918                 return;
919         }
920
921         app_role = surf->role;
922         if (app_role == IVI_SURFACE_ROLE_POPUP)
923                 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
924
925         wl_list_for_each(dclient, &ivi->desktop_clients, link)
926                 agl_shell_desktop_send_state_app(dclient->resource, app_id,
927                                                  data, app_state, app_role);
928 }
929
930 static void
931 shell_activate_app(struct wl_client *client,
932                    struct wl_resource *shell_res,
933                    const char *app_id,
934                    struct wl_resource *output_res)
935 {
936         struct weston_head *head = weston_head_from_resource(output_res);
937         struct weston_output *woutput = weston_head_get_output(head);
938         struct ivi_output *output = to_ivi_output(woutput);
939
940         ivi_layout_activate(output, app_id);
941 }
942
943 static void
944 shell_desktop_activate_app(struct wl_client *client,
945                            struct wl_resource *shell_res,
946                            const char *app_id, const char *data,
947                            struct wl_resource *output_res)
948 {
949         struct weston_head *head = weston_head_from_resource(output_res);
950         struct weston_output *woutput = weston_head_get_output(head);
951         struct ivi_output *output = to_ivi_output(woutput);
952
953         ivi_layout_activate(output, app_id);
954         shell_advertise_app_state(output->ivi, app_id,
955                                   data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
956 }
957
958 static void
959 shell_deactivate_app(struct wl_client *client,
960                    struct wl_resource *shell_res,
961                    const char *app_id)
962 {
963         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
964         struct ivi_compositor *ivi = dclient->ivi;
965
966         ivi_layout_deactivate(ivi, app_id);
967         shell_advertise_app_state(ivi, app_id,
968                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
969 }
970
971 static const struct agl_shell_interface agl_shell_implementation = {
972         .ready = shell_ready,
973         .set_background = shell_set_background,
974         .set_panel = shell_set_panel,
975         .activate_app = shell_activate_app,
976 };
977
978 static void
979 shell_desktop_set_app_property(struct wl_client *client,
980                                struct wl_resource *shell_res,
981                                const char *app_id, uint32_t role,
982                                int x, int y, int bx, int by,
983                                int width, int height,
984                                struct wl_resource *output_res)
985 {
986         struct weston_head *head = weston_head_from_resource(output_res);
987         struct weston_output *woutput = weston_head_get_output(head);
988         struct ivi_output *output = to_ivi_output(woutput);
989
990         switch (role) {
991         case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
992                 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
993                                                       width, height, app_id);
994                 break;
995         case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
996                 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
997                 break;
998         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
999         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
1000                 ivi_set_pending_desktop_surface_split(output, app_id, role);
1001                 break;
1002         case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
1003                 ivi_set_pending_desktop_surface_remote(output, app_id);
1004                 break;
1005         default:
1006                 break;
1007         }
1008 }
1009
1010 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
1011         .activate_app = shell_desktop_activate_app,
1012         .set_app_property = shell_desktop_set_app_property,
1013         .deactivate_app = shell_deactivate_app,
1014 };
1015
1016 static void
1017 unbind_agl_shell(struct wl_resource *resource)
1018 {
1019         struct ivi_compositor *ivi;
1020         struct ivi_output *output;
1021         struct ivi_surface *surf, *surf_tmp;
1022
1023         ivi = wl_resource_get_user_data(resource);
1024         wl_list_for_each(output, &ivi->outputs, link) {
1025                 /* reset the active surf if there's one present */
1026                 if (output->active) {
1027                         output->active->view->is_mapped = false;
1028                         output->active->view->surface->is_mapped = false;
1029
1030                         weston_layer_entry_remove(&output->active->view->layer_link);
1031                         output->active = NULL;
1032                 }
1033
1034                 insert_black_surface(output);
1035         }
1036
1037         wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
1038                 wl_list_remove(&surf->link);
1039                 wl_list_init(&surf->link);
1040         }
1041
1042         wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
1043                 wl_list_remove(&surf->link);
1044                 wl_list_init(&surf->link);
1045         }
1046
1047         wl_list_init(&ivi->surfaces);
1048         wl_list_init(&ivi->pending_surfaces);
1049
1050         ivi->shell_client.ready = false;
1051         ivi->shell_client.resource = NULL;
1052         ivi->shell_client.client = NULL;
1053 }
1054
1055 static void
1056 bind_agl_shell(struct wl_client *client,
1057                void *data, uint32_t version, uint32_t id)
1058 {
1059         struct ivi_compositor *ivi = data;
1060         struct wl_resource *resource;
1061         struct ivi_policy *policy;
1062         void *interface;
1063
1064         policy = ivi->policy;
1065         interface = (void *) &agl_shell_interface;
1066         if (policy && policy->api.shell_bind_interface &&
1067             !policy->api.shell_bind_interface(client, interface)) {
1068                 wl_client_post_implementation_error(client,
1069                                        "client not authorized to use agl_shell");
1070                 return;
1071         }
1072
1073         resource = wl_resource_create(client, &agl_shell_interface,
1074                                       1, id);
1075         if (!resource) {
1076                 wl_client_post_no_memory(client);
1077                 return;
1078         }
1079
1080 #if 0
1081         if (ivi->shell_client.client != client) {
1082                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1083                                        "client not authorized to use agl_shell");
1084                 return;
1085         }
1086 #endif
1087
1088         if (ivi->shell_client.resource) {
1089                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1090                                        "agl_shell has already been bound");
1091                 return;
1092         }
1093
1094         wl_resource_set_implementation(resource, &agl_shell_implementation,
1095                                        ivi, unbind_agl_shell);
1096         ivi->shell_client.resource = resource;
1097 }
1098
1099 static void
1100 unbind_agl_shell_desktop(struct wl_resource *resource)
1101 {
1102         struct desktop_client *dclient = wl_resource_get_user_data(resource);
1103
1104         wl_list_remove(&dclient->link);
1105         free(dclient);
1106 }
1107
1108 static void
1109 bind_agl_shell_desktop(struct wl_client *client,
1110                        void *data, uint32_t version, uint32_t id)
1111 {
1112         struct ivi_compositor *ivi = data;
1113         struct wl_resource *resource;
1114         struct ivi_policy *policy;
1115         struct desktop_client *dclient;
1116         void *interface;
1117
1118         policy = ivi->policy;
1119         interface  = (void *) &agl_shell_desktop_interface;
1120         if (policy && policy->api.shell_bind_interface &&
1121             !policy->api.shell_bind_interface(client, interface)) {
1122                 wl_client_post_implementation_error(client,
1123                                 "client not authorized to use agl_shell_desktop");
1124                 return;
1125         }
1126
1127         dclient = zalloc(sizeof(*dclient));
1128         if (!dclient) {
1129                 wl_client_post_no_memory(client);
1130                 return;
1131         }
1132
1133         resource = wl_resource_create(client, &agl_shell_desktop_interface,
1134                                       version, id);
1135         dclient->ivi = ivi;
1136         if (!resource) {
1137                 wl_client_post_no_memory(client);
1138                 return;
1139         }
1140
1141         wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
1142                                        dclient, unbind_agl_shell_desktop);
1143
1144         dclient->resource = resource;
1145         wl_list_insert(&ivi->desktop_clients, &dclient->link);
1146
1147         /* advertise xdg surfaces */
1148         ivi_shell_advertise_xdg_surfaces(ivi, resource);
1149 }
1150
1151 int
1152 ivi_shell_create_global(struct ivi_compositor *ivi)
1153 {
1154         ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
1155                                           &agl_shell_interface, 1,
1156                                           ivi, bind_agl_shell);
1157         if (!ivi->agl_shell) {
1158                 weston_log("Failed to create wayland global.\n");
1159                 return -1;
1160         }
1161
1162         ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
1163                                                   &agl_shell_desktop_interface, 1,
1164                                                   ivi, bind_agl_shell_desktop);
1165         if (!ivi->agl_shell_desktop) {
1166                 weston_log("Failed to create wayland global (agl_shell_desktop).\n");
1167                 return -1;
1168         }
1169
1170         return 0;
1171 }