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