2 * Copyright © 2019 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>
37 #include <libweston/libweston.h>
38 #include <libweston/config-parser.h>
40 #include "shared/os-compatibility.h"
42 #include "agl-shell-server-protocol.h"
43 #include "agl-shell-desktop-server-protocol.h"
46 #include <waltham-transmitter/transmitter_api.h>
50 create_black_surface_view(struct ivi_output *output);
52 static struct ivi_surface *
53 get_ivi_shell_surface(struct weston_surface *wsurface)
55 if (weston_surface_is_desktop_surface(wsurface)) {
56 struct weston_desktop_surface *dsurface =
57 weston_surface_get_desktop_surface(wsurface);
58 return weston_desktop_surface_get_user_data(dsurface);
65 agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi,
66 struct ivi_surface *surface)
68 struct desktop_client *dclient;
69 static bool display_adv = false;
71 if (surface->advertised_on_launch)
74 /* advertise to all desktop clients the new surface */
75 wl_list_for_each(dclient, &ivi->desktop_clients, link) {
77 weston_desktop_surface_get_app_id(surface->dsurface);
80 weston_log("WARNING app_is is null, unable to advertise\n");
85 agl_shell_desktop_send_application(dclient->resource, app_id);
86 surface->advertised_on_launch = true;
91 ivi_set_desktop_surface(struct ivi_surface *surface)
93 struct ivi_compositor *ivi = surface->ivi;
94 assert(surface->role == IVI_SURFACE_ROLE_NONE);
96 surface->role = IVI_SURFACE_ROLE_DESKTOP;
97 wl_list_insert(&surface->ivi->surfaces, &surface->link);
99 agl_shell_desktop_advertise_application_id(ivi, surface);
103 ivi_set_desktop_surface_popup(struct ivi_surface *surface)
105 struct ivi_compositor *ivi = surface->ivi;
106 assert(surface->role == IVI_SURFACE_ROLE_NONE);
108 surface->role = IVI_SURFACE_ROLE_POPUP;
109 wl_list_insert(&ivi->surfaces, &surface->link);
111 agl_shell_desktop_advertise_application_id(ivi, surface);
115 ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface)
117 struct ivi_compositor *ivi = surface->ivi;
118 assert(surface->role == IVI_SURFACE_ROLE_NONE);
120 surface->role = IVI_SURFACE_ROLE_FULLSCREEN;
121 wl_list_insert(&ivi->surfaces, &surface->link);
123 agl_shell_desktop_advertise_application_id(ivi, surface);
128 ivi_destroy_waltham_destroy(struct ivi_surface *surface)
130 struct ivi_compositor *ivi = surface->ivi;
131 const struct weston_transmitter_api *api =
132 ivi->waltham_transmitter_api;
137 if (surface->waltham_surface.transmitter_surface)
138 api->surface_destroy(surface->waltham_surface.transmitter_surface);
142 ivi_output_notify_waltham_plugin(struct ivi_surface *surface)
144 struct ivi_compositor *ivi = surface->ivi;
145 const struct weston_transmitter_api *api = ivi->waltham_transmitter_api;
146 struct weston_transmitter *transmitter;
147 struct weston_transmitter_remote *trans_remote;
148 struct weston_surface *weston_surface;
149 struct weston_output *woutput = surface->remote.output->output;
155 transmitter = api->transmitter_get(ivi->compositor);
159 trans_remote = api->get_transmitter_remote(woutput->name, transmitter);
161 weston_log("Could not find a valie weston_transmitter_remote "
162 "that matches the output %s\n", woutput->name);
166 app_id = weston_desktop_surface_get_app_id(surface->dsurface);
168 weston_desktop_surface_get_surface(surface->dsurface);
170 weston_log("Forwarding app_id %s to remote %s\n", app_id, woutput->name);
172 /* this will have the effect of informing the remote side to create a
173 * surface with the name app_id. W/ xdg-shell the following happens:
175 * compositor (server):
176 * surface_push_to_remote():
177 * waltham-transmitter plug-in
178 * -> wthp_ivi_app_id_surface_create()
180 * client -- on the receiver side:
181 * -> wthp_ivi_app_id_surface_create()
182 * -> wth_receiver_weston_main()
183 * -> wl_compositor_create_surface()
184 * -> xdg_wm_base_get_xdg_surface
185 * -> xdg_toplevel_set_app_id()
187 * -> gst_parse_launch()
189 * wth_receiver_weston_main() will be invoked from the handler of
190 * wthp_ivi_app_id_surface_create() and is responsible for setting-up
191 * the gstreamer pipeline as well.
193 surface->waltham_surface.transmitter_surface =
194 api->surface_push_to_remote(weston_surface, app_id, trans_remote, NULL);
199 ivi_destroy_waltham_destroy(struct ivi_surface *surface)
203 ivi_output_notify_waltham_plugin(struct ivi_surface *surface)
209 ivi_set_desktop_surface_remote(struct ivi_surface *surface)
211 struct ivi_compositor *ivi = surface->ivi;
212 struct weston_view *view;
213 struct ivi_output *output = surface->remote.output;
215 assert(surface->role == IVI_SURFACE_ROLE_NONE);
217 /* remote type are the same as desktop just that client can tell
218 * the compositor to start on another output */
219 surface->role = IVI_SURFACE_ROLE_REMOTE;
221 /* if thew black surface view is mapped on the mean we need
222 * to remove it in order to start showing the 'remote' surface
223 * just being added */
224 view = output->fullscreen_view.fs->view;
225 if (view->is_mapped || view->surface->is_mapped)
226 remove_black_surface(output);
228 if (output->type == OUTPUT_WALTHAM)
229 ivi_output_notify_waltham_plugin(surface);
231 wl_list_insert(&ivi->surfaces, &surface->link);
236 ivi_set_desktop_surface_split(struct ivi_surface *surface)
238 struct ivi_compositor *ivi = surface->ivi;
239 assert(surface->role == IVI_SURFACE_ROLE_NONE);
241 if (surface->split.orientation == AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL)
242 surface->role = IVI_SURFACE_ROLE_SPLIT_V;
244 surface->role = IVI_SURFACE_ROLE_SPLIT_H;
246 wl_list_insert(&ivi->surfaces, &surface->link);
248 agl_shell_desktop_advertise_application_id(ivi, surface);
251 static struct pending_popup *
252 ivi_ensure_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
253 int width, int height, const char *app_id)
255 struct pending_popup *p_popup = zalloc(sizeof(*p_popup));
256 size_t len_app_id = strlen(app_id);
260 p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
261 if (!p_popup->app_id) {
265 memcpy(p_popup->app_id, app_id, len_app_id);
266 p_popup->ioutput = ioutput;
272 p_popup->bb.width = width;
273 p_popup->bb.height = height;
279 ivi_update_popup(struct ivi_output *ioutput, int x, int y, int bx, int by,
280 int width, int height, const char *app_id, struct pending_popup *p_popup)
282 size_t len_app_id = strlen(app_id);
284 wl_list_remove(&p_popup->link);
285 wl_list_init(&p_popup->link);
287 memset(p_popup->app_id, 0, strlen(app_id) + 1);
288 free(p_popup->app_id);
290 p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1));
291 if (!p_popup->app_id)
293 memcpy(p_popup->app_id, app_id, len_app_id);
295 p_popup->ioutput = ioutput;
301 p_popup->bb.width = width;
302 p_popup->bb.height = height;
305 static struct pending_fullscreen *
306 ivi_ensure_fullscreen(struct ivi_output *ioutput, const char *app_id)
308 struct pending_fullscreen *p_fullscreen = zalloc(sizeof(*p_fullscreen));
309 size_t len_app_id = strlen(app_id);
313 p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
314 if (!p_fullscreen->app_id) {
318 memcpy(p_fullscreen->app_id, app_id, len_app_id);
320 p_fullscreen->ioutput = ioutput;
325 ivi_update_fullscreen(struct ivi_output *ioutput, const char *app_id,
326 struct pending_fullscreen *p_fullscreen)
328 size_t len_app_id = strlen(app_id);
330 wl_list_remove(&p_fullscreen->link);
331 wl_list_init(&p_fullscreen->link);
333 memset(p_fullscreen->app_id, 0, strlen(app_id) + 1);
334 free(p_fullscreen->app_id);
336 p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1));
337 if (!p_fullscreen->app_id)
339 memcpy(p_fullscreen->app_id, app_id, len_app_id);
341 p_fullscreen->ioutput = ioutput;
344 static struct pending_remote *
345 ivi_ensure_remote(struct ivi_output *ioutput, const char *app_id)
347 struct pending_remote *p_remote = zalloc(sizeof(*p_remote));
348 size_t len_app_id = strlen(app_id);
352 p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
353 if (!p_remote->app_id) {
357 memcpy(p_remote->app_id, app_id, len_app_id);
359 p_remote->ioutput = ioutput;
364 ivi_update_remote(struct ivi_output *ioutput, const char *app_id,
365 struct pending_remote *p_remote)
367 size_t len_app_id = strlen(app_id);
369 wl_list_remove(&p_remote->link);
370 wl_list_init(&p_remote->link);
372 memset(p_remote->app_id, 0, strlen(app_id) + 1);
373 free(p_remote->app_id);
375 p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1));
376 if (!p_remote->app_id)
378 memcpy(p_remote->app_id, app_id, len_app_id);
380 p_remote->ioutput = ioutput;
384 ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput, int x, int y, int bx,
385 int by, int width, int height, const char *app_id)
387 struct ivi_compositor *ivi = ioutput->ivi;
388 struct pending_popup *p_popup = NULL;
389 struct pending_popup *popup;
391 wl_list_for_each(popup, &ivi->popup_pending_apps, link)
392 if (!strcmp(app_id, popup->app_id))
396 p_popup = ivi_ensure_popup(ioutput, x, y, bx, by, width, height, app_id);
398 ivi_update_popup(ioutput, x, y, bx, by, width, height, app_id, p_popup);
402 wl_list_insert(&ivi->popup_pending_apps, &p_popup->link);
406 ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput,
409 struct ivi_compositor *ivi = ioutput->ivi;
410 struct pending_fullscreen *p_fullscreen = NULL;
411 struct pending_fullscreen *fullscreen;
413 wl_list_for_each(fullscreen, &ivi->fullscreen_pending_apps, link)
414 if (!strcmp(app_id, fullscreen->app_id))
415 p_fullscreen = fullscreen;
418 p_fullscreen = ivi_ensure_fullscreen(ioutput, app_id);
420 ivi_update_fullscreen(ioutput, app_id, p_fullscreen);
424 wl_list_insert(&ivi->fullscreen_pending_apps, &p_fullscreen->link);
428 ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput,
429 const char *app_id, uint32_t orientation)
431 struct ivi_compositor *ivi = ioutput->ivi;
432 struct ivi_surface *surf;
433 size_t len_app_id = strlen(app_id);
434 struct pending_split *split;
436 if (orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL &&
437 orientation != AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL)
440 /* more than one is un-supported, do note we need to do
441 * conversion for surface roles instead of using the protocol ones */
442 wl_list_for_each(surf, &ivi->surfaces, link)
443 if (surf->role == IVI_SURFACE_ROLE_SPLIT_V ||
444 surf->role == IVI_SURFACE_ROLE_SPLIT_H)
447 split = zalloc(sizeof(*split));
450 split->app_id = zalloc(sizeof(char) * (len_app_id + 1));
451 if (!split->app_id) {
455 memcpy(split->app_id, app_id, len_app_id);
457 split->ioutput = ioutput;
458 split->orientation = orientation;
460 wl_list_insert(&ivi->split_pending_apps, &split->link);
464 ivi_set_pending_desktop_surface_remote(struct ivi_output *ioutput,
467 struct ivi_compositor *ivi = ioutput->ivi;
468 struct pending_remote *remote;
469 struct pending_remote *p_remote = NULL;
471 wl_list_for_each(remote, &ivi->remote_pending_apps, link)
472 if (!strcmp(app_id, remote->app_id))
476 p_remote = ivi_ensure_remote(ioutput, app_id);
478 ivi_update_remote(ioutput, app_id, p_remote);
482 wl_list_insert(&ivi->remote_pending_apps, &remote->link);
487 ivi_remove_pending_desktop_surface_split(struct pending_split *split)
490 wl_list_remove(&split->link);
495 ivi_remove_pending_desktop_surface_fullscreen(struct pending_fullscreen *fs)
498 wl_list_remove(&fs->link);
503 ivi_remove_pending_desktop_surface_popup(struct pending_popup *p_popup)
505 free(p_popup->app_id);
506 wl_list_remove(&p_popup->link);
511 ivi_remove_pending_desktop_surface_remote(struct pending_remote *remote)
513 free(remote->app_id);
514 wl_list_remove(&remote->link);
519 ivi_compositor_keep_pending_surfaces(struct ivi_surface *surface)
521 return surface->ivi->keep_pending_surfaces;
525 ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface)
527 struct ivi_compositor *ivi = surface->ivi;
528 struct pending_popup *p_popup, *next_p_popup;
529 const char *_app_id =
530 weston_desktop_surface_get_app_id(surface->dsurface);
532 if (wl_list_empty(&ivi->popup_pending_apps) || !_app_id)
535 wl_list_for_each_safe(p_popup, next_p_popup,
536 &ivi->popup_pending_apps, link) {
537 if (!strcmp(_app_id, p_popup->app_id)) {
538 surface->popup.output = p_popup->ioutput;
539 surface->popup.x = p_popup->x;
540 surface->popup.y = p_popup->y;
542 surface->popup.bb.x = p_popup->bb.x;
543 surface->popup.bb.y = p_popup->bb.y;
544 surface->popup.bb.width = p_popup->bb.width;
545 surface->popup.bb.height = p_popup->bb.height;
547 if (!ivi_compositor_keep_pending_surfaces(surface))
548 ivi_remove_pending_desktop_surface_popup(p_popup);
557 ivi_check_pending_desktop_surface_split(struct ivi_surface *surface)
559 struct pending_split *split_surf, *next_split_surf;
560 struct ivi_compositor *ivi = surface->ivi;
561 const char *_app_id =
562 weston_desktop_surface_get_app_id(surface->dsurface);
564 if (wl_list_empty(&ivi->split_pending_apps) || !_app_id)
567 wl_list_for_each_safe(split_surf, next_split_surf,
568 &ivi->split_pending_apps, link) {
569 if (!strcmp(_app_id, split_surf->app_id)) {
570 surface->split.output = split_surf->ioutput;
571 surface->split.orientation = split_surf->orientation;
572 if (!ivi_compositor_keep_pending_surfaces(surface))
573 ivi_remove_pending_desktop_surface_split(split_surf);
582 ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface)
584 struct pending_fullscreen *fs_surf, *next_fs_surf;
585 struct ivi_compositor *ivi = surface->ivi;
586 const char *_app_id =
587 weston_desktop_surface_get_app_id(surface->dsurface);
589 if (wl_list_empty(&ivi->fullscreen_pending_apps) || !_app_id)
592 wl_list_for_each_safe(fs_surf, next_fs_surf,
593 &ivi->fullscreen_pending_apps, link) {
594 if (!strcmp(_app_id, fs_surf->app_id)) {
595 surface->fullscreen.output = fs_surf->ioutput;
596 if (!ivi_compositor_keep_pending_surfaces(surface))
597 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
606 ivi_check_pending_desktop_surface_remote(struct ivi_surface *surface)
608 struct pending_remote *remote_surf, *next_remote_surf;
609 struct ivi_compositor *ivi = surface->ivi;
610 const char *_app_id =
611 weston_desktop_surface_get_app_id(surface->dsurface);
613 if (wl_list_empty(&ivi->remote_pending_apps) || !_app_id)
616 wl_list_for_each_safe(remote_surf, next_remote_surf,
617 &ivi->remote_pending_apps, link) {
618 if (!strcmp(_app_id, remote_surf->app_id)) {
619 surface->remote.output = remote_surf->ioutput;
620 if (!ivi_compositor_keep_pending_surfaces(surface))
621 ivi_remove_pending_desktop_surface_remote(remote_surf);
629 ivi_check_pending_surface_desktop(struct ivi_surface *surface,
630 enum ivi_surface_role *role)
632 struct ivi_compositor *ivi = surface->ivi;
633 struct wl_list *role_pending_list;
634 struct pending_popup *p_popup;
635 struct pending_split *p_split;
636 struct pending_fullscreen *p_fullscreen;
637 struct pending_remote *p_remote;
639 weston_desktop_surface_get_app_id(surface->dsurface);
642 *role = IVI_SURFACE_ROLE_NONE;
646 role_pending_list = &ivi->popup_pending_apps;
647 wl_list_for_each(p_popup, role_pending_list, link) {
648 if (!strcmp(app_id, p_popup->app_id)) {
649 *role = IVI_SURFACE_ROLE_POPUP;
654 role_pending_list = &ivi->split_pending_apps;
655 wl_list_for_each(p_split, role_pending_list, link) {
656 if (!strcmp(app_id, p_split->app_id)) {
657 *role = IVI_SURFACE_ROLE_SPLIT_V;
662 role_pending_list = &ivi->fullscreen_pending_apps;
663 wl_list_for_each(p_fullscreen, role_pending_list, link) {
664 if (!strcmp(app_id, p_fullscreen->app_id)) {
665 *role = IVI_SURFACE_ROLE_FULLSCREEN;
670 role_pending_list = &ivi->remote_pending_apps;
671 wl_list_for_each(p_remote, role_pending_list, link) {
672 if (!strcmp(app_id, p_remote->app_id)) {
673 *role = IVI_SURFACE_ROLE_REMOTE;
678 /* else, we are a regular desktop surface */
679 *role = IVI_SURFACE_ROLE_DESKTOP;
684 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
688 ret = ivi_check_pending_desktop_surface_popup(surface);
690 ivi_set_desktop_surface_popup(surface);
691 ivi_layout_popup_committed(surface);
695 ret = ivi_check_pending_desktop_surface_split(surface);
697 ivi_set_desktop_surface_split(surface);
698 ivi_layout_split_committed(surface);
702 ret = ivi_check_pending_desktop_surface_fullscreen(surface);
704 ivi_set_desktop_surface_fullscreen(surface);
705 ivi_layout_fullscreen_committed(surface);
709 ret = ivi_check_pending_desktop_surface_remote(surface);
711 ivi_set_desktop_surface_remote(surface);
712 ivi_layout_desktop_committed(surface);
716 /* if we end up here means we have a regular desktop app and
717 * try to activate it */
718 ivi_set_desktop_surface(surface);
719 ivi_layout_desktop_committed(surface);
723 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
725 struct ivi_output *out;
727 wl_list_for_each(out, &ivi->outputs, link) {
728 create_black_surface_view(out);
729 insert_black_surface(out);
734 ivi_shell_init(struct ivi_compositor *ivi)
736 weston_layer_init(&ivi->hidden, ivi->compositor);
737 weston_layer_init(&ivi->background, ivi->compositor);
738 weston_layer_init(&ivi->normal, ivi->compositor);
739 weston_layer_init(&ivi->panel, ivi->compositor);
740 weston_layer_init(&ivi->popup, ivi->compositor);
741 weston_layer_init(&ivi->fullscreen, ivi->compositor);
743 weston_layer_set_position(&ivi->hidden,
744 WESTON_LAYER_POSITION_HIDDEN);
745 weston_layer_set_position(&ivi->background,
746 WESTON_LAYER_POSITION_BACKGROUND);
747 weston_layer_set_position(&ivi->normal,
748 WESTON_LAYER_POSITION_NORMAL);
749 weston_layer_set_position(&ivi->panel,
750 WESTON_LAYER_POSITION_UI);
751 weston_layer_set_position(&ivi->popup,
752 WESTON_LAYER_POSITION_TOP_UI);
753 weston_layer_set_position(&ivi->fullscreen,
754 WESTON_LAYER_POSITION_FULLSCREEN);
761 ivi_surf_destroy(struct ivi_surface *surf)
763 struct weston_surface *wsurface = surf->view->surface;
765 if (weston_surface_is_mapped(wsurface)) {
766 weston_desktop_surface_unlink_view(surf->view);
767 weston_view_destroy(surf->view);
770 wl_list_remove(&surf->link);
775 ivi_shell_destroy_views_on_layer(struct weston_layer *layer)
777 struct weston_view *view, *view_next;
779 wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) {
780 struct ivi_surface *ivi_surf =
781 get_ivi_shell_surface(view->surface);
783 ivi_surf_destroy(ivi_surf);
788 ivi_shell_finalize(struct ivi_compositor *ivi)
790 ivi_shell_destroy_views_on_layer(&ivi->hidden);
791 weston_layer_fini(&ivi->hidden);
793 ivi_shell_destroy_views_on_layer(&ivi->background);
794 weston_layer_fini(&ivi->background);
796 ivi_shell_destroy_views_on_layer(&ivi->normal);
797 weston_layer_fini(&ivi->normal);
799 ivi_shell_destroy_views_on_layer(&ivi->panel);
800 weston_layer_fini(&ivi->panel);
802 ivi_shell_destroy_views_on_layer(&ivi->popup);
803 weston_layer_fini(&ivi->popup);
807 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
809 struct ivi_surface *surface;
811 wl_list_for_each(surface, &ivi->surfaces, link) {
813 weston_desktop_surface_get_app_id(surface->dsurface);
814 if (app_id == NULL) {
815 weston_log("WARNING app_is is null, unable to advertise\n");
818 agl_shell_desktop_send_application(resource, app_id);
823 client_exec(const char *command, int fd)
828 /* Don't give the child our signal mask */
830 sigprocmask(SIG_UNBLOCK, &sig, NULL);
832 /* Launch clients as the user; don't give them the wrong euid */
833 if (seteuid(getuid()) == -1) {
834 weston_log("seteuid failed: %s\n", strerror(errno));
838 /* Duplicate fd to unset the CLOEXEC flag. We don't need to worry about
839 * clobbering fd, as we'll exit/exec either way.
843 weston_log("dup failed: %s\n", strerror(errno));
847 snprintf(s, sizeof s, "%d", fd);
848 setenv("WAYLAND_SOCKET", s, 1);
850 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
851 weston_log("executing '%s' failed: %s", command, strerror(errno));
854 static struct wl_client *
855 launch_shell_client(struct ivi_compositor *ivi, const char *command)
857 struct wl_client *client;
861 weston_log("launching' %s'\n", command);
863 if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
864 weston_log("socketpair failed while launching '%s': %s\n",
865 command, strerror(errno));
873 weston_log("fork failed while launching '%s': %s\n",
874 command, strerror(errno));
879 client_exec(command, sock[1]);
884 client = wl_client_create(ivi->compositor->wl_display, sock[0]);
887 weston_log("Failed to create wayland client for '%s'",
896 ivi_launch_shell_client(struct ivi_compositor *ivi)
898 struct weston_config_section *section;
899 char *command = NULL;
901 section = weston_config_get_section(ivi->config, "shell-client",
904 weston_config_section_get_string(section, "command",
910 ivi->shell_client.client = launch_shell_client(ivi, command);
911 if (!ivi->shell_client.client)
918 destroy_black_view(struct wl_listener *listener, void *data)
920 struct fullscreen_view *fs =
921 wl_container_of(listener, fs, fs_destroy);
925 wl_list_remove(&fs->fs_destroy.link);
932 create_black_surface_view(struct ivi_output *output)
934 struct weston_surface *surface = NULL;
935 struct weston_view *view;
936 struct ivi_compositor *ivi = output->ivi;
937 struct weston_compositor *wc= ivi->compositor;
938 struct weston_output *woutput = output->output;
943 surface = weston_surface_create(wc);
946 view = weston_view_create(surface);
948 weston_surface_destroy(surface);
952 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
953 weston_surface_set_size(surface, woutput->width, woutput->height);
954 weston_view_set_position(view, woutput->x, woutput->y);
956 output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
957 if (!output->fullscreen_view.fs) {
958 weston_surface_destroy(surface);
961 output->fullscreen_view.fs->view = view;
963 output->fullscreen_view.fs_destroy.notify = destroy_black_view;
964 wl_signal_add(&woutput->destroy_signal,
965 &output->fullscreen_view.fs_destroy);
969 remove_black_surface(struct ivi_output *output)
971 struct weston_view *view;
974 !output->fullscreen_view.fs &&
975 !output->fullscreen_view.fs->view) {
976 weston_log("Output %s doesn't have a surface installed!\n", output->name);
980 view = output->fullscreen_view.fs->view;
981 assert(view->is_mapped == true ||
982 view->surface->is_mapped == true);
984 view->is_mapped = false;
985 view->surface->is_mapped = false;
987 weston_layer_entry_remove(&view->layer_link);
988 weston_view_update_transform(view);
990 weston_view_damage_below(view);
994 insert_black_surface(struct ivi_output *output)
996 struct weston_view *view;
999 !output->fullscreen_view.fs &&
1000 !output->fullscreen_view.fs->view) || !output->output) {
1001 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1005 view = output->fullscreen_view.fs->view;
1006 if (view->is_mapped || view->surface->is_mapped)
1009 weston_layer_entry_remove(&view->layer_link);
1010 weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
1013 view->is_mapped = true;
1014 view->surface->is_mapped = true;
1016 weston_view_update_transform(view);
1017 weston_view_damage_below(view);
1021 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
1023 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1024 struct ivi_output *output;
1025 struct ivi_surface *surface, *tmp;
1027 /* Init already finished. Do nothing */
1028 if (ivi->shell_client.ready)
1031 ivi->shell_client.ready = true;
1033 wl_list_for_each(output, &ivi->outputs, link) {
1034 if (output->background)
1035 remove_black_surface(output);
1036 ivi_layout_init(ivi, output);
1039 wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
1040 wl_list_remove(&surface->link);
1041 wl_list_init(&surface->link);
1042 ivi_check_pending_desktop_surface(surface);
1043 surface->checked_pending = true;
1048 shell_set_background(struct wl_client *client,
1049 struct wl_resource *shell_res,
1050 struct wl_resource *surface_res,
1051 struct wl_resource *output_res)
1053 struct weston_head *head = weston_head_from_resource(output_res);
1054 struct weston_output *woutput = weston_head_get_output(head);
1055 struct ivi_output *output = to_ivi_output(woutput);
1056 struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1057 struct weston_desktop_surface *dsurface;
1058 struct ivi_surface *surface;
1060 dsurface = weston_surface_get_desktop_surface(wsurface);
1062 wl_resource_post_error(shell_res,
1063 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1064 "surface must be a desktop surface");
1068 surface = weston_desktop_surface_get_user_data(dsurface);
1069 if (surface->role != IVI_SURFACE_ROLE_NONE) {
1070 wl_resource_post_error(shell_res,
1071 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1072 "surface already has another ivi role");
1076 if (output->background) {
1077 wl_resource_post_error(shell_res,
1078 AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1079 "output already has background");
1083 surface->checked_pending = true;
1084 surface->role = IVI_SURFACE_ROLE_BACKGROUND;
1085 surface->bg.output = output;
1086 wl_list_remove(&surface->link);
1087 wl_list_init(&surface->link);
1089 output->background = surface;
1091 weston_desktop_surface_set_maximized(dsurface, true);
1092 weston_desktop_surface_set_size(dsurface,
1093 output->output->width,
1094 output->output->height);
1098 shell_set_panel(struct wl_client *client,
1099 struct wl_resource *shell_res,
1100 struct wl_resource *surface_res,
1101 struct wl_resource *output_res,
1104 struct weston_head *head = weston_head_from_resource(output_res);
1105 struct weston_output *woutput = weston_head_get_output(head);
1106 struct ivi_output *output = to_ivi_output(woutput);
1107 struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1108 struct weston_desktop_surface *dsurface;
1109 struct ivi_surface *surface;
1110 struct ivi_surface **member;
1111 int32_t width = 0, height = 0;
1113 dsurface = weston_surface_get_desktop_surface(wsurface);
1115 wl_resource_post_error(shell_res,
1116 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1117 "surface must be a desktop surface");
1121 surface = weston_desktop_surface_get_user_data(dsurface);
1122 if (surface->role != IVI_SURFACE_ROLE_NONE) {
1123 wl_resource_post_error(shell_res,
1124 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1125 "surface already has another ivi role");
1130 case AGL_SHELL_EDGE_TOP:
1131 member = &output->top;
1133 case AGL_SHELL_EDGE_BOTTOM:
1134 member = &output->bottom;
1136 case AGL_SHELL_EDGE_LEFT:
1137 member = &output->left;
1139 case AGL_SHELL_EDGE_RIGHT:
1140 member = &output->right;
1143 wl_resource_post_error(shell_res,
1144 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1145 "invalid edge for panel");
1150 wl_resource_post_error(shell_res,
1151 AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1152 "output already has panel on this edge");
1156 surface->checked_pending = true;
1157 surface->role = IVI_SURFACE_ROLE_PANEL;
1158 surface->panel.output = output;
1159 surface->panel.edge = edge;
1160 wl_list_remove(&surface->link);
1161 wl_list_init(&surface->link);
1165 switch (surface->panel.edge) {
1166 case AGL_SHELL_EDGE_TOP:
1167 case AGL_SHELL_EDGE_BOTTOM:
1168 width = woutput->width;
1170 case AGL_SHELL_EDGE_LEFT:
1171 case AGL_SHELL_EDGE_RIGHT:
1172 height = woutput->height;
1176 weston_desktop_surface_set_size(dsurface, width, height);
1180 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
1181 const char *data, uint32_t app_state)
1183 struct desktop_client *dclient;
1185 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1186 struct ivi_policy *policy = ivi->policy;
1188 /* FIXME: should queue it here and see when binding agl-shell-desktop
1189 * if there are any to be sent */
1196 if (policy && policy->api.surface_advertise_state_change &&
1197 !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
1201 app_role = surf->role;
1202 if (app_role == IVI_SURFACE_ROLE_POPUP)
1203 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
1205 wl_list_for_each(dclient, &ivi->desktop_clients, link)
1206 agl_shell_desktop_send_state_app(dclient->resource, app_id,
1207 data, app_state, app_role);
1211 shell_activate_app(struct wl_client *client,
1212 struct wl_resource *shell_res,
1214 struct wl_resource *output_res)
1216 struct weston_head *head = weston_head_from_resource(output_res);
1217 struct weston_output *woutput = weston_head_get_output(head);
1218 struct ivi_output *output = to_ivi_output(woutput);
1220 ivi_layout_activate(output, app_id);
1224 shell_desktop_activate_app(struct wl_client *client,
1225 struct wl_resource *shell_res,
1226 const char *app_id, const char *data,
1227 struct wl_resource *output_res)
1229 struct weston_head *head = weston_head_from_resource(output_res);
1230 struct weston_output *woutput = weston_head_get_output(head);
1231 struct ivi_output *output = to_ivi_output(woutput);
1233 ivi_layout_activate(output, app_id);
1234 shell_advertise_app_state(output->ivi, app_id,
1235 data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
1239 shell_deactivate_app(struct wl_client *client,
1240 struct wl_resource *shell_res,
1243 struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1244 struct ivi_compositor *ivi = dclient->ivi;
1246 ivi_layout_deactivate(ivi, app_id);
1247 shell_advertise_app_state(ivi, app_id,
1248 NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
1251 static const struct agl_shell_interface agl_shell_implementation = {
1252 .ready = shell_ready,
1253 .set_background = shell_set_background,
1254 .set_panel = shell_set_panel,
1255 .activate_app = shell_activate_app,
1259 shell_desktop_set_app_property(struct wl_client *client,
1260 struct wl_resource *shell_res,
1261 const char *app_id, uint32_t role,
1262 int x, int y, int bx, int by,
1263 int width, int height,
1264 struct wl_resource *output_res)
1266 struct weston_head *head = weston_head_from_resource(output_res);
1267 struct weston_output *woutput = weston_head_get_output(head);
1268 struct ivi_output *output = to_ivi_output(woutput);
1271 case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
1272 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
1273 width, height, app_id);
1275 case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
1276 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
1278 case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
1279 case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
1280 ivi_set_pending_desktop_surface_split(output, app_id, role);
1282 case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
1283 ivi_set_pending_desktop_surface_remote(output, app_id);
1291 ivi_compositor_destroy_pending_surfaces(struct ivi_compositor *ivi)
1293 struct pending_popup *p_popup, *next_p_popup;
1294 struct pending_split *split_surf, *next_split_surf;
1295 struct pending_fullscreen *fs_surf, *next_fs_surf;
1296 struct pending_remote *remote_surf, *next_remote_surf;
1298 wl_list_for_each_safe(p_popup, next_p_popup,
1299 &ivi->popup_pending_apps, link)
1300 ivi_remove_pending_desktop_surface_popup(p_popup);
1302 wl_list_for_each_safe(split_surf, next_split_surf,
1303 &ivi->split_pending_apps, link)
1304 ivi_remove_pending_desktop_surface_split(split_surf);
1306 wl_list_for_each_safe(fs_surf, next_fs_surf,
1307 &ivi->fullscreen_pending_apps, link)
1308 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
1310 wl_list_for_each_safe(remote_surf, next_remote_surf,
1311 &ivi->remote_pending_apps, link)
1312 ivi_remove_pending_desktop_surface_remote(remote_surf);
1316 shell_desktop_set_app_property_mode(struct wl_client *client,
1317 struct wl_resource *shell_res, uint32_t perm)
1319 struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1321 dclient->ivi->keep_pending_surfaces = true;
1323 dclient->ivi->keep_pending_surfaces = false;
1324 /* remove any previous pending surfaces */
1325 ivi_compositor_destroy_pending_surfaces(dclient->ivi);
1329 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
1330 .activate_app = shell_desktop_activate_app,
1331 .set_app_property = shell_desktop_set_app_property,
1332 .deactivate_app = shell_deactivate_app,
1333 .set_app_property_mode = shell_desktop_set_app_property_mode,
1337 unbind_agl_shell(struct wl_resource *resource)
1339 struct ivi_compositor *ivi;
1340 struct ivi_output *output;
1341 struct ivi_surface *surf, *surf_tmp;
1343 ivi = wl_resource_get_user_data(resource);
1344 wl_list_for_each(output, &ivi->outputs, link) {
1345 /* reset the active surf if there's one present */
1346 if (output->active) {
1347 output->active->view->is_mapped = false;
1348 output->active->view->surface->is_mapped = false;
1350 weston_layer_entry_remove(&output->active->view->layer_link);
1351 output->active = NULL;
1354 insert_black_surface(output);
1357 wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
1358 wl_list_remove(&surf->link);
1359 wl_list_init(&surf->link);
1362 wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
1363 wl_list_remove(&surf->link);
1364 wl_list_init(&surf->link);
1367 wl_list_init(&ivi->surfaces);
1368 wl_list_init(&ivi->pending_surfaces);
1370 ivi->shell_client.ready = false;
1371 ivi->shell_client.resource = NULL;
1372 ivi->shell_client.client = NULL;
1376 bind_agl_shell(struct wl_client *client,
1377 void *data, uint32_t version, uint32_t id)
1379 struct ivi_compositor *ivi = data;
1380 struct wl_resource *resource;
1381 struct ivi_policy *policy;
1384 policy = ivi->policy;
1385 interface = (void *) &agl_shell_interface;
1386 if (policy && policy->api.shell_bind_interface &&
1387 !policy->api.shell_bind_interface(client, interface)) {
1388 wl_client_post_implementation_error(client,
1389 "client not authorized to use agl_shell");
1393 resource = wl_resource_create(client, &agl_shell_interface,
1396 wl_client_post_no_memory(client);
1400 if (ivi->shell_client.resource) {
1401 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1402 "agl_shell has already been bound");
1406 wl_resource_set_implementation(resource, &agl_shell_implementation,
1407 ivi, unbind_agl_shell);
1408 ivi->shell_client.resource = resource;
1412 unbind_agl_shell_desktop(struct wl_resource *resource)
1414 struct desktop_client *dclient = wl_resource_get_user_data(resource);
1416 wl_list_remove(&dclient->link);
1421 bind_agl_shell_desktop(struct wl_client *client,
1422 void *data, uint32_t version, uint32_t id)
1424 struct ivi_compositor *ivi = data;
1425 struct wl_resource *resource;
1426 struct ivi_policy *policy;
1427 struct desktop_client *dclient;
1430 policy = ivi->policy;
1431 interface = (void *) &agl_shell_desktop_interface;
1432 if (policy && policy->api.shell_bind_interface &&
1433 !policy->api.shell_bind_interface(client, interface)) {
1434 wl_client_post_implementation_error(client,
1435 "client not authorized to use agl_shell_desktop");
1439 dclient = zalloc(sizeof(*dclient));
1441 wl_client_post_no_memory(client);
1445 resource = wl_resource_create(client, &agl_shell_desktop_interface,
1449 wl_client_post_no_memory(client);
1453 wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
1454 dclient, unbind_agl_shell_desktop);
1456 dclient->resource = resource;
1457 wl_list_insert(&ivi->desktop_clients, &dclient->link);
1459 /* advertise xdg surfaces */
1460 ivi_shell_advertise_xdg_surfaces(ivi, resource);
1464 ivi_shell_create_global(struct ivi_compositor *ivi)
1466 ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
1467 &agl_shell_interface, 1,
1468 ivi, bind_agl_shell);
1469 if (!ivi->agl_shell) {
1470 weston_log("Failed to create wayland global.\n");
1474 ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
1475 &agl_shell_desktop_interface, 2,
1476 ivi, bind_agl_shell_desktop);
1477 if (!ivi->agl_shell_desktop) {
1478 weston_log("Failed to create wayland global (agl_shell_desktop).\n");