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);
641 role_pending_list = &ivi->popup_pending_apps;
642 wl_list_for_each(p_popup, role_pending_list, link) {
643 if (!strcmp(app_id, p_popup->app_id)) {
644 *role = IVI_SURFACE_ROLE_POPUP;
649 role_pending_list = &ivi->split_pending_apps;
650 wl_list_for_each(p_split, role_pending_list, link) {
651 if (!strcmp(app_id, p_split->app_id)) {
652 *role = IVI_SURFACE_ROLE_SPLIT_V;
657 role_pending_list = &ivi->fullscreen_pending_apps;
658 wl_list_for_each(p_fullscreen, role_pending_list, link) {
659 if (!strcmp(app_id, p_fullscreen->app_id)) {
660 *role = IVI_SURFACE_ROLE_FULLSCREEN;
665 role_pending_list = &ivi->remote_pending_apps;
666 wl_list_for_each(p_remote, role_pending_list, link) {
667 if (!strcmp(app_id, p_remote->app_id)) {
668 *role = IVI_SURFACE_ROLE_REMOTE;
673 /* else, we are a regular desktop surface */
674 *role = IVI_SURFACE_ROLE_DESKTOP;
679 ivi_check_pending_desktop_surface(struct ivi_surface *surface)
683 ret = ivi_check_pending_desktop_surface_popup(surface);
685 ivi_set_desktop_surface_popup(surface);
686 ivi_layout_popup_committed(surface);
690 ret = ivi_check_pending_desktop_surface_split(surface);
692 ivi_set_desktop_surface_split(surface);
693 ivi_layout_split_committed(surface);
697 ret = ivi_check_pending_desktop_surface_fullscreen(surface);
699 ivi_set_desktop_surface_fullscreen(surface);
700 ivi_layout_fullscreen_committed(surface);
704 ret = ivi_check_pending_desktop_surface_remote(surface);
706 ivi_set_desktop_surface_remote(surface);
707 ivi_layout_desktop_committed(surface);
711 /* if we end up here means we have a regular desktop app and
712 * try to activate it */
713 ivi_set_desktop_surface(surface);
714 ivi_layout_desktop_committed(surface);
718 ivi_shell_init_black_fs(struct ivi_compositor *ivi)
720 struct ivi_output *out;
722 wl_list_for_each(out, &ivi->outputs, link) {
723 create_black_surface_view(out);
724 insert_black_surface(out);
729 ivi_shell_init(struct ivi_compositor *ivi)
731 weston_layer_init(&ivi->hidden, ivi->compositor);
732 weston_layer_init(&ivi->background, ivi->compositor);
733 weston_layer_init(&ivi->normal, ivi->compositor);
734 weston_layer_init(&ivi->panel, ivi->compositor);
735 weston_layer_init(&ivi->popup, ivi->compositor);
736 weston_layer_init(&ivi->fullscreen, ivi->compositor);
738 weston_layer_set_position(&ivi->hidden,
739 WESTON_LAYER_POSITION_HIDDEN);
740 weston_layer_set_position(&ivi->background,
741 WESTON_LAYER_POSITION_BACKGROUND);
742 weston_layer_set_position(&ivi->normal,
743 WESTON_LAYER_POSITION_NORMAL);
744 weston_layer_set_position(&ivi->panel,
745 WESTON_LAYER_POSITION_UI);
746 weston_layer_set_position(&ivi->popup,
747 WESTON_LAYER_POSITION_TOP_UI);
748 weston_layer_set_position(&ivi->fullscreen,
749 WESTON_LAYER_POSITION_FULLSCREEN);
756 ivi_surf_destroy(struct ivi_surface *surf)
758 struct weston_surface *wsurface = surf->view->surface;
760 if (weston_surface_is_mapped(wsurface)) {
761 weston_desktop_surface_unlink_view(surf->view);
762 weston_view_destroy(surf->view);
765 wl_list_remove(&surf->link);
770 ivi_shell_destroy_views_on_layer(struct weston_layer *layer)
772 struct weston_view *view, *view_next;
774 wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) {
775 struct ivi_surface *ivi_surf =
776 get_ivi_shell_surface(view->surface);
778 ivi_surf_destroy(ivi_surf);
783 ivi_shell_finalize(struct ivi_compositor *ivi)
785 ivi_shell_destroy_views_on_layer(&ivi->hidden);
786 weston_layer_fini(&ivi->hidden);
788 ivi_shell_destroy_views_on_layer(&ivi->background);
789 weston_layer_fini(&ivi->background);
791 ivi_shell_destroy_views_on_layer(&ivi->normal);
792 weston_layer_fini(&ivi->normal);
794 ivi_shell_destroy_views_on_layer(&ivi->panel);
795 weston_layer_fini(&ivi->panel);
797 ivi_shell_destroy_views_on_layer(&ivi->popup);
798 weston_layer_fini(&ivi->popup);
802 ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource)
804 struct ivi_surface *surface;
806 wl_list_for_each(surface, &ivi->surfaces, link) {
808 weston_desktop_surface_get_app_id(surface->dsurface);
809 if (app_id == NULL) {
810 weston_log("WARNING app_is is null, unable to advertise\n");
813 agl_shell_desktop_send_application(resource, app_id);
818 client_exec(const char *command, int fd)
823 /* Don't give the child our signal mask */
825 sigprocmask(SIG_UNBLOCK, &sig, NULL);
827 /* Launch clients as the user; don't give them the wrong euid */
828 if (seteuid(getuid()) == -1) {
829 weston_log("seteuid failed: %s\n", strerror(errno));
833 /* Duplicate fd to unset the CLOEXEC flag. We don't need to worry about
834 * clobbering fd, as we'll exit/exec either way.
838 weston_log("dup failed: %s\n", strerror(errno));
842 snprintf(s, sizeof s, "%d", fd);
843 setenv("WAYLAND_SOCKET", s, 1);
845 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
846 weston_log("executing '%s' failed: %s", command, strerror(errno));
849 static struct wl_client *
850 launch_shell_client(struct ivi_compositor *ivi, const char *command)
852 struct wl_client *client;
856 weston_log("launching' %s'\n", command);
858 if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
859 weston_log("socketpair failed while launching '%s': %s\n",
860 command, strerror(errno));
868 weston_log("fork failed while launching '%s': %s\n",
869 command, strerror(errno));
874 client_exec(command, sock[1]);
879 client = wl_client_create(ivi->compositor->wl_display, sock[0]);
882 weston_log("Failed to create wayland client for '%s'",
891 ivi_launch_shell_client(struct ivi_compositor *ivi)
893 struct weston_config_section *section;
894 char *command = NULL;
896 section = weston_config_get_section(ivi->config, "shell-client",
899 weston_config_section_get_string(section, "command",
905 ivi->shell_client.client = launch_shell_client(ivi, command);
906 if (!ivi->shell_client.client)
913 destroy_black_view(struct wl_listener *listener, void *data)
915 struct fullscreen_view *fs =
916 wl_container_of(listener, fs, fs_destroy);
920 wl_list_remove(&fs->fs_destroy.link);
927 create_black_surface_view(struct ivi_output *output)
929 struct weston_surface *surface = NULL;
930 struct weston_view *view;
931 struct ivi_compositor *ivi = output->ivi;
932 struct weston_compositor *wc= ivi->compositor;
933 struct weston_output *woutput = output->output;
938 surface = weston_surface_create(wc);
941 view = weston_view_create(surface);
943 weston_surface_destroy(surface);
947 weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
948 weston_surface_set_size(surface, woutput->width, woutput->height);
949 weston_view_set_position(view, woutput->x, woutput->y);
951 output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface));
952 if (!output->fullscreen_view.fs) {
953 weston_surface_destroy(surface);
956 output->fullscreen_view.fs->view = view;
958 output->fullscreen_view.fs_destroy.notify = destroy_black_view;
959 wl_signal_add(&woutput->destroy_signal,
960 &output->fullscreen_view.fs_destroy);
964 remove_black_surface(struct ivi_output *output)
966 struct weston_view *view;
969 !output->fullscreen_view.fs &&
970 !output->fullscreen_view.fs->view) {
971 weston_log("Output %s doesn't have a surface installed!\n", output->name);
975 view = output->fullscreen_view.fs->view;
976 assert(view->is_mapped == true ||
977 view->surface->is_mapped == true);
979 view->is_mapped = false;
980 view->surface->is_mapped = false;
982 weston_layer_entry_remove(&view->layer_link);
983 weston_view_update_transform(view);
985 weston_view_damage_below(view);
989 insert_black_surface(struct ivi_output *output)
991 struct weston_view *view;
994 !output->fullscreen_view.fs &&
995 !output->fullscreen_view.fs->view) || !output->output) {
996 weston_log("Output %s doesn't have a surface installed!\n", output->name);
1000 view = output->fullscreen_view.fs->view;
1001 if (view->is_mapped || view->surface->is_mapped)
1004 weston_layer_entry_remove(&view->layer_link);
1005 weston_layer_entry_insert(&output->ivi->fullscreen.view_list,
1008 view->is_mapped = true;
1009 view->surface->is_mapped = true;
1011 weston_view_update_transform(view);
1012 weston_view_damage_below(view);
1016 shell_ready(struct wl_client *client, struct wl_resource *shell_res)
1018 struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res);
1019 struct ivi_output *output;
1020 struct ivi_surface *surface, *tmp;
1022 /* Init already finished. Do nothing */
1023 if (ivi->shell_client.ready)
1026 ivi->shell_client.ready = true;
1028 wl_list_for_each(output, &ivi->outputs, link) {
1029 if (output->background)
1030 remove_black_surface(output);
1031 ivi_layout_init(ivi, output);
1034 wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) {
1035 wl_list_remove(&surface->link);
1036 wl_list_init(&surface->link);
1037 ivi_check_pending_desktop_surface(surface);
1038 surface->checked_pending = true;
1043 shell_set_background(struct wl_client *client,
1044 struct wl_resource *shell_res,
1045 struct wl_resource *surface_res,
1046 struct wl_resource *output_res)
1048 struct weston_head *head = weston_head_from_resource(output_res);
1049 struct weston_output *woutput = weston_head_get_output(head);
1050 struct ivi_output *output = to_ivi_output(woutput);
1051 struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1052 struct weston_desktop_surface *dsurface;
1053 struct ivi_surface *surface;
1055 dsurface = weston_surface_get_desktop_surface(wsurface);
1057 wl_resource_post_error(shell_res,
1058 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1059 "surface must be a desktop surface");
1063 surface = weston_desktop_surface_get_user_data(dsurface);
1064 if (surface->role != IVI_SURFACE_ROLE_NONE) {
1065 wl_resource_post_error(shell_res,
1066 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1067 "surface already has another ivi role");
1071 if (output->background) {
1072 wl_resource_post_error(shell_res,
1073 AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1074 "output already has background");
1078 surface->checked_pending = true;
1079 surface->role = IVI_SURFACE_ROLE_BACKGROUND;
1080 surface->bg.output = output;
1081 wl_list_remove(&surface->link);
1082 wl_list_init(&surface->link);
1084 output->background = surface;
1086 weston_desktop_surface_set_maximized(dsurface, true);
1087 weston_desktop_surface_set_size(dsurface,
1088 output->output->width,
1089 output->output->height);
1093 shell_set_panel(struct wl_client *client,
1094 struct wl_resource *shell_res,
1095 struct wl_resource *surface_res,
1096 struct wl_resource *output_res,
1099 struct weston_head *head = weston_head_from_resource(output_res);
1100 struct weston_output *woutput = weston_head_get_output(head);
1101 struct ivi_output *output = to_ivi_output(woutput);
1102 struct weston_surface *wsurface = wl_resource_get_user_data(surface_res);
1103 struct weston_desktop_surface *dsurface;
1104 struct ivi_surface *surface;
1105 struct ivi_surface **member;
1106 int32_t width = 0, height = 0;
1108 dsurface = weston_surface_get_desktop_surface(wsurface);
1110 wl_resource_post_error(shell_res,
1111 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1112 "surface must be a desktop surface");
1116 surface = weston_desktop_surface_get_user_data(dsurface);
1117 if (surface->role != IVI_SURFACE_ROLE_NONE) {
1118 wl_resource_post_error(shell_res,
1119 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1120 "surface already has another ivi role");
1125 case AGL_SHELL_EDGE_TOP:
1126 member = &output->top;
1128 case AGL_SHELL_EDGE_BOTTOM:
1129 member = &output->bottom;
1131 case AGL_SHELL_EDGE_LEFT:
1132 member = &output->left;
1134 case AGL_SHELL_EDGE_RIGHT:
1135 member = &output->right;
1138 wl_resource_post_error(shell_res,
1139 AGL_SHELL_ERROR_INVALID_ARGUMENT,
1140 "invalid edge for panel");
1145 wl_resource_post_error(shell_res,
1146 AGL_SHELL_ERROR_BACKGROUND_EXISTS,
1147 "output already has panel on this edge");
1151 surface->checked_pending = true;
1152 surface->role = IVI_SURFACE_ROLE_PANEL;
1153 surface->panel.output = output;
1154 surface->panel.edge = edge;
1155 wl_list_remove(&surface->link);
1156 wl_list_init(&surface->link);
1160 switch (surface->panel.edge) {
1161 case AGL_SHELL_EDGE_TOP:
1162 case AGL_SHELL_EDGE_BOTTOM:
1163 width = woutput->width;
1165 case AGL_SHELL_EDGE_LEFT:
1166 case AGL_SHELL_EDGE_RIGHT:
1167 height = woutput->height;
1171 weston_desktop_surface_set_size(dsurface, width, height);
1175 shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
1176 const char *data, uint32_t app_state)
1178 struct desktop_client *dclient;
1180 struct ivi_surface *surf = ivi_find_app(ivi, app_id);
1181 struct ivi_policy *policy = ivi->policy;
1183 /* FIXME: should queue it here and see when binding agl-shell-desktop
1184 * if there are any to be sent */
1191 if (policy && policy->api.surface_advertise_state_change &&
1192 !policy->api.surface_advertise_state_change(surf, surf->ivi)) {
1196 app_role = surf->role;
1197 if (app_role == IVI_SURFACE_ROLE_POPUP)
1198 app_role = AGL_SHELL_DESKTOP_APP_ROLE_POPUP;
1200 wl_list_for_each(dclient, &ivi->desktop_clients, link)
1201 agl_shell_desktop_send_state_app(dclient->resource, app_id,
1202 data, app_state, app_role);
1206 shell_activate_app(struct wl_client *client,
1207 struct wl_resource *shell_res,
1209 struct wl_resource *output_res)
1211 struct weston_head *head = weston_head_from_resource(output_res);
1212 struct weston_output *woutput = weston_head_get_output(head);
1213 struct ivi_output *output = to_ivi_output(woutput);
1215 ivi_layout_activate(output, app_id);
1219 shell_desktop_activate_app(struct wl_client *client,
1220 struct wl_resource *shell_res,
1221 const char *app_id, const char *data,
1222 struct wl_resource *output_res)
1224 struct weston_head *head = weston_head_from_resource(output_res);
1225 struct weston_output *woutput = weston_head_get_output(head);
1226 struct ivi_output *output = to_ivi_output(woutput);
1228 ivi_layout_activate(output, app_id);
1229 shell_advertise_app_state(output->ivi, app_id,
1230 data, AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED);
1234 shell_deactivate_app(struct wl_client *client,
1235 struct wl_resource *shell_res,
1238 struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1239 struct ivi_compositor *ivi = dclient->ivi;
1241 ivi_layout_deactivate(ivi, app_id);
1242 shell_advertise_app_state(ivi, app_id,
1243 NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED);
1246 static const struct agl_shell_interface agl_shell_implementation = {
1247 .ready = shell_ready,
1248 .set_background = shell_set_background,
1249 .set_panel = shell_set_panel,
1250 .activate_app = shell_activate_app,
1254 shell_desktop_set_app_property(struct wl_client *client,
1255 struct wl_resource *shell_res,
1256 const char *app_id, uint32_t role,
1257 int x, int y, int bx, int by,
1258 int width, int height,
1259 struct wl_resource *output_res)
1261 struct weston_head *head = weston_head_from_resource(output_res);
1262 struct weston_output *woutput = weston_head_get_output(head);
1263 struct ivi_output *output = to_ivi_output(woutput);
1266 case AGL_SHELL_DESKTOP_APP_ROLE_POPUP:
1267 ivi_set_pending_desktop_surface_popup(output, x, y, bx, by,
1268 width, height, app_id);
1270 case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN:
1271 ivi_set_pending_desktop_surface_fullscreen(output, app_id);
1273 case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_VERTICAL:
1274 case AGL_SHELL_DESKTOP_APP_ROLE_SPLIT_HORIZONTAL:
1275 ivi_set_pending_desktop_surface_split(output, app_id, role);
1277 case AGL_SHELL_DESKTOP_APP_ROLE_REMOTE:
1278 ivi_set_pending_desktop_surface_remote(output, app_id);
1286 ivi_compositor_destroy_pending_surfaces(struct ivi_compositor *ivi)
1288 struct pending_popup *p_popup, *next_p_popup;
1289 struct pending_split *split_surf, *next_split_surf;
1290 struct pending_fullscreen *fs_surf, *next_fs_surf;
1291 struct pending_remote *remote_surf, *next_remote_surf;
1293 wl_list_for_each_safe(p_popup, next_p_popup,
1294 &ivi->popup_pending_apps, link)
1295 ivi_remove_pending_desktop_surface_popup(p_popup);
1297 wl_list_for_each_safe(split_surf, next_split_surf,
1298 &ivi->split_pending_apps, link)
1299 ivi_remove_pending_desktop_surface_split(split_surf);
1301 wl_list_for_each_safe(fs_surf, next_fs_surf,
1302 &ivi->fullscreen_pending_apps, link)
1303 ivi_remove_pending_desktop_surface_fullscreen(fs_surf);
1305 wl_list_for_each_safe(remote_surf, next_remote_surf,
1306 &ivi->remote_pending_apps, link)
1307 ivi_remove_pending_desktop_surface_remote(remote_surf);
1311 shell_desktop_set_app_property_mode(struct wl_client *client,
1312 struct wl_resource *shell_res, uint32_t perm)
1314 struct desktop_client *dclient = wl_resource_get_user_data(shell_res);
1316 dclient->ivi->keep_pending_surfaces = true;
1318 dclient->ivi->keep_pending_surfaces = false;
1319 /* remove any previous pending surfaces */
1320 ivi_compositor_destroy_pending_surfaces(dclient->ivi);
1324 static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = {
1325 .activate_app = shell_desktop_activate_app,
1326 .set_app_property = shell_desktop_set_app_property,
1327 .deactivate_app = shell_deactivate_app,
1328 .set_app_property_mode = shell_desktop_set_app_property_mode,
1332 unbind_agl_shell(struct wl_resource *resource)
1334 struct ivi_compositor *ivi;
1335 struct ivi_output *output;
1336 struct ivi_surface *surf, *surf_tmp;
1338 ivi = wl_resource_get_user_data(resource);
1339 wl_list_for_each(output, &ivi->outputs, link) {
1340 /* reset the active surf if there's one present */
1341 if (output->active) {
1342 output->active->view->is_mapped = false;
1343 output->active->view->surface->is_mapped = false;
1345 weston_layer_entry_remove(&output->active->view->layer_link);
1346 output->active = NULL;
1349 insert_black_surface(output);
1352 wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) {
1353 wl_list_remove(&surf->link);
1354 wl_list_init(&surf->link);
1357 wl_list_for_each_safe(surf, surf_tmp, &ivi->pending_surfaces, link) {
1358 wl_list_remove(&surf->link);
1359 wl_list_init(&surf->link);
1362 wl_list_init(&ivi->surfaces);
1363 wl_list_init(&ivi->pending_surfaces);
1365 ivi->shell_client.ready = false;
1366 ivi->shell_client.resource = NULL;
1367 ivi->shell_client.client = NULL;
1371 bind_agl_shell(struct wl_client *client,
1372 void *data, uint32_t version, uint32_t id)
1374 struct ivi_compositor *ivi = data;
1375 struct wl_resource *resource;
1376 struct ivi_policy *policy;
1379 policy = ivi->policy;
1380 interface = (void *) &agl_shell_interface;
1381 if (policy && policy->api.shell_bind_interface &&
1382 !policy->api.shell_bind_interface(client, interface)) {
1383 wl_client_post_implementation_error(client,
1384 "client not authorized to use agl_shell");
1388 resource = wl_resource_create(client, &agl_shell_interface,
1391 wl_client_post_no_memory(client);
1395 if (ivi->shell_client.resource) {
1396 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
1397 "agl_shell has already been bound");
1401 wl_resource_set_implementation(resource, &agl_shell_implementation,
1402 ivi, unbind_agl_shell);
1403 ivi->shell_client.resource = resource;
1407 unbind_agl_shell_desktop(struct wl_resource *resource)
1409 struct desktop_client *dclient = wl_resource_get_user_data(resource);
1411 wl_list_remove(&dclient->link);
1416 bind_agl_shell_desktop(struct wl_client *client,
1417 void *data, uint32_t version, uint32_t id)
1419 struct ivi_compositor *ivi = data;
1420 struct wl_resource *resource;
1421 struct ivi_policy *policy;
1422 struct desktop_client *dclient;
1425 policy = ivi->policy;
1426 interface = (void *) &agl_shell_desktop_interface;
1427 if (policy && policy->api.shell_bind_interface &&
1428 !policy->api.shell_bind_interface(client, interface)) {
1429 wl_client_post_implementation_error(client,
1430 "client not authorized to use agl_shell_desktop");
1434 dclient = zalloc(sizeof(*dclient));
1436 wl_client_post_no_memory(client);
1440 resource = wl_resource_create(client, &agl_shell_desktop_interface,
1444 wl_client_post_no_memory(client);
1448 wl_resource_set_implementation(resource, &agl_shell_desktop_implementation,
1449 dclient, unbind_agl_shell_desktop);
1451 dclient->resource = resource;
1452 wl_list_insert(&ivi->desktop_clients, &dclient->link);
1454 /* advertise xdg surfaces */
1455 ivi_shell_advertise_xdg_surfaces(ivi, resource);
1459 ivi_shell_create_global(struct ivi_compositor *ivi)
1461 ivi->agl_shell = wl_global_create(ivi->compositor->wl_display,
1462 &agl_shell_interface, 1,
1463 ivi, bind_agl_shell);
1464 if (!ivi->agl_shell) {
1465 weston_log("Failed to create wayland global.\n");
1469 ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display,
1470 &agl_shell_desktop_interface, 2,
1471 ivi, bind_agl_shell_desktop);
1472 if (!ivi->agl_shell_desktop) {
1473 weston_log("Failed to create wayland global (agl_shell_desktop).\n");