2 * Copyright © 2019, 2022 Collabora, Ltd.
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:
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.
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
26 #include "ivi-compositor.h"
34 #include <sys/socket.h>
35 #include <sys/types.h>
38 #include <libweston/libweston.h>
39 #include <libweston/config-parser.h>
42 #include "shared/os-compatibility.h"
43 #include "shared/helpers.h"
44 #include "shared/process-util.h"
46 #include "agl-shell-server-protocol.h"
47 #include "agl-shell-desktop-server-protocol.h"
50 create_black_curtain_view(struct ivi_output *output);
53 _ivi_set_shell_surface_split(struct ivi_surface *surface, struct ivi_output *output,
54 uint32_t orientation, bool to_activate);
57 reverse_orientation(uint32_t orientation);
60 agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi,
61 struct ivi_surface *surface)
63 struct desktop_client *dclient;
64 static bool display_adv = false;
66 if (surface->advertised_on_launch)
69 /* advertise to all desktop clients the new surface */
70 wl_list_for_each(dclient, &ivi->desktop_clients, link) {
72 weston_desktop_surface_get_app_id(surface->dsurface);
75 weston_log("WARNING app_is is null, unable to advertise\n");
80 agl_shell_desktop_send_application(dclient->resource, app_id);
81 surface->advertised_on_launch = true;
86 ivi_set_desktop_surface(struct ivi_surface *surface)
88 struct ivi_compositor *ivi = surface->ivi;
89 assert(surface->role == IVI_SURFACE_ROLE_NONE);
91 surface->role = IVI_SURFACE_ROLE_DESKTOP;
92 wl_list_insert(&surface->ivi->surfaces, &surface->link);
94 agl_shell_desktop_advertise_application_id(ivi, surface);
98 ivi_set_background_surface(struct ivi_surface *surface)
100 struct ivi_compositor *ivi = surface->ivi;
101 assert(surface->role == IVI_SURFACE_ROLE_BACKGROUND);
103 wl_list_insert(&surface->ivi->surfaces, &surface->link);
104 agl_shell_desktop_advertise_application_id(ivi, surface);
108 ivi_set_desktop_surface_popup(struct ivi_surface *surface)
110 struct ivi_compositor *ivi = surface->ivi;
111 assert(surface->role == IVI_SURFACE_ROLE_NONE);
113 surface->role = IVI_SURFACE_ROLE_POPUP;
114 wl_list_insert(&ivi->surfaces, &surface->link);
116 agl_shell_desktop_advertise_application_id(ivi, surface);
120 ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface)
122 struct ivi_compositor *ivi = surface->ivi;
123 assert(surface->role == IVI_SURFACE_ROLE_NONE);
125 surface->role = IVI_SURFACE_ROLE_FULLSCREEN;
126 wl_list_insert(&ivi->surfaces, &surface->link);
128 agl_shell_desktop_advertise_application_id(ivi, surface);
132 ivi_set_desktop_surface_remote(struct ivi_surface *surface)
134 struct ivi_compositor *ivi = surface->ivi;
135 struct weston_view *view;
136 struct ivi_output *output = surface->remote.output;
138 assert(surface->role == IVI_SURFACE_ROLE_NONE);
140 /* remote type are the same as desktop just that client can tell
141 * the compositor to start on another output */
142 surface->role = IVI_SURFACE_ROLE_REMOTE;
144 /* if thew black surface view is mapped on the mean we need
145 * to remove it in order to start showing the 'remote' surface
146 * just being added */
147 view = output->fullscreen_view.fs->view;
148 if (view->is_mapped || view->surface->is_mapped)
149 remove_black_curtain(output);
151 wl_list_insert(&ivi->surfaces, &surface->link);
156 ivi_set_desktop_surface_split(struct ivi_surface *surface)
158 struct ivi_compositor *ivi = surface->ivi;
159 assert(surface->role == IVI_SURFACE_ROLE_NONE);
161 if (surface->split.orientation == AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL)
162 surface->role = IVI_SURFACE_ROLE_SPLIT_V;
164 surface->role = IVI_SURFACE_ROLE_SPLIT_H;
166 wl_list_insert(&ivi->surfaces, &surface->link);
168 agl_shell_desktop_advertise_application_id(ivi, surface);
171 static struct pending_popup *
172 ivi_ensure_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
173 int width, int height, const char *app_id)
175 struct pending_popup *p_popup = zalloc(sizeof(*p_popup));
176 size_t len_app_id = strlen(app_id);
180 p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
181 if (!p_popup->app_id) {
185 memcpy(p_popup->app_id, app_id, len_app_id);
186 p_popup->ioutput = ioutput;
192 p_popup->bb.width = width;
193 p_popup->bb.height = height;
199 ivi_update_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
200 int width, int height, const char *app_id, struct pending_popup *p_popup)
202 size_t len_app_id = strlen(app_id);
204 wl_list_remove(&p_popup->link);
205 wl_list_init(&p_popup->link);
207 memset(p_popup->app_id, 0, strlen(app_id) + 1);
208 free(p_popup->app_id);
210 p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
211 if (!p_popup->app_id)
213 memcpy(p_popup->app_id, app_id, len_app_id);
215 p_popup->ioutput = ioutput;
221 p_popup->bb.width = width;
222 p_popup->bb.height = height;
225 static struct pending_fullscreen *
226 ivi_ensure_fullscreen(struct ivi_output *ioutput, const char *app_id)
228 struct pending_fullscreen *p_fullscreen = zalloc(sizeof(*p_fullscreen));
229 size_t len_app_id = strlen(app_id);
233 p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
234 if (!p_fullscreen->app_id) {
238 memcpy(p_fullscreen->app_id, app_id, len_app_id);
240 p_fullscreen->ioutput = ioutput;
245 ivi_update_fullscreen(struct ivi_output *ioutput, const char *app_id,
246 struct pending_fullscreen *p_fullscreen)
248 size_t len_app_id = strlen(app_id);
250 wl_list_remove(&p_fullscreen->link);
251 wl_list_init(&p_fullscreen->link);
253 memset(p_fullscreen->app_id, 0, strlen(app_id) + 1);
254 free(p_fullscreen->app_id);
256 p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
257 if (!p_fullscreen->app_id)
259 memcpy(p_fullscreen->app_id, app_id, len_app_id);
261 p_fullscreen->ioutput = ioutput;
264 static struct pending_remote *
265 ivi_ensure_remote(struct ivi_output *ioutput, const char *app_id)
267 struct pending_remote *p_remote = zalloc(sizeof(*p_remote));
268 size_t len_app_id = strlen(app_id);
272 p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
273 if (!p_remote->app_id) {
277 memcpy(p_remote->app_id, app_id, len_app_id);
279 p_remote->ioutput = ioutput;
284 ivi_update_remote(struct ivi_output *ioutput, const char *app_id,
285 struct pending_remote *p_remote)
287 size_t len_app_id = strlen(app_id);
289 wl_list_remove(&p_remote->link);
290 wl_list_init(&p_remote->link);
292 memset(p_remote->app_id, 0, strlen(app_id) + 1);
293 free(p_remote->app_id);
295 p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
296 if (!p_remote->app_id)
298 memcpy(p_remote->app_id, app_id, len_app_id);
300 p_remote->ioutput = ioutput;
304 ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput, int x, int y, int bx,
305 int by, int width, int height, const char *app_id)
307 struct ivi_compositor *ivi = ioutput->ivi;
308 struct pending_popup *p_popup = NULL;
309 struct pending_popup *popup;
311 wl_list_for_each(popup, &ivi->popup_pending_apps, link)
312 if (!strcmp(app_id, popup->app_id))
316 p_popup = ivi_ensure_popup(ioutput, x, y, bx, by, width, height, app_id);
318 ivi_update_popup(ioutput, x, y, bx, by, width, height, app_id, p_popup);
322 wl_list_insert(&ivi->popup_pending_apps, &p_popup->link);
326 ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput,
329 struct ivi_compositor *ivi = ioutput->ivi;
330 struct pending_fullscreen *p_fullscreen = NULL;
331 struct pending_fullscreen *fullscreen;
333 wl_list_for_each(fullscreen, &ivi->fullscreen_pending_apps, link)
334 if (!strcmp(app_id, fullscreen->app_id))
335 p_fullscreen = fullscreen;
338 p_fullscreen = ivi_ensure_fullscreen(ioutput, app_id);
340 ivi_update_fullscreen(ioutput, app_id, p_fullscreen);
344 wl_list_insert(&ivi->fullscreen_pending_apps, &p_fullscreen->link);
348 ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput,
349 const char *app_id, uint32_t orientation)
351 struct ivi_compositor *ivi = ioutput->ivi;
352 struct ivi_surface *surf;
353 size_t len_app_id = strlen(app_id);
354 struct pending_split *split;
356 if (orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL &&
357 orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL)
360 /* more than one is un-supported, do note we need to do
361 * conversion for surface roles instead of using the protocol ones */
362 wl_list_for_each(surf, &ivi->surfaces, link)
363 if (surf->role == IVI_SURFACE_ROLE_SPLIT_V ||
364 surf->role == IVI_SURFACE_ROLE_SPLIT_H)
367 split = zalloc(sizeof(*split));
370 split->app_id = zalloc(sizeof(char) * (len_app_id + 1));
371 if (!split->app_id) {
375 memcpy(split->app_id, app_id, len_app_id);
377 split->ioutput = ioutput;
378 split->orientation = orientation;
380 wl_list_insert(&ivi->split_pending_apps, &split->link);
384 ivi_set_pending_desktop_surface_remote(struct ivi_output *ioutput,
387 struct ivi_compositor *ivi = ioutput->ivi;
388 struct pending_remote *remote;
389 struct pending_remote *p_remote = NULL;
391 wl_list_for_each(remote, &ivi->remote_pending_apps, link)
392 if (!strcmp(app_id, remote->app_id))
396 p_remote = ivi_ensure_remote(ioutput, app_id);
398 ivi_update_remote(ioutput, app_id, p_remote);
402 wl_list_insert(&ivi->remote_pending_apps, &p_remote->link);
407 ivi_remove_pending_desktop_surface_split(struct pending_split *split)
410 wl_list_remove(&split->link);
415 ivi_remove_pending_desktop_surface_fullscreen(struct pending_fullscreen *fs)
418 wl_list_remove(&fs->link);
423 ivi_remove_pending_desktop_surface_popup(struct pending_popup *p_popup)
425 free(p_popup->app_id);
426 wl_list_remove(&p_popup->link);
431 ivi_remove_pending_desktop_surface_remote(struct pending_remote *remote)
433 free(remote->app_id);
434 wl_list_remove(&remote->link);
439 ivi_compositor_keep_pending_surfaces(struct ivi_surface *surface)
441 return surface->ivi->keep_pending_surfaces;
445 ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface)
447 struct ivi_compositor *ivi = surface->ivi;
448 struct pending_popup *p_popup, *next_p_popup;
449 const char *_app_id =
450 weston_desktop_surface_get_app_id(surface->dsurface);
452 if (wl_list_empty(&ivi->popup_pending_apps) || !_app_id)
455 wl_list_for_each_safe(p_popup, next_p_popup,
456 &ivi->popup_pending_apps, link) {
457 if (!strcmp(_app_id, p_popup->app_id)) {
458 surface->popup.output = p_popup->ioutput;
459 surface->popup.x = p_popup->x;
460 surface->popup.y = p_popup->y;
462 surface->popup.bb.x = p_popup->bb.x;
463 surface->popup.bb.y = p_popup->bb.y;
464 surface->popup.bb.width = p_popup->bb.width;
465 surface->popup.bb.height = p_popup->bb.height;
467 if (!ivi_compositor_keep_pending_surfaces(surface))
468 ivi_remove_pending_desktop_surface_popup(p_popup);
477 ivi_check_pending_desktop_surface_split(struct ivi_surface *surface)
479 struct pending_split *split_surf, *next_split_surf;
480 struct ivi_compositor *ivi = surface->ivi;
481 const char *_app_id =
482 weston_desktop_surface_get_app_id(surface->dsurface);
484 if (wl_list_empty(&ivi->split_pending_apps) || !_app_id)
487 wl_list_for_each_safe(split_surf, next_split_surf,
488 &ivi->split_pending_apps, link) {
489 if (!strcmp(_app_id, split_surf->app_id)) {
490 surface->split.output = split_surf->ioutput;
491 surface->split.orientation = split_surf->orientation;
492 if (!ivi_compositor_keep_pending_surfaces(surface))
493 ivi_remove_pending_desktop_surface_split(split_surf);
502 ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface)
504 struct pending_fullscreen *fs_surf, *next_fs_surf;
505 struct ivi_compositor *ivi = surface->ivi;
506 const char *_app_id =
507 weston_desktop_surface_get_app_id(surface->dsurface);
509 if (wl_list_empty(&ivi->fullscreen_pending_apps) || !_app_id)
512 wl_list_for_each_safe(fs_surf, next_fs_surf,
513 &ivi->fullscreen_pending_apps, link) {
514 if (!strcmp(_app_id, fs_surf->app_id)) {
515 surface->fullscreen.output = fs_surf->ioutput;
516 if (!ivi_compositor_keep_pending_surfaces(surface))
517 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
526 ivi_check_pending_desktop_surface_remote(struct ivi_surface *surface)
528 struct pending_remote *remote_surf, *next_remote_surf;
529 struct ivi_compositor *ivi = surface->ivi;
530 const char *_app_id =
531 weston_desktop_surface_get_app_id(surface->dsurface);
533 if (wl_list_empty(&ivi->remote_pending_apps) || !_app_id)
536 wl_list_for_each_safe(remote_surf, next_remote_surf,
537 &ivi->remote_pending_apps, link) {
538 if (!strcmp(_app_id, remote_surf->app_id)) {
539 surface->remote.output = remote_surf->ioutput;
540 if (!ivi_compositor_keep_pending_surfaces(surface))
541 ivi_remove_pending_desktop_surface_remote(remote_surf);
549 ivi_check_pending_surface_desktop(struct ivi_surface *surface,
550 enum ivi_surface_role *role)
552 struct ivi_compositor *ivi = surface->ivi;
553 struct wl_list *role_pending_list;
554 struct pending_popup *p_popup;
555 struct pending_split *p_split;
556 struct pending_fullscreen *p_fullscreen;
557 struct pending_remote *p_remote;
559 weston_desktop_surface_get_app_id(surface->dsurface);
561 role_pending_list = &ivi->popup_pending_apps;
562 wl_list_for_each(p_popup, role_pending_list, link) {
563 if (app_id && !strcmp(app_id, p_popup->app_id)) {
564 *role = IVI_SURFACE_ROLE_POPUP;
569 role_pending_list = &ivi->split_pending_apps;
570 wl_list_for_each(p_split, role_pending_list, link) {
571 if (app_id && !strcmp(app_id, p_split->app_id)) {
572 *role = IVI_SURFACE_ROLE_SPLIT_V;
577 role_pending_list = &ivi->fullscreen_pending_apps;
578 wl_list_for_each(p_fullscreen, role_pending_list, link) {
579 if (app_id && !strcmp(app_id, p_fullscreen->app_id)) {
580 *role = IVI_SURFACE_ROLE_FULLSCREEN;
585 role_pending_list = &ivi->remote_pending_apps;
586 wl_list_for_each(p_remote, role_pending_list, link) {
587 if (app_id && !strcmp(app_id, p_remote->app_id)) {
588 *role = IVI_SURFACE_ROLE_REMOTE;
593 /* else, we are a regular desktop surface */
594 *role = IVI_SURFACE_ROLE_DESKTOP;
598 ivi_check_pending_app_type(struct ivi_surface *surface, enum ivi_surface_role role)
600 struct pending_app *papp;
601 const char *app_id = NULL;
603 app_id = weston_desktop_surface_get_app_id(surface->dsurface);
607 wl_list_for_each(papp, &surface->ivi->pending_apps, link) {
608 if (strcmp(app_id, papp->app_id) == 0 && papp->role == role)
617 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
621 ret = ivi_check_pending_desktop_surface_popup(surface);
623 ivi_set_desktop_surface_popup(surface);
624 ivi_layout_popup_committed(surface);
628 ret = ivi_check_pending_desktop_surface_split(surface);
630 ivi_set_desktop_surface_split(surface);
631 ivi_layout_split_committed(surface);
635 ret = ivi_check_pending_desktop_surface_fullscreen(surface);
637 ivi_set_desktop_surface_fullscreen(surface);
638 ivi_layout_fullscreen_committed(surface);
642 ret = ivi_check_pending_desktop_surface_remote(surface);
644 ivi_set_desktop_surface_remote(surface);
645 ivi_layout_remote_committed(surface);
649 /* new way of doing it */
650 struct pending_app *papp =
651 ivi_check_pending_app_type(surface, IVI_SURFACE_ROLE_TILE);
653 struct pending_app_tile *papp_tile =
654 container_of(papp, struct pending_app_tile, base);
656 // handle the currently active surface
657 if (papp->ioutput->active) {
658 _ivi_set_shell_surface_split(papp->ioutput->active, NULL,
659 reverse_orientation(papp_tile->orientation), false);
662 surface->role = IVI_SURFACE_ROLE_TILE;
663 surface->current_completed_output = papp->ioutput;
664 wl_list_insert(&surface->ivi->surfaces, &surface->link);
666 _ivi_set_shell_surface_split(surface, papp->ioutput,
667 papp_tile->orientation, true);
669 /* remove it from pending */
670 wl_list_remove(&papp->link);
677 /* if we end up here means we have a regular desktop app and
678 * try to activate it */
679 ivi_set_desktop_surface(surface);
680 ivi_layout_desktop_committed(surface);
684 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
686 struct ivi_output *out;
688 wl_list_for_each(out, &ivi->outputs, link) {
689 create_black_curtain_view(out);
690 insert_black_curtain(out);
695 ivi_shell_init(struct ivi_compositor *ivi)
697 weston_layer_init(&ivi->hidden, ivi->compositor);
698 weston_layer_init(&ivi->background, ivi->compositor);
699 weston_layer_init(&ivi->normal, ivi->compositor);
700 weston_layer_init(&ivi->panel, ivi->compositor);
701 weston_layer_init(&ivi->popup, ivi->compositor);
702 weston_layer_init(&ivi->fullscreen, ivi->compositor);
704 weston_layer_set_position(&ivi->hidden,
705 WESTON_LAYER_POSITION_HIDDEN);
706 weston_layer_set_position(&ivi->background,
707 WESTON_LAYER_POSITION_BACKGROUND);
708 weston_layer_set_position(&ivi->normal,
709 WESTON_LAYER_POSITION_NORMAL);
710 weston_layer_set_position(&ivi->panel,
711 WESTON_LAYER_POSITION_UI);
712 weston_layer_set_position(&ivi->popup,
713 WESTON_LAYER_POSITION_TOP_UI);
714 weston_layer_set_position(&ivi->fullscreen,
715 WESTON_LAYER_POSITION_FULLSCREEN);
722 ivi_surf_destroy(struct ivi_surface *surf)
724 struct weston_surface *wsurface = surf->view->surface;
726 if (weston_surface_is_mapped(wsurface)) {
727 weston_desktop_surface_unlink_view(surf->view);
728 weston_view_destroy(surf->view);
731 wl_list_remove(&surf->link);
736 ivi_shell_destroy_views_on_layer(struct weston_layer *layer)
738 struct weston_view *view, *view_next;
740 wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) {
741 struct ivi_surface *ivi_surf =
742 get_ivi_shell_surface(view->surface);
744 ivi_surf_destroy(ivi_surf);
749 ivi_shell_finalize(struct ivi_compositor *ivi)
751 struct ivi_output *output;
753 ivi_shell_destroy_views_on_layer(&ivi->hidden);
754 weston_layer_fini(&ivi->hidden);
756 ivi_shell_destroy_views_on_layer(&ivi->background);
757 weston_layer_fini(&ivi->background);
759 ivi_shell_destroy_views_on_layer(&ivi->normal);
760 weston_layer_fini(&ivi->normal);
762 ivi_shell_destroy_views_on_layer(&ivi->panel);
763 weston_layer_fini(&ivi->panel);
765 ivi_shell_destroy_views_on_layer(&ivi->popup);
766 weston_layer_fini(&ivi->popup);
768 wl_list_for_each(output, &ivi->outputs, link) {
769 if (output->fullscreen_view.fs &&
770 output->fullscreen_view.fs->view) {
771 weston_surface_destroy(output->fullscreen_view.fs->view->surface);
772 output->fullscreen_view.fs->view = NULL;
775 weston_layer_fini(&ivi->fullscreen);
779 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
781 struct ivi_surface *surface;
783 wl_list_for_each(surface, &ivi->surfaces, link) {
785 weston_desktop_surface_get_app_id(surface->dsurface);
786 if (app_id == NULL) {
787 weston_log("WARNING app_is is null, unable to advertise\n");
790 agl_shell_desktop_send_application(resource, app_id);
794 static struct wl_client *
795 client_launch(struct weston_compositor *compositor,
796 struct weston_process *proc,
798 weston_process_cleanup_func_t cleanup)
800 struct wl_client *client = NULL;
801 struct custom_env child_env;
802 struct fdstr wayland_socket;
803 const char *fail_cloexec = "Couldn't unset CLOEXEC on client socket";
804 const char *fail_seteuid = "Couldn't call seteuid";
811 struct ivi_compositor *ivi;
812 size_t written __attribute__((unused));
814 weston_log("launching '%s'\n", path);
815 str_printf(&fail_exec, "Error: Couldn't launch client '%s'\n", path);
817 custom_env_init_from_environ(&child_env);
818 custom_env_add_from_exec_string(&child_env, path);
820 if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0,
821 wayland_socket.fds) < 0) {
822 weston_log("client_launch: "
823 "socketpair failed while launching '%s': %s\n",
824 path, strerror(errno));
825 custom_env_fini(&child_env);
828 fdstr_update_str1(&wayland_socket);
829 custom_env_set_env_var(&child_env, "WAYLAND_SOCKET",
830 wayland_socket.str1);
832 argp = custom_env_get_argp(&child_env);
833 envp = custom_env_get_envp(&child_env);
838 /* Put the client in a new session so it won't catch signals
839 * intended for the parent. Sharing a session can be
840 * confusing when launching weston under gdb, as the ctrl-c
841 * intended for gdb will pass to the child, and weston
842 * will cleanly shut down when the child exits.
846 /* do not give our signal mask to the new process */
847 sigfillset(&allsigs);
848 sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
850 /* Launch clients as the user. Do not launch clients with wrong euid. */
851 if (seteuid(getuid()) == -1) {
852 written = write(STDERR_FILENO, fail_seteuid, strlen(fail_seteuid));
856 ret = fdstr_clear_cloexec_fd1(&wayland_socket);
858 written = write(STDERR_FILENO, fail_cloexec, strlen(fail_cloexec));
862 execve(argp[0], argp, envp);
865 written = write(STDERR_FILENO, fail_exec, strlen(fail_exec));
869 close(wayland_socket.fds[1]);
870 ivi = weston_compositor_get_user_data(compositor);
871 client = wl_client_create(compositor->wl_display,
872 wayland_socket.fds[0]);
874 custom_env_fini(&child_env);
875 close(wayland_socket.fds[0]);
877 weston_log("client_launch: "
878 "wl_client_create failed while launching '%s'.\n",
884 proc->cleanup = cleanup;
885 wl_list_insert(&ivi->child_process_list, &proc->link);
889 fdstr_close_all(&wayland_socket);
890 weston_log("client_launch: "
891 "fork failed while launching '%s': %s\n", path,
896 custom_env_fini(&child_env);
902 struct process_info {
903 struct weston_process proc;
908 sigchld_handler(int signal_number, void *data)
910 struct weston_process *p;
911 struct ivi_compositor *ivi = data;
915 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
916 wl_list_for_each(p, &ivi->child_process_list, link) {
921 if (&p->link == &ivi->child_process_list) {
922 weston_log("unknown child process exited\n");
926 wl_list_remove(&p->link);
927 wl_list_init(&p->link);
928 p->cleanup(p, status);
931 if (pid < 0 && errno != ECHILD)
932 weston_log("waitpid error %s\n", strerror(errno));
939 process_handle_sigchld(struct weston_process *process, int status)
941 struct process_info *pinfo =
942 container_of(process, struct process_info, proc);
945 * There are no guarantees whether this runs before or after
946 * the wl_client destructor.
949 if (WIFEXITED(status)) {
950 weston_log("%s exited with status %d\n", pinfo->path,
951 WEXITSTATUS(status));
952 } else if (WIFSIGNALED(status)) {
953 weston_log("%s died on signal %d\n", pinfo->path,
956 weston_log("%s disappeared\n", pinfo->path);
964 ivi_launch_shell_client(struct ivi_compositor *ivi, const char *cmd_section,
965 struct wl_client **client)
967 struct process_info *pinfo;
968 struct weston_config_section *section;
969 char *command = NULL;
971 section = weston_config_get_section(ivi->config, cmd_section, NULL, NULL);
973 weston_config_section_get_string(section, "command", &command, NULL);
978 pinfo = zalloc(sizeof *pinfo);
982 pinfo->path = strdup(command);
986 *client = client_launch(ivi->compositor, &pinfo->proc, command, process_handle_sigchld);
1002 destroy_black_curtain_view(struct wl_listener *listener, void *data)
1004 struct fullscreen_view *fs =
1005 wl_container_of(listener, fs, fs_destroy);
1009 wl_list_remove(&fs->fs_destroy.link);
1016 create_black_curtain_view(struct ivi_output *output)
1018 struct weston_surface *surface = NULL;
1019 struct weston_view *view;
1020 struct ivi_compositor *ivi = output->ivi;
1021 struct weston_compositor *wc= ivi->compositor;
1022 struct weston_output *woutput = output->output;
1027 surface = weston_surface_create(wc);
1030 view = weston_view_create(surface);
1032 weston_surface_destroy(surface);
1036 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
1037 weston_surface_set_size(surface, woutput->width, woutput->height);
1038 weston_view_set_position(view, woutput->x, woutput->y);
1040 output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
1041 if (!output->fullscreen_view.fs) {
1042 weston_surface_destroy(surface);
1045 output->fullscreen_view.fs->view = view;
1047 output->fullscreen_view.fs_destroy.notify = destroy_black_curtain_view;
1048 wl_signal_add(&woutput->destroy_signal,
1049 &output->fullscreen_view.fs_destroy);
1053 output_has_black_curtain(struct ivi_output *output)
1055 return (output->fullscreen_view.fs &&
1056 output->fullscreen_view.fs->view &&
1057 output->fullscreen_view.fs->view->is_mapped &&
1058 output->fullscreen_view.fs->view->surface->is_mapped);
1062 remove_black_curtain(struct ivi_output *output)
1064 struct weston_view *view;
1067 !output->fullscreen_view.fs &&
1068 !output->fullscreen_view.fs->view) ||
1069 !output->fullscreen_view.fs) {
1070 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1074 view = output->fullscreen_view.fs->view;
1075 assert(view->is_mapped == true ||
1076 view->surface->is_mapped == true);
1078 view->is_mapped = false;
1079 view->surface->is_mapped = false;
1081 weston_layer_entry_remove(&view->layer_link);
1082 weston_view_update_transform(view);
1084 weston_view_damage_below(view);
1086 weston_log("Removed black curtain from output %s\n", output->output->name);
1090 insert_black_curtain(struct ivi_output *output)
1092 struct weston_view *view;
1095 !output->fullscreen_view.fs &&
1096 !output->fullscreen_view.fs->view) || !output->output ||
1097 !output->fullscreen_view.fs) {
1098 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1102 view = output->fullscreen_view.fs->view;
1103 if (view->is_mapped || view->surface->is_mapped)
1106 weston_layer_entry_remove(&view->layer_link);
1107 weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
1110 view->is_mapped = true;
1111 view->surface->is_mapped = true;
1113 weston_view_update_transform(view);
1114 weston_view_damage_below(view);
1116 weston_log("Added black curtain to output %s\n", output->output->name);
1120 shell_send_app_state(struct ivi_compositor *ivi, const char *app_id,
1121 enum agl_shell_app_state state)
1123 if (app_id && wl_resource_get_version(ivi->shell_client.resource) >=
1124 AGL_SHELL_APP_STATE_SINCE_VERSION) {
1126 agl_shell_send_app_state(ivi->shell_client.resource,
1129 if (ivi->shell_client.resource_ext)
1130 agl_shell_send_app_state(ivi->shell_client.resource_ext,
1136 shell_send_app_on_output(struct ivi_compositor *ivi, const char *app_id,
1137 const char *output_name)
1139 if (app_id && ivi->shell_client.resource &&
1140 wl_resource_get_version(ivi->shell_client.resource) >=
1141 AGL_SHELL_APP_ON_OUTPUT_SINCE_VERSION) {
1143 agl_shell_send_app_on_output(ivi->shell_client.resource,
1144 app_id, output_name);
1146 if (ivi->shell_client.resource_ext)
1147 agl_shell_send_app_on_output(ivi->shell_client.resource_ext,
1148 app_id, output_name);
1153 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
1155 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1156 struct ivi_output *output;
1157 struct ivi_surface *surface, *tmp;
1159 if (wl_resource_get_version(shell_res) >=
1160 AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1161 ivi->shell_client.status == BOUND_FAILED) {
1162 wl_resource_post_error(shell_res,
1163 WL_DISPLAY_ERROR_INVALID_OBJECT,
1164 "agl_shell (ready quest) has already "
1165 "been bound. Check out bound_fail event");
1169 /* Init already finished. Do nothing */
1170 if (ivi->shell_client.ready)
1174 ivi->shell_client.ready = true;
1176 wl_list_for_each(output, &ivi->outputs, link) {
1177 if (output->background &&
1178 output->background->role == IVI_SURFACE_ROLE_BACKGROUND) {
1179 /* track the background surface role as a "regular"
1180 * surface so we can activate it */
1181 ivi_set_background_surface(output->background);
1182 remove_black_curtain(output);
1185 ivi_layout_init(ivi, output);
1188 wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
1191 wl_list_remove(&surface->link);
1192 wl_list_init(&surface->link);
1193 ivi_check_pending_desktop_surface(surface);
1194 surface->checked_pending = true;
1195 app_id = weston_desktop_surface_get_app_id(surface->dsurface);
1197 shell_send_app_state(ivi, app_id, AGL_SHELL_APP_STATE_STARTED);
1202 shell_set_background(struct wl_client *client,
1203 struct wl_resource *shell_res,
1204 struct wl_resource *surface_res,
1205 struct wl_resource *output_res)
1207 struct weston_head *head = weston_head_from_resource(output_res);
1208 struct weston_output *woutput = weston_head_get_output(head);
1209 struct ivi_output *output = to_ivi_output(woutput);
1210 struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1211 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1212 struct weston_desktop_surface *dsurface;
1213 struct ivi_surface *surface;
1215 if ((wl_resource_get_version(shell_res) >=
1216 AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1217 ivi->shell_client.status == BOUND_FAILED) ||
1218 ivi->shell_client.resource_ext == shell_res) {
1219 wl_resource_post_error(shell_res,
1220 WL_DISPLAY_ERROR_INVALID_OBJECT,
1221 "agl_shell (set_background) has already "
1222 "been bound. Check out bound_fail event");
1226 dsurface = weston_surface_get_desktop_surface(wsurface);
1228 wl_resource_post_error(shell_res,
1229 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1230 "surface must be a desktop surface");
1234 surface = weston_desktop_surface_get_user_data(dsurface);
1235 if (surface->role != IVI_SURFACE_ROLE_NONE) {
1236 wl_resource_post_error(shell_res,
1237 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1238 "surface already has another ivi role");
1242 if (output->background) {
1243 wl_resource_post_error(shell_res,
1244 AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1245 "output already has background");
1249 surface->checked_pending = true;
1250 surface->role = IVI_SURFACE_ROLE_BACKGROUND;
1251 surface->bg.output = output;
1252 wl_list_remove(&surface->link);
1253 wl_list_init(&surface->link);
1255 output->background = surface;
1257 weston_desktop_surface_set_maximized(dsurface, true);
1258 weston_desktop_surface_set_size(dsurface,
1259 output->output->width,
1260 output->output->height);
1264 shell_set_panel(struct wl_client *client,
1265 struct wl_resource *shell_res,
1266 struct wl_resource *surface_res,
1267 struct wl_resource *output_res,
1270 struct weston_head *head = weston_head_from_resource(output_res);
1271 struct weston_output *woutput = weston_head_get_output(head);
1272 struct ivi_output *output = to_ivi_output(woutput);
1273 struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1274 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1275 struct weston_desktop_surface *dsurface;
1276 struct ivi_surface *surface;
1277 struct ivi_surface **member;
1278 int32_t width = 0, height = 0;
1280 if ((wl_resource_get_version(shell_res) >=
1281 AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1282 ivi->shell_client.status == BOUND_FAILED) ||
1283 ivi->shell_client.resource_ext == shell_res) {
1284 wl_resource_post_error(shell_res,
1285 WL_DISPLAY_ERROR_INVALID_OBJECT,
1286 "agl_shell (set_panel) has already been bound. "
1287 "Check out bound_fail event");
1291 dsurface = weston_surface_get_desktop_surface(wsurface);
1293 wl_resource_post_error(shell_res,
1294 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1295 "surface must be a desktop surface");
1299 surface = weston_desktop_surface_get_user_data(dsurface);
1300 if (surface->role != IVI_SURFACE_ROLE_NONE) {
1301 wl_resource_post_error(shell_res,
1302 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1303 "surface already has another ivi role");
1308 case AGL_SHELL_EDGE_TOP:
1309 member = &output->top;
1311 case AGL_SHELL_EDGE_BOTTOM:
1312 member = &output->bottom;
1314 case AGL_SHELL_EDGE_LEFT:
1315 member = &output->left;
1317 case AGL_SHELL_EDGE_RIGHT:
1318 member = &output->right;
1321 wl_resource_post_error(shell_res,
1322 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1323 "invalid edge for panel");
1328 wl_resource_post_error(shell_res,
1329 AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1330 "output already has panel on this edge");
1334 surface->checked_pending = true;
1335 surface->role = IVI_SURFACE_ROLE_PANEL;
1336 surface->panel.output = output;
1337 surface->panel.edge = edge;
1338 wl_list_remove(&surface->link);
1339 wl_list_init(&surface->link);
1343 switch (surface->panel.edge) {
1344 case AGL_SHELL_EDGE_TOP:
1345 case AGL_SHELL_EDGE_BOTTOM:
1346 width = woutput->width;
1348 case AGL_SHELL_EDGE_LEFT:
1349 case AGL_SHELL_EDGE_RIGHT:
1350 height = woutput->height;
1354 weston_desktop_surface_set_size(dsurface, width, height);
1358 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
1359 const char *data, uint32_t app_state)
1361 struct desktop_client *dclient;
1363 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1364 struct ivi_policy *policy = ivi->policy;
1366 /* FIXME: should queue it here and see when binding agl-shell-desktop
1367 * if there are any to be sent */
1374 if (policy && policy->api.surface_advertise_state_change &&
1375 !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
1379 app_role = surf->role;
1380 if (app_role == IVI_SURFACE_ROLE_POPUP)
1381 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
1383 wl_list_for_each(dclient, &ivi->desktop_clients, link)
1384 agl_shell_desktop_send_state_app(dclient->resource, app_id,
1385 data, app_state, app_role);
1389 shell_activate_app(struct wl_client *client,
1390 struct wl_resource *shell_res,
1392 struct wl_resource *output_res)
1394 struct weston_head *head;
1395 struct weston_output *woutput;
1396 struct ivi_compositor *ivi;
1397 struct ivi_output *output;
1399 head = weston_head_from_resource(output_res);
1401 weston_log("Invalid output to activate '%s' on\n", app_id);
1405 woutput = weston_head_get_output(head);
1406 ivi = wl_resource_get_user_data(shell_res);
1407 output = to_ivi_output(woutput);
1409 if (wl_resource_get_version(shell_res) >=
1410 AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1411 ivi->shell_client.status == BOUND_FAILED) {
1412 wl_resource_post_error(shell_res,
1413 WL_DISPLAY_ERROR_INVALID_OBJECT,
1414 "agl_shell has already been bound. "
1415 "Check out bound_fail event");
1419 ivi_layout_activate(output, app_id);
1423 shell_new_deactivate_app(struct wl_client *client, struct wl_resource *shell_res,
1426 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1428 ivi_layout_deactivate(ivi, app_id);
1432 shell_set_app_float(struct wl_client *client, struct wl_resource *shell_res,
1433 const char *app_id, int32_t x_pos, int32_t y_pos)
1435 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1436 struct weston_output *output = get_focused_output(ivi->compositor);
1437 struct ivi_output *ivi_output;
1438 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1441 output = get_default_output(ivi->compositor);
1443 ivi_output = to_ivi_output(output);
1445 /* verify if already mapped as desktop role, regular, unmap it, so we
1446 * can make it float */
1447 if (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1448 struct weston_view *ev = surf->view;
1449 struct weston_desktop_surface *dsurf = surf->dsurface;
1450 struct ivi_bounding_box bb = {};
1451 const char *prev_activate_app_id = NULL;
1453 /* XXX: if this is useful we could bring it as active then make
1454 * it float, but avoid doing it for the moment */
1455 if (surf != ivi_output->active)
1458 if (ivi_output->previous_active)
1459 prev_activate_app_id =
1460 weston_desktop_surface_get_app_id(ivi_output->previous_active->dsurface);
1462 /* only deactivate if previous_active is different, otherwise
1463 * this will blow up, because we're trying to activate the same
1464 * app_id as the this one! */
1465 if (prev_activate_app_id && strcmp(app_id, prev_activate_app_id)) {
1466 ivi_layout_deactivate(ivi, app_id);
1467 } else if (prev_activate_app_id) {
1468 weston_layer_entry_remove(&ev->layer_link);
1469 weston_view_geometry_dirty(ev);
1470 weston_surface_damage(ev->surface);
1473 surf->hidden_layer_output = ivi_output;
1475 /* set attributes */
1476 surf->popup.output = ivi_output;
1478 surf->popup.x = x_pos;
1479 surf->popup.y = y_pos;
1480 surf->popup.bb = bb;
1483 /* change the role */
1484 surf->role = IVI_SURFACE_ROLE_NONE;
1486 wl_list_remove(&surf->link);
1487 wl_list_init(&surf->link);
1489 ivi_set_desktop_surface_popup(surf);
1491 weston_desktop_surface_set_maximized(dsurf, false);
1492 weston_desktop_surface_set_size(dsurf, 0, 0);
1494 /* add to hidden layer */
1495 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
1496 weston_compositor_schedule_repaint(ivi->compositor);
1498 } else if (!surf || (surf && surf->role != IVI_SURFACE_ROLE_POPUP)) {
1499 ivi_set_pending_desktop_surface_popup(ivi_output, x_pos, y_pos,
1500 0, 0, 0, 0, app_id);
1505 shell_set_app_fullscreen(struct wl_client *client,
1506 struct wl_resource *shell_res, const char *app_id)
1508 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1509 struct weston_output *output = get_focused_output(ivi->compositor);
1510 struct ivi_output *ivi_output;
1511 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1514 output = get_default_output(ivi->compositor);
1516 ivi_output = to_ivi_output(output);
1518 if (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP) {
1519 struct weston_view *ev = surf->view;
1520 struct weston_desktop_surface *dsurf = surf->dsurface;
1522 if (surf != ivi_output->active)
1525 weston_layer_entry_remove(&surf->view->layer_link);
1526 weston_view_geometry_dirty(surf->view);
1527 weston_surface_damage(surf->view->surface);
1529 surf->hidden_layer_output = ivi_output;
1531 /* set attributes */
1532 surf->fullscreen.output = ivi_output;
1534 /* change the role */
1535 surf->role = IVI_SURFACE_ROLE_NONE;
1537 wl_list_remove(&surf->link);
1538 wl_list_init(&surf->link);
1540 ivi_set_desktop_surface_fullscreen(surf);
1542 weston_desktop_surface_set_maximized(dsurf, false);
1543 weston_desktop_surface_set_fullscreen(dsurf, true);
1544 weston_desktop_surface_set_size(dsurf,
1545 ivi_output->output->width,
1546 ivi_output->output->height);
1548 /* add to hidden layer */
1549 weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link);
1550 weston_compositor_schedule_repaint(ivi->compositor);
1551 } else if (!surf || (surf && surf->role != IVI_SURFACE_ROLE_FULLSCREEN)) {
1552 ivi_set_pending_desktop_surface_fullscreen(ivi_output, app_id);
1558 shell_set_app_normal(struct wl_client *client, struct wl_resource *shell_res,
1561 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1562 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1563 struct weston_output *output = get_focused_output(ivi->compositor);
1564 struct ivi_output *ivi_output;
1565 struct weston_desktop_surface *dsurf;
1566 struct weston_geometry area = {};
1569 if (!surf || (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP))
1573 output = get_default_output(ivi->compositor);
1575 dsurf = surf->dsurface;
1576 ivi_output = to_ivi_output(output);
1578 weston_layer_entry_remove(&surf->view->layer_link);
1579 weston_view_geometry_dirty(surf->view);
1580 weston_surface_damage(surf->view->surface);
1582 /* change the role */
1583 surf->role = IVI_SURFACE_ROLE_NONE;
1584 surf->state = NORMAL;
1585 surf->desktop.pending_output = ivi_output;
1587 wl_list_remove(&surf->link);
1588 wl_list_init(&surf->link);
1590 ivi_set_desktop_surface(surf);
1592 if (ivi_output->area_activation.width ||
1593 ivi_output->area_activation.height)
1594 area = ivi_output->area_activation;
1596 area = ivi_output->area;
1598 if (weston_desktop_surface_get_fullscreen(dsurf))
1599 weston_desktop_surface_set_fullscreen(dsurf, false);
1601 weston_desktop_surface_set_maximized(dsurf, true);
1602 weston_desktop_surface_set_size(dsurf, area.width, area.height);
1604 /* add to hidden layer */
1605 weston_layer_entry_insert(&ivi->hidden.view_list,
1606 &surf->view->layer_link);
1607 weston_compositor_schedule_repaint(ivi->compositor);
1612 shell_desktop_activate_app(struct wl_client *client,
1613 struct wl_resource *shell_res,
1614 const char *app_id, const char *data,
1615 struct wl_resource *output_res)
1617 struct weston_head *head = weston_head_from_resource(output_res);
1618 struct weston_output *woutput = weston_head_get_output(head);
1619 struct ivi_output *output = to_ivi_output(woutput);
1621 ivi_layout_activate(output, app_id);
1622 shell_advertise_app_state(output->ivi, app_id,
1623 data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
1627 shell_deactivate_app(struct wl_client *client,
1628 struct wl_resource *shell_res,
1631 struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1632 struct ivi_compositor *ivi = dclient->ivi;
1634 ivi_layout_deactivate(ivi, app_id);
1635 shell_advertise_app_state(ivi, app_id,
1636 NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
1640 shell_destroy(struct wl_client *client, struct wl_resource *res)
1642 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1644 /* reset status in case bind_fail was sent */
1645 if (wl_resource_get_version(res) >= AGL_SHELL_BOUND_OK_SINCE_VERSION &&
1646 ivi->shell_client.status == BOUND_FAILED)
1647 ivi->shell_client.status = BOUND_OK;
1651 shell_set_activate_region(struct wl_client *client, struct wl_resource *res,
1652 struct wl_resource *output, int x, int y,
1653 int width, int height)
1655 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1656 struct weston_head *head = weston_head_from_resource(output);
1657 struct weston_output *woutput = weston_head_get_output(head);
1658 struct ivi_output *ioutput = to_ivi_output(woutput);
1660 struct weston_geometry area = { .x = x, .y = y,
1663 if (ivi->shell_client.ready)
1666 ioutput->area_activation = area;
1670 shell_set_app_output(struct wl_client *client, struct wl_resource *res,
1671 const char *app_id, struct wl_resource *output)
1673 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1674 struct weston_head *head = weston_head_from_resource(output);
1675 struct weston_output *woutput = weston_head_get_output(head);
1676 struct ivi_output *ioutput = to_ivi_output(woutput);
1677 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1678 struct ivi_output *desktop_last_output;
1679 struct ivi_output *current_completed_output;
1681 if (!app_id || !ioutput)
1684 /* handle the case we're not mapped at all */
1686 ivi_set_pending_desktop_surface_remote(ioutput, app_id);
1687 shell_send_app_on_output(ivi, app_id, woutput->name);
1691 desktop_last_output = surf->desktop.last_output;
1692 current_completed_output = surf->current_completed_output;
1694 if (surf->remote.output)
1695 surf->hidden_layer_output = surf->remote.output;
1697 surf->hidden_layer_output = desktop_last_output;
1698 assert(surf->hidden_layer_output);
1700 if (ivi_surface_count_one(current_completed_output, IVI_SURFACE_ROLE_REMOTE) ||
1701 ivi_surface_count_one(current_completed_output, IVI_SURFACE_ROLE_DESKTOP)) {
1702 if (!current_completed_output->background)
1703 insert_black_curtain(current_completed_output);
1705 ivi_layout_deactivate(ivi, app_id);
1708 /* update the remote output */
1709 surf->remote.output = ioutput;
1711 if (surf->role != IVI_SURFACE_ROLE_REMOTE) {
1712 wl_list_remove(&surf->link);
1713 wl_list_init(&surf->link);
1715 surf->role = IVI_SURFACE_ROLE_NONE;
1716 ivi_set_desktop_surface_remote(surf);
1719 shell_send_app_on_output(ivi, app_id, woutput->name);
1723 shell_set_app_position(struct wl_client *client, struct wl_resource *res,
1724 const char *app_id, int32_t x, int32_t y)
1726 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1727 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1729 if (!surf || !app_id || surf->role != IVI_SURFACE_ROLE_POPUP)
1732 weston_view_set_position(surf->view, x, y);
1733 weston_compositor_schedule_repaint(ivi->compositor);
1737 shell_set_app_scale(struct wl_client *client, struct wl_resource *res,
1738 const char *app_id, int32_t width, int32_t height)
1741 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1742 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1744 if (!surf || !app_id || surf->role != IVI_SURFACE_ROLE_POPUP)
1747 weston_desktop_surface_set_size(surf->dsurface, width, height);
1748 weston_compositor_schedule_repaint(ivi->compositor);
1752 _ivi_set_pending_desktop_surface_split(struct wl_resource *output,
1753 const char *app_id, uint32_t orientation)
1755 weston_log("%s() added split surface for app_id '%s' with "
1756 "orientation %d to pending\n", __func__, app_id, orientation);
1758 struct weston_head *head = weston_head_from_resource(output);
1759 struct weston_output *woutput = weston_head_get_output(head);
1760 struct ivi_output *ivi_output = to_ivi_output(woutput);
1762 struct pending_app_tile *app_tile = zalloc(sizeof(*app_tile));
1764 app_tile->base.app_id = strdup(app_id);
1765 app_tile->base.ioutput = ivi_output;
1766 app_tile->base.role = IVI_SURFACE_ROLE_TILE;
1768 app_tile->orientation = orientation;
1769 wl_list_insert(&ivi_output->ivi->pending_apps, &app_tile->base.link);
1774 reverse_orientation(uint32_t orientation)
1777 switch (orientation) {
1778 case AGL_SHELL_TILE_ORIENTATION_LEFT:
1779 return AGL_SHELL_TILE_ORIENTATION_RIGHT;
1781 case AGL_SHELL_TILE_ORIENTATION_RIGHT:
1782 return AGL_SHELL_TILE_ORIENTATION_LEFT;
1784 case AGL_SHELL_TILE_ORIENTATION_TOP:
1785 return AGL_SHELL_TILE_ORIENTATION_BOTTOM;
1787 case AGL_SHELL_TILE_ORIENTATION_BOTTOM:
1788 return AGL_SHELL_TILE_ORIENTATION_TOP;
1791 return AGL_SHELL_TILE_ORIENTATION_NONE;
1796 _ivi_set_shell_surface_split(struct ivi_surface *surface, struct ivi_output *ioutput,
1797 uint32_t orientation, bool to_activate)
1799 struct ivi_compositor *ivi = surface->ivi;
1800 struct weston_geometry geom = {};
1801 struct ivi_output *output = NULL;
1806 geom = weston_desktop_surface_get_geometry(surface->dsurface);
1807 output = ivi_layout_get_output_from_surface(surface);
1812 width = output->area.width;
1813 height = output->area.height;
1815 switch (orientation) {
1816 case AGL_SHELL_TILE_ORIENTATION_LEFT:
1817 case AGL_SHELL_TILE_ORIENTATION_RIGHT:
1820 case AGL_SHELL_TILE_ORIENTATION_TOP:
1821 case AGL_SHELL_TILE_ORIENTATION_BOTTOM:
1824 case AGL_SHELL_TILE_ORIENTATION_NONE:
1828 assert(!"Invalid orientation passed");
1832 x = output->area.x - geom.x;
1833 y = output->area.y - geom.y;
1835 if (orientation == AGL_SHELL_TILE_ORIENTATION_RIGHT)
1837 else if (orientation == AGL_SHELL_TILE_ORIENTATION_BOTTOM)
1841 struct weston_view *ev = surface->view;
1842 struct ivi_shell_seat *ivi_seat = NULL;
1843 struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi);
1846 ivi_seat = get_ivi_shell_seat(wseat);
1848 if (!weston_view_is_mapped(ev))
1849 weston_view_update_transform(ev);
1851 weston_layer_entry_remove(&ev->layer_link);
1854 // mark view as mapped
1855 ev->is_mapped = true;
1856 ev->surface->is_mapped = true;
1857 surface->mapped = true;
1859 // update older/new active surface
1860 output->previous_active = output->active;
1861 output->active = surface;
1863 // add to the layer and inflict damage
1864 weston_view_set_output(ev, output->output);
1865 weston_layer_entry_insert(&ivi->normal.view_list, &ev->layer_link);
1866 weston_view_geometry_dirty(ev);
1867 weston_surface_damage(ev->surface);
1869 // handle input / keyboard
1871 ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE);
1874 weston_view_set_position(surface->view, x, y);
1875 weston_desktop_surface_set_size(surface->dsurface, width, height);
1876 weston_desktop_surface_set_orientation(surface->dsurface, orientation);
1877 surface->orientation = orientation;
1879 weston_compositor_schedule_repaint(ivi->compositor);
1881 weston_log("%s() Setting to x=%d, y=%d, width=%d, height=%d, orientation=%d\n",
1882 __func__, x, y, width, height, orientation);
1887 shell_ivi_surf_count_split_surfaces(struct ivi_compositor *ivi)
1890 struct ivi_surface *surf;
1892 wl_list_for_each(surf, &ivi->surfaces, link) {
1893 if (surf->orientation > AGL_SHELL_TILE_ORIENTATION_NONE)
1902 void shell_set_app_split(struct wl_client *client, struct wl_resource *res,
1903 const char *app_id, uint32_t orientation,
1904 struct wl_resource *output_res)
1906 struct ivi_surface *surf;
1907 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1909 struct weston_head *head = weston_head_from_resource(output_res);
1910 struct weston_output *woutput = weston_head_get_output(head);
1911 struct ivi_output *output = to_ivi_output(woutput);
1916 if (shell_ivi_surf_count_split_surfaces(ivi) > 2) {
1917 weston_log("Found more than two split surfaces in tile orientation.\n");
1921 /* add it as pending until */
1922 surf = ivi_find_app(ivi, app_id);
1924 _ivi_set_pending_desktop_surface_split(output_res, app_id, orientation);
1928 /* otherwise, take actions now */
1929 weston_log("%s() added split surface for app_id '%s' with orientation %d\n",
1930 __func__, app_id, orientation);
1932 if (output->previous_active) {
1933 struct weston_view *ev = output->previous_active->view;
1935 if (!weston_view_is_mapped(ev))
1936 weston_view_update_transform(ev);
1938 weston_layer_entry_remove(&ev->layer_link);
1940 ev->is_mapped = true;
1941 ev->surface->is_mapped = true;
1942 output->previous_active->mapped = true;
1944 weston_view_set_output(ev, woutput);
1946 weston_layer_entry_insert(&ivi->normal.view_list, &ev->layer_link);
1948 _ivi_set_shell_surface_split(output->previous_active, NULL,
1949 reverse_orientation(orientation), false);
1951 if (orientation == AGL_SHELL_TILE_ORIENTATION_NONE &&
1952 output->active == surf) {
1953 output->active = output->previous_active;
1957 _ivi_set_shell_surface_split(surf, NULL, orientation, false);
1961 shell_ext_destroy(struct wl_client *client, struct wl_resource *res)
1963 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1965 ivi->shell_client_ext.doas_requested = false;
1966 wl_resource_destroy(res);
1970 shell_ext_doas(struct wl_client *client, struct wl_resource *res)
1972 struct ivi_compositor *ivi = wl_resource_get_user_data(res);
1974 ivi->shell_client_ext.doas_requested = true;
1976 if (ivi->shell_client_ext.resource && ivi->shell_client.resource) {
1977 ivi->shell_client_ext.doas_requested_pending_bind = true;
1979 agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource,
1980 AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS);
1982 agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource,
1983 AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_FAILED);
1988 static const struct agl_shell_interface agl_shell_implementation = {
1989 .ready = shell_ready,
1990 .set_background = shell_set_background,
1991 .set_panel = shell_set_panel,
1992 .activate_app = shell_activate_app,
1993 .destroy = shell_destroy,
1994 .set_activate_region = shell_set_activate_region,
1995 .deactivate_app = shell_new_deactivate_app,
1996 .set_app_float = shell_set_app_float,
1997 .set_app_normal = shell_set_app_normal,
1998 .set_app_fullscreen = shell_set_app_fullscreen,
1999 .set_app_output = shell_set_app_output,
2000 .set_app_position = shell_set_app_position,
2001 .set_app_scale = shell_set_app_scale,
2002 .set_app_split = shell_set_app_split,
2005 static const struct agl_shell_ext_interface agl_shell_ext_implementation = {
2006 .destroy = shell_ext_destroy,
2007 .doas_shell_client = shell_ext_doas,
2011 shell_desktop_set_app_property(struct wl_client *client,
2012 struct wl_resource *shell_res,
2013 const char *app_id, uint32_t role,
2014 int x, int y, int bx, int by,
2015 int width, int height,
2016 struct wl_resource *output_res)
2018 struct weston_head *head = weston_head_from_resource(output_res);
2019 struct weston_output *woutput = weston_head_get_output(head);
2020 struct ivi_output *output = to_ivi_output(woutput);
2023 case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
2024 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
2025 width, height, app_id);
2027 case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
2028 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
2030 case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
2031 case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
2032 ivi_set_pending_desktop_surface_split(output, app_id, role);
2034 case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
2035 ivi_set_pending_desktop_surface_remote(output, app_id);
2043 ivi_compositor_destroy_pending_surfaces(struct ivi_compositor *ivi)
2045 struct pending_popup *p_popup, *next_p_popup;
2046 struct pending_split *split_surf, *next_split_surf;
2047 struct pending_fullscreen *fs_surf, *next_fs_surf;
2048 struct pending_remote *remote_surf, *next_remote_surf;
2050 wl_list_for_each_safe(p_popup, next_p_popup,
2051 &ivi->popup_pending_apps, link)
2052 ivi_remove_pending_desktop_surface_popup(p_popup);
2054 wl_list_for_each_safe(split_surf, next_split_surf,
2055 &ivi->split_pending_apps, link)
2056 ivi_remove_pending_desktop_surface_split(split_surf);
2058 wl_list_for_each_safe(fs_surf, next_fs_surf,
2059 &ivi->fullscreen_pending_apps, link)
2060 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
2062 wl_list_for_each_safe(remote_surf, next_remote_surf,
2063 &ivi->remote_pending_apps, link)
2064 ivi_remove_pending_desktop_surface_remote(remote_surf);
2068 shell_desktop_set_app_property_mode(struct wl_client *client,
2069 struct wl_resource *shell_res, uint32_t perm)
2071 struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
2073 dclient->ivi->keep_pending_surfaces = true;
2075 dclient->ivi->keep_pending_surfaces = false;
2076 /* remove any previous pending surfaces */
2077 ivi_compositor_destroy_pending_surfaces(dclient->ivi);
2081 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
2082 .activate_app = shell_desktop_activate_app,
2083 .set_app_property = shell_desktop_set_app_property,
2084 .deactivate_app = shell_deactivate_app,
2085 .set_app_property_mode = shell_desktop_set_app_property_mode,
2089 unbind_agl_shell(struct wl_resource *resource)
2091 struct ivi_compositor *ivi;
2092 struct ivi_output *output;
2093 struct ivi_surface *surf, *surf_tmp;
2095 ivi = wl_resource_get_user_data(resource);
2097 /* reset status to allow other clients issue legit requests */
2098 if (wl_resource_get_version(resource) >=
2099 AGL_SHELL_BOUND_OK_SINCE_VERSION &&
2100 ivi->shell_client.status == BOUND_FAILED) {
2101 ivi->shell_client.status = BOUND_OK;
2105 wl_list_for_each(output, &ivi->outputs, link) {
2107 /* reset the active surf if there's one present */
2108 if (output->active) {
2109 struct weston_geometry area = {};
2111 output->active->view->is_mapped = false;
2112 output->active->view->surface->is_mapped = false;
2114 weston_layer_entry_remove(&output->active->view->layer_link);
2115 output->active = NULL;
2117 output->area_activation = area;
2120 insert_black_curtain(output);
2123 wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
2124 wl_list_remove(&surf->link);
2125 wl_list_init(&surf->link);
2128 wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
2129 wl_list_remove(&surf->link);
2130 wl_list_init(&surf->link);
2133 wl_list_init(&ivi->surfaces);
2134 wl_list_init(&ivi->pending_surfaces);
2136 ivi->shell_client.ready = false;
2137 ivi->shell_client.resource = NULL;
2138 ivi->shell_client.resource_ext = NULL;
2139 ivi->shell_client.client = NULL;
2143 unbind_agl_shell_ext(struct wl_resource *resource)
2145 struct ivi_compositor *ivi = wl_resource_get_user_data(resource);
2147 ivi->shell_client_ext.resource = NULL;
2148 ivi->shell_client.resource_ext = NULL;
2149 ivi->shell_client_ext.doas_requested = false;
2153 bind_agl_shell(struct wl_client *client,
2154 void *data, uint32_t version, uint32_t id)
2156 struct ivi_compositor *ivi = data;
2157 struct wl_resource *resource;
2158 struct ivi_policy *policy;
2161 policy = ivi->policy;
2162 interface = (void *) &agl_shell_interface;
2163 if (policy && policy->api.shell_bind_interface &&
2164 !policy->api.shell_bind_interface(client, interface)) {
2165 wl_client_post_implementation_error(client,
2166 "client not authorized to use agl_shell");
2170 resource = wl_resource_create(client, &agl_shell_interface, version, id);
2172 wl_client_post_no_memory(client);
2176 if (ivi->shell_client.resource && wl_resource_get_version(resource) == 1) {
2177 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2178 "agl_shell has already been bound (version 1)");
2179 wl_resource_destroy(resource);
2183 // for agl_shell client proxy
2184 if (ivi->shell_client.resource &&
2185 ivi->shell_client_ext.doas_requested_pending_bind) {
2187 ivi->shell_client_ext.doas_requested_pending_bind = false;
2189 // if there's one connected
2190 if (ivi->shell_client.resource_ext) {
2191 ivi->shell_client_ext.status = BOUND_FAILED;
2192 agl_shell_send_bound_fail(ivi->shell_client.resource_ext);
2193 wl_resource_destroy(resource);
2197 wl_resource_set_implementation(resource, &agl_shell_implementation,
2199 ivi->shell_client.resource_ext = resource;
2200 ivi->shell_client_ext.status = BOUND_OK;
2201 agl_shell_send_bound_ok(ivi->shell_client.resource_ext);
2206 // if we already have an agl_shell client
2207 if (ivi->shell_client.resource) {
2208 agl_shell_send_bound_fail(resource);
2209 ivi->shell_client.status = BOUND_FAILED;
2210 wl_resource_destroy(resource);
2214 // default agl_shell client
2215 wl_resource_set_implementation(resource, &agl_shell_implementation,
2216 ivi, unbind_agl_shell);
2217 ivi->shell_client.resource = resource;
2219 if (wl_resource_get_version(resource) >=
2220 AGL_SHELL_BOUND_OK_SINCE_VERSION) {
2221 /* if we land here we'll have BOUND_OK by default,
2222 but still do the assignment */
2223 ivi->shell_client.status = BOUND_OK;
2224 agl_shell_send_bound_ok(ivi->shell_client.resource);
2229 bind_agl_shell_ext(struct wl_client *client,
2230 void *data, uint32_t version, uint32_t id)
2232 struct ivi_compositor *ivi = data;
2233 struct wl_resource *resource;
2235 resource = wl_resource_create(client, &agl_shell_ext_interface, version, id);
2237 wl_client_post_no_memory(client);
2241 if (ivi->shell_client_ext.resource) {
2242 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2243 "agl_shell_ext has already been bound");
2247 wl_resource_set_implementation(resource, &agl_shell_ext_implementation,
2248 ivi, unbind_agl_shell_ext);
2249 ivi->shell_client_ext.resource = resource;
2253 unbind_agl_shell_desktop(struct wl_resource *resource)
2255 struct desktop_client *dclient = wl_resource_get_user_data(resource);
2257 wl_list_remove(&dclient->link);
2262 bind_agl_shell_desktop(struct wl_client *client,
2263 void *data, uint32_t version, uint32_t id)
2265 struct ivi_compositor *ivi = data;
2266 struct wl_resource *resource;
2267 struct ivi_policy *policy;
2268 struct desktop_client *dclient;
2271 policy = ivi->policy;
2272 interface = (void *) &agl_shell_desktop_interface;
2273 if (policy && policy->api.shell_bind_interface &&
2274 !policy->api.shell_bind_interface(client, interface)) {
2275 wl_client_post_implementation_error(client,
2276 "client not authorized to use agl_shell_desktop");
2280 dclient = zalloc(sizeof(*dclient));
2282 wl_client_post_no_memory(client);
2286 resource = wl_resource_create(client, &agl_shell_desktop_interface,
2290 wl_client_post_no_memory(client);
2294 wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
2295 dclient, unbind_agl_shell_desktop);
2297 dclient->resource = resource;
2298 wl_list_insert(&ivi->desktop_clients, &dclient->link);
2300 /* advertise xdg surfaces */
2301 ivi_shell_advertise_xdg_surfaces(ivi, resource);
2305 ivi_shell_create_global(struct ivi_compositor *ivi)
2307 ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
2308 &agl_shell_interface, 11,
2309 ivi, bind_agl_shell);
2310 if (!ivi->agl_shell) {
2311 weston_log("Failed to create wayland global.\n");
2315 ivi->agl_shell_ext = wl_global_create(ivi->compositor->wl_display,
2316 &agl_shell_ext_interface, 1,
2317 ivi, bind_agl_shell_ext);
2318 if (!ivi->agl_shell_ext) {
2319 weston_log("Failed to create agl_shell_ext global.\n");
2323 ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
2324 &agl_shell_desktop_interface, 2,
2325 ivi, bind_agl_shell_desktop);
2326 if (!ivi->agl_shell_desktop) {
2327 weston_log("Failed to create wayland global (agl_shell_desktop).\n");