40beef10e9338a4da6e9d36e035a1ae90caf0c36
[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                 wl_list_remove(&fs->fs_destroy.link);
565                 free(fs->fs);
566         }
567 }
568
569
570 static void
571 create_black_surface_view(struct ivi_output *output)
572 {
573         struct weston_surface *surface = NULL;
574         struct weston_view *view;
575         struct ivi_compositor *ivi = output->ivi;
576         struct weston_compositor *wc= ivi->compositor;
577         struct weston_output *woutput = output->output;
578
579         surface = weston_surface_create(wc);
580         view = weston_view_create(surface);
581
582         assert(view || surface);
583
584         weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
585         weston_surface_set_size(surface, woutput->width, woutput->height);
586         weston_view_set_position(view, woutput->x, woutput->y);
587
588         output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
589         output->fullscreen_view.fs->view = view;
590
591         output->fullscreen_view.fs_destroy.notify = destroy_black_view;
592         wl_signal_add(&woutput->destroy_signal,
593                       &output->fullscreen_view.fs_destroy);
594 }
595
596 void
597 remove_black_surface(struct ivi_output *output)
598 {
599         struct weston_view *view;
600
601         if (!output &&
602             !output->fullscreen_view.fs &&
603             !output->fullscreen_view.fs->view) {
604                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
605                 return;
606         }
607
608         view = output->fullscreen_view.fs->view;
609         assert(view->is_mapped == true ||
610                view->surface->is_mapped == true);
611
612         view->is_mapped = false;
613         view->surface->is_mapped = false;
614
615         weston_layer_entry_remove(&view->layer_link);
616         weston_view_update_transform(view);
617
618         weston_output_damage(output->output);
619 }
620
621 void
622 insert_black_surface(struct ivi_output *output)
623 {
624         struct weston_view *view;
625
626         if (!output &&
627             !output->fullscreen_view.fs &&
628             !output->fullscreen_view.fs->view) {
629                 weston_log("Output %s doesn't have a surface installed!\n", output->name);
630                 return;
631         }
632
633         view = output->fullscreen_view.fs->view;
634         if (view->is_mapped || view->surface->is_mapped)
635                 return;
636
637         weston_layer_entry_remove(&view->layer_link);
638         weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
639                                   &view->layer_link);
640
641         view->is_mapped = true;
642         view->surface->is_mapped = true;
643
644         weston_view_update_transform(view);
645         weston_output_damage(output->output);
646 }
647
648 static void
649 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
650 {
651         struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
652         struct ivi_output *output;
653         struct ivi_surface *surface, *tmp;
654
655         /* Init already finished. Do nothing */
656         if (ivi->shell_client.ready)
657                 return;
658
659         ivi->shell_client.ready = true;
660
661         wl_list_for_each(output, &ivi->outputs, link) {
662                 if (output->background)
663                         remove_black_surface(output);
664                 ivi_layout_init(ivi, output);
665         }
666
667         wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
668                 wl_list_remove(&surface->link);
669                 ivi_check_pending_desktop_surface(surface);
670         }
671 }
672
673 static void
674 shell_set_background(struct wl_client *client,
675                      struct wl_resource *shell_res,
676                      struct wl_resource *surface_res,
677                      struct wl_resource *output_res)
678 {
679         struct weston_head *head = weston_head_from_resource(output_res);
680         struct weston_output *woutput = weston_head_get_output(head);
681         struct ivi_output *output = to_ivi_output(woutput);
682         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
683         struct weston_desktop_surface *dsurface;
684         struct ivi_surface *surface;
685
686         dsurface = weston_surface_get_desktop_surface(wsurface);
687         if (!dsurface) {
688                 wl_resource_post_error(shell_res,
689                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
690                                        "surface must be a desktop surface");
691                 return;
692         }
693
694         surface = weston_desktop_surface_get_user_data(dsurface);
695         if (surface->role != IVI_SURFACE_ROLE_NONE) {
696                 wl_resource_post_error(shell_res,
697                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
698                                        "surface already has another ivi role");
699                 return;
700         }
701
702         if (output->background) {
703                 wl_resource_post_error(shell_res,
704                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
705                                        "output already has background");
706                 return;
707         }
708
709         surface->role = IVI_SURFACE_ROLE_BACKGROUND;
710         surface->bg.output = output;
711         wl_list_remove(&surface->link);
712         wl_list_init(&surface->link);
713
714         output->background = surface;
715
716         weston_desktop_surface_set_maximized(dsurface, true);
717         weston_desktop_surface_set_size(dsurface,
718                                         output->output->width,
719                                         output->output->height);
720 }
721
722 static void
723 shell_set_panel(struct wl_client *client,
724                 struct wl_resource *shell_res,
725                 struct wl_resource *surface_res,
726                 struct wl_resource *output_res,
727                 uint32_t edge)
728 {
729         struct weston_head *head = weston_head_from_resource(output_res);
730         struct weston_output *woutput = weston_head_get_output(head);
731         struct ivi_output *output = to_ivi_output(woutput);
732         struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
733         struct weston_desktop_surface *dsurface;
734         struct ivi_surface *surface;
735         struct ivi_surface **member;
736         int32_t width = 0, height = 0;
737
738         dsurface = weston_surface_get_desktop_surface(wsurface);
739         if (!dsurface) {
740                 wl_resource_post_error(shell_res,
741                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
742                                        "surface must be a desktop surface");
743                 return;
744         }
745
746         surface = weston_desktop_surface_get_user_data(dsurface);
747         if (surface->role != IVI_SURFACE_ROLE_NONE) {
748                 wl_resource_post_error(shell_res,
749                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
750                                        "surface already has another ivi role");
751                 return;
752         }
753
754         switch (edge) {
755         case AGL_SHELL_EDGE_TOP:
756                 member = &output->top;
757                 break;
758         case AGL_SHELL_EDGE_BOTTOM:
759                 member = &output->bottom;
760                 break;
761         case AGL_SHELL_EDGE_LEFT:
762                 member = &output->left;
763                 break;
764         case AGL_SHELL_EDGE_RIGHT:
765                 member = &output->right;
766                 break;
767         default:
768                 wl_resource_post_error(shell_res,
769                                        AGL_SHELL_ERROR_INVALID_ARGUMENT,
770                                        "invalid edge for panel");
771                 return;
772         }
773
774         if (*member) {
775                 wl_resource_post_error(shell_res,
776                                        AGL_SHELL_ERROR_BACKGROUND_EXISTS,
777                                        "output already has panel on this edge");
778                 return;
779         }
780
781         surface->role = IVI_SURFACE_ROLE_PANEL;
782         surface->panel.output = output;
783         surface->panel.edge = edge;
784         wl_list_remove(&surface->link);
785         wl_list_init(&surface->link);
786
787         *member = surface;
788
789         switch (surface->panel.edge) {
790         case AGL_SHELL_EDGE_TOP:
791         case AGL_SHELL_EDGE_BOTTOM:
792                 width = woutput->width;
793                 break;
794         case AGL_SHELL_EDGE_LEFT:
795         case AGL_SHELL_EDGE_RIGHT:
796                 height = woutput->height;
797                 break;
798         }
799
800         weston_desktop_surface_set_size(dsurface, width, height);
801 }
802
803 void
804 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
805                           const char *data, uint32_t app_state)
806 {
807         struct desktop_client *dclient;
808         uint32_t app_role;
809         struct ivi_surface *surf = ivi_find_app(ivi, app_id);
810         struct ivi_policy *policy = ivi->policy;
811
812         /* FIXME: should queue it here and see when binding agl-shell-desktop
813          * if there are any to be sent */
814         if (!surf)
815                 return;
816
817         if (!app_id)
818                 return;
819
820         if (policy && policy->api.surface_advertise_state_change &&
821             !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
822                 return;
823         }
824
825         app_role = surf->role;
826         if (app_role == IVI_SURFACE_ROLE_POPUP)
827                 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
828
829         wl_list_for_each(dclient, &ivi->desktop_clients, link)
830                 agl_shell_desktop_send_state_app(dclient->resource, app_id,
831                                                  data, app_state, app_role);
832 }
833
834 static void
835 shell_activate_app(struct wl_client *client,
836                    struct wl_resource *shell_res,
837                    const char *app_id,
838                    struct wl_resource *output_res)
839 {
840         struct weston_head *head = weston_head_from_resource(output_res);
841         struct weston_output *woutput = weston_head_get_output(head);
842         struct ivi_output *output = to_ivi_output(woutput);
843
844         ivi_layout_activate(output, app_id);
845 }
846
847 static void
848 shell_desktop_activate_app(struct wl_client *client,
849                            struct wl_resource *shell_res,
850                            const char *app_id, const char *data,
851                            struct wl_resource *output_res)
852 {
853         struct weston_head *head = weston_head_from_resource(output_res);
854         struct weston_output *woutput = weston_head_get_output(head);
855         struct ivi_output *output = to_ivi_output(woutput);
856
857         ivi_layout_activate(output, app_id);
858         shell_advertise_app_state(output->ivi, app_id,
859                                   data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
860 }
861
862 static void
863 shell_deactivate_app(struct wl_client *client,
864                    struct wl_resource *shell_res,
865                    const char *app_id)
866 {
867         struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
868         struct ivi_compositor *ivi = dclient->ivi;
869
870         ivi_layout_deactivate(ivi, app_id);
871         shell_advertise_app_state(ivi, app_id,
872                                   NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
873 }
874
875 static const struct agl_shell_interface agl_shell_implementation = {
876         .ready = shell_ready,
877         .set_background = shell_set_background,
878         .set_panel = shell_set_panel,
879         .activate_app = shell_activate_app,
880 };
881
882 static void
883 shell_desktop_set_app_property(struct wl_client *client,
884                                struct wl_resource *shell_res,
885                                const char *app_id, uint32_t role,
886                                int x, int y, int bx, int by,
887                                int width, int height,
888                                struct wl_resource *output_res)
889 {
890         struct weston_head *head = weston_head_from_resource(output_res);
891         struct weston_output *woutput = weston_head_get_output(head);
892         struct ivi_output *output = to_ivi_output(woutput);
893
894         switch (role) {
895         case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
896                 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
897                                                       width, height, app_id);
898                 break;
899         case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
900                 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
901                 break;
902         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
903         case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
904                 ivi_set_pending_desktop_surface_split(output, app_id, role);
905                 break;
906         case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
907                 ivi_set_pending_desktop_surface_remote(output, app_id);
908                 break;
909         default:
910                 break;
911         }
912 }
913
914 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
915         .activate_app = shell_desktop_activate_app,
916         .set_app_property = shell_desktop_set_app_property,
917         .deactivate_app = shell_deactivate_app,
918 };
919
920 static void
921 unbind_agl_shell(struct wl_resource *resource)
922 {
923         struct ivi_compositor *ivi;
924         struct ivi_output *output;
925         struct ivi_surface *surf, *surf_tmp;
926
927         ivi = wl_resource_get_user_data(resource);
928         wl_list_for_each(output, &ivi->outputs, link) {
929                 /* reset the active surf if there's one present */
930                 if (output->active) {
931                         output->active->view->is_mapped = false;
932                         output->active->view->surface->is_mapped = false;
933
934                         weston_layer_entry_remove(&output->active->view->layer_link);
935                         output->active = NULL;
936                 }
937
938                 insert_black_surface(output);
939         }
940
941         wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
942                 wl_list_remove(&surf->link);
943                 wl_list_init(&surf->link);
944         }
945
946         wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
947                 wl_list_remove(&surf->link);
948                 wl_list_init(&surf->link);
949         }
950
951         wl_list_init(&ivi->surfaces);
952         wl_list_init(&ivi->pending_surfaces);
953
954         ivi->shell_client.ready = false;
955         ivi->shell_client.resource = NULL;
956         ivi->shell_client.client = NULL;
957 }
958
959 static void
960 bind_agl_shell(struct wl_client *client,
961                void *data, uint32_t version, uint32_t id)
962 {
963         struct ivi_compositor *ivi = data;
964         struct wl_resource *resource;
965         struct ivi_policy *policy;
966         void *interface;
967
968         policy = ivi->policy;
969         interface = (void *) &agl_shell_interface;
970         if (policy && policy->api.shell_bind_interface &&
971             !policy->api.shell_bind_interface(client, interface)) {
972                 wl_client_post_implementation_error(client,
973                                        "client not authorized to use agl_shell");
974                 return;
975         }
976
977         resource = wl_resource_create(client, &agl_shell_interface,
978                                       1, id);
979         if (!resource) {
980                 wl_client_post_no_memory(client);
981                 return;
982         }
983
984 #if 0
985         if (ivi->shell_client.client != client) {
986                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
987                                        "client not authorized to use agl_shell");
988                 return;
989         }
990 #endif
991
992         if (ivi->shell_client.resource) {
993                 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
994                                        "agl_shell has already been bound");
995                 return;
996         }
997
998         wl_resource_set_implementation(resource, &agl_shell_implementation,
999                                        ivi, unbind_agl_shell);
1000         ivi->shell_client.resource = resource;
1001 }
1002
1003 static void
1004 unbind_agl_shell_desktop(struct wl_resource *resource)
1005 {
1006         struct desktop_client *dclient = wl_resource_get_user_data(resource);
1007
1008         wl_list_remove(&dclient->link);
1009         free(dclient);
1010 }
1011
1012 static void
1013 bind_agl_shell_desktop(struct wl_client *client,
1014                        void *data, uint32_t version, uint32_t id)
1015 {
1016         struct ivi_compositor *ivi = data;
1017         struct wl_resource *resource;
1018         struct ivi_policy *policy;
1019         struct desktop_client *dclient;
1020         void *interface;
1021
1022         policy = ivi->policy;
1023         interface  = (void *) &agl_shell_desktop_interface;
1024         if (policy && policy->api.shell_bind_interface &&
1025             !policy->api.shell_bind_interface(client, interface)) {
1026                 wl_client_post_implementation_error(client,
1027                                 "client not authorized to use agl_shell_desktop");
1028                 return;
1029         }
1030
1031         dclient = zalloc(sizeof(*dclient));
1032         if (!dclient) {
1033                 wl_client_post_no_memory(client);
1034                 return;
1035         }
1036
1037         resource = wl_resource_create(client, &agl_shell_desktop_interface,
1038                                       version, id);
1039         dclient->ivi = ivi;
1040         if (!resource) {
1041                 wl_client_post_no_memory(client);
1042                 return;
1043         }
1044
1045         wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
1046                                        dclient, unbind_agl_shell_desktop);
1047
1048         dclient->resource = resource;
1049         wl_list_insert(&ivi->desktop_clients, &dclient->link);
1050
1051         /* advertise xdg surfaces */
1052         ivi_shell_advertise_xdg_surfaces(ivi, resource);
1053 }
1054
1055 int
1056 ivi_shell_create_global(struct ivi_compositor *ivi)
1057 {
1058         ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
1059                                           &agl_shell_interface, 1,
1060                                           ivi, bind_agl_shell);
1061         if (!ivi->agl_shell) {
1062                 weston_log("Failed to create wayland global.\n");
1063                 return -1;
1064         }
1065
1066         ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
1067                                                   &agl_shell_desktop_interface, 1,
1068                                                   ivi, bind_agl_shell_desktop);
1069         if (!ivi->agl_shell_desktop) {
1070                 weston_log("Failed to create wayland global (agl_shell_desktop).\n");
1071                 return -1;
1072         }
1073
1074         return 0;
1075 }