X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fshell.c;h=4ab5e422932d55dad430d123f0bb37df7a3b94bc;hb=b92397ef12626a0d09cb4c9e853d0c038104110f;hp=6944f8a254543e1e17c69ee56745060e4dbf9143;hpb=b491db3111b98e008a31ac817b9987db1b47f35f;p=src%2Fagl-compositor.git diff --git a/src/shell.c b/src/shell.c index 6944f8a..4ab5e42 100644 --- a/src/shell.c +++ b/src/shell.c @@ -42,27 +42,51 @@ #include "agl-shell-server-protocol.h" #include "agl-shell-desktop-server-protocol.h" +#ifdef HAVE_WALTHAM +#include +#endif + static void -create_black_surface_view(struct ivi_output *output); +create_black_curtain_view(struct ivi_output *output); void -ivi_set_desktop_surface(struct ivi_surface *surface) +agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi, + struct ivi_surface *surface) { struct desktop_client *dclient; - struct ivi_compositor *ivi = surface->ivi; - assert(surface->role == IVI_SURFACE_ROLE_NONE); + static bool display_adv = false; - surface->role = IVI_SURFACE_ROLE_DESKTOP; - wl_list_insert(&surface->ivi->surfaces, &surface->link); + if (surface->advertised_on_launch) + return; /* advertise to all desktop clients the new surface */ wl_list_for_each(dclient, &ivi->desktop_clients, link) { const char *app_id = weston_desktop_surface_get_app_id(surface->dsurface); + if (app_id == NULL) { + if (!display_adv) { + weston_log("WARNING app_is is null, unable to advertise\n"); + display_adv = true; + } + return; + } agl_shell_desktop_send_application(dclient->resource, app_id); + surface->advertised_on_launch = true; } } +void +ivi_set_desktop_surface(struct ivi_surface *surface) +{ + struct ivi_compositor *ivi = surface->ivi; + assert(surface->role == IVI_SURFACE_ROLE_NONE); + + surface->role = IVI_SURFACE_ROLE_DESKTOP; + wl_list_insert(&surface->ivi->surfaces, &surface->link); + + agl_shell_desktop_advertise_application_id(ivi, surface); +} + static void ivi_set_desktop_surface_popup(struct ivi_surface *surface) { @@ -71,6 +95,8 @@ ivi_set_desktop_surface_popup(struct ivi_surface *surface) surface->role = IVI_SURFACE_ROLE_POPUP; wl_list_insert(&ivi->surfaces, &surface->link); + + agl_shell_desktop_advertise_application_id(ivi, surface); } static void @@ -81,8 +107,92 @@ ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface) surface->role = IVI_SURFACE_ROLE_FULLSCREEN; wl_list_insert(&ivi->surfaces, &surface->link); + + agl_shell_desktop_advertise_application_id(ivi, surface); +} + +#ifdef HAVE_WALTHAM +void +ivi_destroy_waltham_destroy(struct ivi_surface *surface) +{ + struct ivi_compositor *ivi = surface->ivi; + const struct weston_transmitter_api *api = + ivi->waltham_transmitter_api; + + if (!api) + return; + + if (surface->waltham_surface.transmitter_surface) + api->surface_destroy(surface->waltham_surface.transmitter_surface); +} + +static void +ivi_output_notify_waltham_plugin(struct ivi_surface *surface) +{ + struct ivi_compositor *ivi = surface->ivi; + const struct weston_transmitter_api *api = ivi->waltham_transmitter_api; + struct weston_transmitter *transmitter; + struct weston_transmitter_remote *trans_remote; + struct weston_surface *weston_surface; + struct weston_output *woutput = surface->remote.output->output; + const char *app_id; + + if (!api) + return; + + transmitter = api->transmitter_get(ivi->compositor); + if (!transmitter) + return; + + trans_remote = api->get_transmitter_remote(woutput->name, transmitter); + if (!trans_remote) { + weston_log("Could not find a valie weston_transmitter_remote " + "that matches the output %s\n", woutput->name); + return; + } + + app_id = weston_desktop_surface_get_app_id(surface->dsurface); + weston_surface = + weston_desktop_surface_get_surface(surface->dsurface); + + weston_log("Forwarding app_id %s to remote %s\n", app_id, woutput->name); + + /* this will have the effect of informing the remote side to create a + * surface with the name app_id. W/ xdg-shell the following happens: + * + * compositor (server): + * surface_push_to_remote(): + * waltham-transmitter plug-in + * -> wthp_ivi_app_id_surface_create() + * + * client -- on the receiver side: + * -> wthp_ivi_app_id_surface_create() + * -> wth_receiver_weston_main() + * -> wl_compositor_create_surface() + * -> xdg_wm_base_get_xdg_surface + * -> xdg_toplevel_set_app_id() + * -> gst_init() + * -> gst_parse_launch() + * + * wth_receiver_weston_main() will be invoked from the handler of + * wthp_ivi_app_id_surface_create() and is responsible for setting-up + * the gstreamer pipeline as well. + */ + surface->waltham_surface.transmitter_surface = + api->surface_push_to_remote(weston_surface, app_id, trans_remote, NULL); } +#else +void +ivi_destroy_waltham_destroy(struct ivi_surface *surface) +{ +} +static void +ivi_output_notify_waltham_plugin(struct ivi_surface *surface) +{ +} +#endif + static void ivi_set_desktop_surface_remote(struct ivi_surface *surface) { @@ -101,7 +211,10 @@ ivi_set_desktop_surface_remote(struct ivi_surface *surface) * just being added */ view = output->fullscreen_view.fs->view; if (view->is_mapped || view->surface->is_mapped) - remove_black_surface(output); + remove_black_curtain(output); + + if (output->type == OUTPUT_WALTHAM) + ivi_output_notify_waltham_plugin(surface); wl_list_insert(&ivi->surfaces, &surface->link); } @@ -119,23 +232,161 @@ ivi_set_desktop_surface_split(struct ivi_surface *surface) surface->role = IVI_SURFACE_ROLE_SPLIT_H; wl_list_insert(&ivi->surfaces, &surface->link); + + agl_shell_desktop_advertise_application_id(ivi, surface); +} + +static struct pending_popup * +ivi_ensure_popup(struct ivi_output *ioutput, int x, int y, int bx, int by, + int width, int height, const char *app_id) +{ + struct pending_popup *p_popup = zalloc(sizeof(*p_popup)); + size_t len_app_id = strlen(app_id); + + if (!p_popup) + return NULL; + p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!p_popup->app_id) { + free(p_popup); + return NULL; + } + memcpy(p_popup->app_id, app_id, len_app_id); + p_popup->ioutput = ioutput; + p_popup->x = x; + p_popup->y = y; + + p_popup->bb.x = bx; + p_popup->bb.y = by; + p_popup->bb.width = width; + p_popup->bb.height = height; + + return p_popup; } static void -ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput, - int x, int y, const char *app_id) +ivi_update_popup(struct ivi_output *ioutput, int x, int y, int bx, int by, + int width, int height, const char *app_id, struct pending_popup *p_popup) { - struct ivi_compositor *ivi = ioutput->ivi; size_t len_app_id = strlen(app_id); - struct pending_popup *p_popup = zalloc(sizeof(*p_popup)); + wl_list_remove(&p_popup->link); + wl_list_init(&p_popup->link); + + memset(p_popup->app_id, 0, strlen(app_id) + 1); + free(p_popup->app_id); p_popup->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!p_popup->app_id) + return; memcpy(p_popup->app_id, app_id, len_app_id); + p_popup->ioutput = ioutput; p_popup->x = x; p_popup->y = y; + p_popup->bb.x = bx; + p_popup->bb.y = by; + p_popup->bb.width = width; + p_popup->bb.height = height; +} + +static struct pending_fullscreen * +ivi_ensure_fullscreen(struct ivi_output *ioutput, const char *app_id) +{ + struct pending_fullscreen *p_fullscreen = zalloc(sizeof(*p_fullscreen)); + size_t len_app_id = strlen(app_id); + + if (!p_fullscreen) + return NULL; + p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!p_fullscreen->app_id) { + free(p_fullscreen); + return NULL; + } + memcpy(p_fullscreen->app_id, app_id, len_app_id); + + p_fullscreen->ioutput = ioutput; + return p_fullscreen; +} + +static void +ivi_update_fullscreen(struct ivi_output *ioutput, const char *app_id, + struct pending_fullscreen *p_fullscreen) +{ + size_t len_app_id = strlen(app_id); + + wl_list_remove(&p_fullscreen->link); + wl_list_init(&p_fullscreen->link); + + memset(p_fullscreen->app_id, 0, strlen(app_id) + 1); + free(p_fullscreen->app_id); + + p_fullscreen->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!p_fullscreen->app_id) + return; + memcpy(p_fullscreen->app_id, app_id, len_app_id); + + p_fullscreen->ioutput = ioutput; +} + +static struct pending_remote * +ivi_ensure_remote(struct ivi_output *ioutput, const char *app_id) +{ + struct pending_remote *p_remote = zalloc(sizeof(*p_remote)); + size_t len_app_id = strlen(app_id); + + if (!p_remote) + return NULL; + p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!p_remote->app_id) { + free(p_remote); + return NULL; + } + memcpy(p_remote->app_id, app_id, len_app_id); + + p_remote->ioutput = ioutput; + return p_remote; +} + +static void +ivi_update_remote(struct ivi_output *ioutput, const char *app_id, + struct pending_remote *p_remote) +{ + size_t len_app_id = strlen(app_id); + + wl_list_remove(&p_remote->link); + wl_list_init(&p_remote->link); + + memset(p_remote->app_id, 0, strlen(app_id) + 1); + free(p_remote->app_id); + + p_remote->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!p_remote->app_id) + return; + memcpy(p_remote->app_id, app_id, len_app_id); + + p_remote->ioutput = ioutput; +} + +static void +ivi_set_pending_desktop_surface_popup(struct ivi_output *ioutput, int x, int y, int bx, + int by, int width, int height, const char *app_id) +{ + struct ivi_compositor *ivi = ioutput->ivi; + struct pending_popup *p_popup = NULL; + struct pending_popup *popup; + + wl_list_for_each(popup, &ivi->popup_pending_apps, link) + if (!strcmp(app_id, popup->app_id)) + p_popup = popup; + + if (!p_popup) + p_popup = ivi_ensure_popup(ioutput, x, y, bx, by, width, height, app_id); + else + ivi_update_popup(ioutput, x, y, bx, by, width, height, app_id, p_popup); + if (!p_popup) + return; + wl_list_insert(&ivi->popup_pending_apps, &p_popup->link); } @@ -144,16 +395,21 @@ ivi_set_pending_desktop_surface_fullscreen(struct ivi_output *ioutput, const char *app_id) { struct ivi_compositor *ivi = ioutput->ivi; - size_t len_app_id = strlen(app_id); - - struct pending_fullscreen *fs = zalloc(sizeof(*fs)); + struct pending_fullscreen *p_fullscreen = NULL; + struct pending_fullscreen *fullscreen; - fs->app_id = zalloc(sizeof(char) * (len_app_id + 1)); - memcpy(fs->app_id, app_id, len_app_id); + wl_list_for_each(fullscreen, &ivi->fullscreen_pending_apps, link) + if (!strcmp(app_id, fullscreen->app_id)) + p_fullscreen = fullscreen; - fs->ioutput = ioutput; + if (!p_fullscreen) + p_fullscreen = ivi_ensure_fullscreen(ioutput, app_id); + else + ivi_update_fullscreen(ioutput, app_id, p_fullscreen); - wl_list_insert(&ivi->fullscreen_pending_apps, &fs->link); + if (!p_fullscreen) + return; + wl_list_insert(&ivi->fullscreen_pending_apps, &p_fullscreen->link); } static void @@ -177,7 +433,13 @@ ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput, return; split = zalloc(sizeof(*split)); + if (!split) + return; split->app_id = zalloc(sizeof(char) * (len_app_id + 1)); + if (!split->app_id) { + free(split); + return; + } memcpy(split->app_id, app_id, len_app_id); split->ioutput = ioutput; @@ -186,21 +448,26 @@ ivi_set_pending_desktop_surface_split(struct ivi_output *ioutput, wl_list_insert(&ivi->split_pending_apps, &split->link); } -static void +void ivi_set_pending_desktop_surface_remote(struct ivi_output *ioutput, const char *app_id) { struct ivi_compositor *ivi = ioutput->ivi; - size_t len_app_id = strlen(app_id); - - struct pending_remote *remote = zalloc(sizeof(*remote)); + struct pending_remote *remote; + struct pending_remote *p_remote = NULL; - remote->app_id = zalloc(sizeof(char) * (len_app_id + 1)); - memcpy(remote->app_id, app_id, len_app_id); + wl_list_for_each(remote, &ivi->remote_pending_apps, link) + if (!strcmp(app_id, remote->app_id)) + p_remote = remote; - remote->ioutput = ioutput; + if (!p_remote) + p_remote = ivi_ensure_remote(ioutput, app_id); + else + ivi_update_remote(ioutput, app_id, p_remote); + if (!p_remote) + return; - wl_list_insert(&ivi->remote_pending_apps, &remote->link); + wl_list_insert(&ivi->remote_pending_apps, &p_remote->link); } @@ -236,6 +503,12 @@ ivi_remove_pending_desktop_surface_remote(struct pending_remote *remote) free(remote); } +static bool +ivi_compositor_keep_pending_surfaces(struct ivi_surface *surface) +{ + return surface->ivi->keep_pending_surfaces; +} + static bool ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface) { @@ -244,7 +517,7 @@ ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface) const char *_app_id = weston_desktop_surface_get_app_id(surface->dsurface); - if (wl_list_empty(&ivi->popup_pending_apps)) + if (wl_list_empty(&ivi->popup_pending_apps) || !_app_id) return false; wl_list_for_each_safe(p_popup, next_p_popup, @@ -253,7 +526,14 @@ ivi_check_pending_desktop_surface_popup(struct ivi_surface *surface) surface->popup.output = p_popup->ioutput; surface->popup.x = p_popup->x; surface->popup.y = p_popup->y; - ivi_remove_pending_desktop_surface_popup(p_popup); + + surface->popup.bb.x = p_popup->bb.x; + surface->popup.bb.y = p_popup->bb.y; + surface->popup.bb.width = p_popup->bb.width; + surface->popup.bb.height = p_popup->bb.height; + + if (!ivi_compositor_keep_pending_surfaces(surface)) + ivi_remove_pending_desktop_surface_popup(p_popup); return true; } } @@ -269,7 +549,7 @@ ivi_check_pending_desktop_surface_split(struct ivi_surface *surface) const char *_app_id = weston_desktop_surface_get_app_id(surface->dsurface); - if (wl_list_empty(&ivi->split_pending_apps)) + if (wl_list_empty(&ivi->split_pending_apps) || !_app_id) return false; wl_list_for_each_safe(split_surf, next_split_surf, @@ -277,7 +557,8 @@ ivi_check_pending_desktop_surface_split(struct ivi_surface *surface) if (!strcmp(_app_id, split_surf->app_id)) { surface->split.output = split_surf->ioutput; surface->split.orientation = split_surf->orientation; - ivi_remove_pending_desktop_surface_split(split_surf); + if (!ivi_compositor_keep_pending_surfaces(surface)) + ivi_remove_pending_desktop_surface_split(split_surf); return true; } } @@ -293,14 +574,15 @@ ivi_check_pending_desktop_surface_fullscreen(struct ivi_surface *surface) const char *_app_id = weston_desktop_surface_get_app_id(surface->dsurface); - if (wl_list_empty(&ivi->fullscreen_pending_apps)) + if (wl_list_empty(&ivi->fullscreen_pending_apps) || !_app_id) return false; wl_list_for_each_safe(fs_surf, next_fs_surf, &ivi->fullscreen_pending_apps, link) { if (!strcmp(_app_id, fs_surf->app_id)) { surface->fullscreen.output = fs_surf->ioutput; - ivi_remove_pending_desktop_surface_fullscreen(fs_surf); + if (!ivi_compositor_keep_pending_surfaces(surface)) + ivi_remove_pending_desktop_surface_fullscreen(fs_surf); return true; } } @@ -316,20 +598,69 @@ ivi_check_pending_desktop_surface_remote(struct ivi_surface *surface) const char *_app_id = weston_desktop_surface_get_app_id(surface->dsurface); - if (wl_list_empty(&ivi->remote_pending_apps)) + if (wl_list_empty(&ivi->remote_pending_apps) || !_app_id) return false; wl_list_for_each_safe(remote_surf, next_remote_surf, &ivi->remote_pending_apps, link) { if (!strcmp(_app_id, remote_surf->app_id)) { surface->remote.output = remote_surf->ioutput; - ivi_remove_pending_desktop_surface_remote(remote_surf); + if (!ivi_compositor_keep_pending_surfaces(surface)) + ivi_remove_pending_desktop_surface_remote(remote_surf); return true; } } return false; } +void +ivi_check_pending_surface_desktop(struct ivi_surface *surface, + enum ivi_surface_role *role) +{ + struct ivi_compositor *ivi = surface->ivi; + struct wl_list *role_pending_list; + struct pending_popup *p_popup; + struct pending_split *p_split; + struct pending_fullscreen *p_fullscreen; + struct pending_remote *p_remote; + const char *app_id = + weston_desktop_surface_get_app_id(surface->dsurface); + + role_pending_list = &ivi->popup_pending_apps; + wl_list_for_each(p_popup, role_pending_list, link) { + if (app_id && !strcmp(app_id, p_popup->app_id)) { + *role = IVI_SURFACE_ROLE_POPUP; + return; + } + } + + role_pending_list = &ivi->split_pending_apps; + wl_list_for_each(p_split, role_pending_list, link) { + if (app_id && !strcmp(app_id, p_split->app_id)) { + *role = IVI_SURFACE_ROLE_SPLIT_V; + return; + } + } + + role_pending_list = &ivi->fullscreen_pending_apps; + wl_list_for_each(p_fullscreen, role_pending_list, link) { + if (app_id && !strcmp(app_id, p_fullscreen->app_id)) { + *role = IVI_SURFACE_ROLE_FULLSCREEN; + return; + } + } + + role_pending_list = &ivi->remote_pending_apps; + wl_list_for_each(p_remote, role_pending_list, link) { + if (app_id && !strcmp(app_id, p_remote->app_id)) { + *role = IVI_SURFACE_ROLE_REMOTE; + return; + } + } + + /* else, we are a regular desktop surface */ + *role = IVI_SURFACE_ROLE_DESKTOP; +} void @@ -340,24 +671,28 @@ ivi_check_pending_desktop_surface(struct ivi_surface *surface) ret = ivi_check_pending_desktop_surface_popup(surface); if (ret) { ivi_set_desktop_surface_popup(surface); + ivi_layout_popup_committed(surface); return; } ret = ivi_check_pending_desktop_surface_split(surface); if (ret) { ivi_set_desktop_surface_split(surface); + ivi_layout_split_committed(surface); return; } ret = ivi_check_pending_desktop_surface_fullscreen(surface); if (ret) { ivi_set_desktop_surface_fullscreen(surface); + ivi_layout_fullscreen_committed(surface); return; } ret = ivi_check_pending_desktop_surface_remote(surface); if (ret) { ivi_set_desktop_surface_remote(surface); + ivi_layout_desktop_committed(surface); return; } @@ -373,8 +708,8 @@ ivi_shell_init_black_fs(struct ivi_compositor *ivi) struct ivi_output *out; wl_list_for_each(out, &ivi->outputs, link) { - create_black_surface_view(out); - insert_black_surface(out); + create_black_curtain_view(out); + insert_black_curtain(out); } } @@ -404,6 +739,63 @@ ivi_shell_init(struct ivi_compositor *ivi) return 0; } + +static void +ivi_surf_destroy(struct ivi_surface *surf) +{ + struct weston_surface *wsurface = surf->view->surface; + + if (weston_surface_is_mapped(wsurface)) { + weston_desktop_surface_unlink_view(surf->view); + weston_view_destroy(surf->view); + } + + wl_list_remove(&surf->link); + free(surf); +} + +static void +ivi_shell_destroy_views_on_layer(struct weston_layer *layer) +{ + struct weston_view *view, *view_next; + + wl_list_for_each_safe(view, view_next, &layer->view_list.link, layer_link.link) { + struct ivi_surface *ivi_surf = + get_ivi_shell_surface(view->surface); + if (ivi_surf) + ivi_surf_destroy(ivi_surf); + } +} + +void +ivi_shell_finalize(struct ivi_compositor *ivi) +{ + struct ivi_output *output; + + ivi_shell_destroy_views_on_layer(&ivi->hidden); + weston_layer_fini(&ivi->hidden); + + ivi_shell_destroy_views_on_layer(&ivi->background); + weston_layer_fini(&ivi->background); + + ivi_shell_destroy_views_on_layer(&ivi->normal); + weston_layer_fini(&ivi->normal); + + ivi_shell_destroy_views_on_layer(&ivi->panel); + weston_layer_fini(&ivi->panel); + + ivi_shell_destroy_views_on_layer(&ivi->popup); + weston_layer_fini(&ivi->popup); + + wl_list_for_each(output, &ivi->outputs, link) { + if (output->fullscreen_view.fs->view) { + weston_surface_destroy(output->fullscreen_view.fs->view->surface); + output->fullscreen_view.fs->view = NULL; + } + } + weston_layer_fini(&ivi->fullscreen); +} + static void ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource *resource) { @@ -412,6 +804,10 @@ ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource wl_list_for_each(surface, &ivi->surfaces, link) { const char *app_id = weston_desktop_surface_get_app_id(surface->dsurface); + if (app_id == NULL) { + weston_log("WARNING app_is is null, unable to advertise\n"); + return; + } agl_shell_desktop_send_application(resource, app_id); } } @@ -512,26 +908,21 @@ ivi_launch_shell_client(struct ivi_compositor *ivi) } static void -destroy_black_view(struct wl_listener *listener, void *data) +destroy_black_curtain_view(struct wl_listener *listener, void *data) { struct fullscreen_view *fs = wl_container_of(listener, fs, fs_destroy); if (fs && fs->fs) { - if (fs->fs->view && fs->fs->view->surface) { - weston_surface_destroy(fs->fs->view->surface); - fs->fs->view = NULL; - } - - free(fs->fs); wl_list_remove(&fs->fs_destroy.link); + free(fs->fs); } } static void -create_black_surface_view(struct ivi_output *output) +create_black_curtain_view(struct ivi_output *output) { struct weston_surface *surface = NULL; struct weston_view *view; @@ -539,28 +930,55 @@ create_black_surface_view(struct ivi_output *output) struct weston_compositor *wc= ivi->compositor; struct weston_output *woutput = output->output; + if (!woutput) + return; + surface = weston_surface_create(wc); + if (!surface) + return; view = weston_view_create(surface); - - assert(view || surface); + if (!view) { + weston_surface_destroy(surface); + return; + } weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1); weston_surface_set_size(surface, woutput->width, woutput->height); weston_view_set_position(view, woutput->x, woutput->y); output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface)); + if (!output->fullscreen_view.fs) { + weston_surface_destroy(surface); + return; + } output->fullscreen_view.fs->view = view; - output->fullscreen_view.fs_destroy.notify = destroy_black_view; + output->fullscreen_view.fs_destroy.notify = destroy_black_curtain_view; wl_signal_add(&woutput->destroy_signal, &output->fullscreen_view.fs_destroy); } +bool +output_has_black_curtain(struct ivi_output *output) +{ + return (output->fullscreen_view.fs->view && + output->fullscreen_view.fs->view->is_mapped && + output->fullscreen_view.fs->view->surface->is_mapped); +} + void -remove_black_surface(struct ivi_output *output) +remove_black_curtain(struct ivi_output *output) { - struct weston_view *view = output->fullscreen_view.fs->view; + struct weston_view *view; + if (!output && + !output->fullscreen_view.fs && + !output->fullscreen_view.fs->view) { + weston_log("Output %s doesn't have a surface installed!\n", output->name); + return; + } + + view = output->fullscreen_view.fs->view; assert(view->is_mapped == true || view->surface->is_mapped == true); @@ -570,14 +988,24 @@ remove_black_surface(struct ivi_output *output) weston_layer_entry_remove(&view->layer_link); weston_view_update_transform(view); - weston_output_damage(output->output); + weston_view_damage_below(view); + + weston_log("Removed black curtain from output %s\n", output->output->name); } void -insert_black_surface(struct ivi_output *output) +insert_black_curtain(struct ivi_output *output) { - struct weston_view *view = output->fullscreen_view.fs->view; + struct weston_view *view; + + if ((!output && + !output->fullscreen_view.fs && + !output->fullscreen_view.fs->view) || !output->output) { + weston_log("Output %s doesn't have a surface installed!\n", output->name); + return; + } + view = output->fullscreen_view.fs->view; if (view->is_mapped || view->surface->is_mapped) return; @@ -589,7 +1017,9 @@ insert_black_surface(struct ivi_output *output) view->surface->is_mapped = true; weston_view_update_transform(view); - weston_output_damage(output->output); + weston_view_damage_below(view); + + weston_log("Added black curtain to output %s\n", output->output->name); } static void @@ -599,21 +1029,33 @@ shell_ready(struct wl_client *client, struct wl_resource *shell_res) struct ivi_output *output; struct ivi_surface *surface, *tmp; + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + /* Init already finished. Do nothing */ if (ivi->shell_client.ready) return; + ivi->shell_client.ready = true; wl_list_for_each(output, &ivi->outputs, link) { if (output->background) - remove_black_surface(output); + remove_black_curtain(output); ivi_layout_init(ivi, output); } wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) { wl_list_remove(&surface->link); + wl_list_init(&surface->link); ivi_check_pending_desktop_surface(surface); + surface->checked_pending = true; } } @@ -627,9 +1069,19 @@ shell_set_background(struct wl_client *client, struct weston_output *woutput = weston_head_get_output(head); struct ivi_output *output = to_ivi_output(woutput); struct weston_surface *wsurface = wl_resource_get_user_data(surface_res); + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); struct weston_desktop_surface *dsurface; struct ivi_surface *surface; + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + dsurface = weston_surface_get_desktop_surface(wsurface); if (!dsurface) { wl_resource_post_error(shell_res, @@ -653,6 +1105,7 @@ shell_set_background(struct wl_client *client, return; } + surface->checked_pending = true; surface->role = IVI_SURFACE_ROLE_BACKGROUND; surface->bg.output = output; wl_list_remove(&surface->link); @@ -677,11 +1130,21 @@ shell_set_panel(struct wl_client *client, struct weston_output *woutput = weston_head_get_output(head); struct ivi_output *output = to_ivi_output(woutput); struct weston_surface *wsurface = wl_resource_get_user_data(surface_res); + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); struct weston_desktop_surface *dsurface; struct ivi_surface *surface; struct ivi_surface **member; int32_t width = 0, height = 0; + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + dsurface = weston_surface_get_desktop_surface(wsurface); if (!dsurface) { wl_resource_post_error(shell_res, @@ -725,6 +1188,7 @@ shell_set_panel(struct wl_client *client, return; } + surface->checked_pending = true; surface->role = IVI_SURFACE_ROLE_PANEL; surface->panel.output = output; surface->panel.edge = edge; @@ -747,8 +1211,7 @@ shell_set_panel(struct wl_client *client, weston_desktop_surface_set_size(dsurface, width, height); } - -static void +void shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id, const char *data, uint32_t app_state) { @@ -762,6 +1225,9 @@ shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id, if (!surf) return; + if (!app_id) + return; + if (policy && policy->api.surface_advertise_state_change && !policy->api.surface_advertise_state_change(surf, surf->ivi)) { return; @@ -784,8 +1250,18 @@ shell_activate_app(struct wl_client *client, { struct weston_head *head = weston_head_from_resource(output_res); struct weston_output *woutput = weston_head_get_output(head); + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); struct ivi_output *output = to_ivi_output(woutput); + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + wl_resource_post_error(shell_res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound. " + "Check out bound_fail event"); + return; + } + ivi_layout_activate(output, app_id); } @@ -817,7 +1293,14 @@ shell_deactivate_app(struct wl_client *client, NULL, AGL_SHELL_DESKTOP_APP_STATE_DEACTIVATED); } +/* stub, no usage for the time being */ +static void +shell_destroy(struct wl_client *client, struct wl_resource *res) +{ +} + static const struct agl_shell_interface agl_shell_implementation = { + .destroy = shell_destroy, .ready = shell_ready, .set_background = shell_set_background, .set_panel = shell_set_panel, @@ -828,7 +1311,9 @@ static void shell_desktop_set_app_property(struct wl_client *client, struct wl_resource *shell_res, const char *app_id, uint32_t role, - int x, int y, struct wl_resource *output_res) + int x, int y, int bx, int by, + int width, int height, + struct wl_resource *output_res) { struct weston_head *head = weston_head_from_resource(output_res); struct weston_output *woutput = weston_head_get_output(head); @@ -836,7 +1321,8 @@ shell_desktop_set_app_property(struct wl_client *client, switch (role) { case AGL_SHELL_DESKTOP_APP_ROLE_POPUP: - ivi_set_pending_desktop_surface_popup(output, x, y, app_id); + ivi_set_pending_desktop_surface_popup(output, x, y, bx, by, + width, height, app_id); break; case AGL_SHELL_DESKTOP_APP_ROLE_FULLSCREEN: ivi_set_pending_desktop_surface_fullscreen(output, app_id); @@ -853,10 +1339,50 @@ shell_desktop_set_app_property(struct wl_client *client, } } +void +ivi_compositor_destroy_pending_surfaces(struct ivi_compositor *ivi) +{ + struct pending_popup *p_popup, *next_p_popup; + struct pending_split *split_surf, *next_split_surf; + struct pending_fullscreen *fs_surf, *next_fs_surf; + struct pending_remote *remote_surf, *next_remote_surf; + + wl_list_for_each_safe(p_popup, next_p_popup, + &ivi->popup_pending_apps, link) + ivi_remove_pending_desktop_surface_popup(p_popup); + + wl_list_for_each_safe(split_surf, next_split_surf, + &ivi->split_pending_apps, link) + ivi_remove_pending_desktop_surface_split(split_surf); + + wl_list_for_each_safe(fs_surf, next_fs_surf, + &ivi->fullscreen_pending_apps, link) + ivi_remove_pending_desktop_surface_fullscreen(fs_surf); + + wl_list_for_each_safe(remote_surf, next_remote_surf, + &ivi->remote_pending_apps, link) + ivi_remove_pending_desktop_surface_remote(remote_surf); +} + +static void +shell_desktop_set_app_property_mode(struct wl_client *client, + struct wl_resource *shell_res, uint32_t perm) +{ + struct desktop_client *dclient = wl_resource_get_user_data(shell_res); + if (perm) { + dclient->ivi->keep_pending_surfaces = true; + } else { + dclient->ivi->keep_pending_surfaces = false; + /* remove any previous pending surfaces */ + ivi_compositor_destroy_pending_surfaces(dclient->ivi); + } +} + static const struct agl_shell_desktop_interface agl_shell_desktop_implementation = { .activate_app = shell_desktop_activate_app, .set_app_property = shell_desktop_set_app_property, .deactivate_app = shell_deactivate_app, + .set_app_property_mode = shell_desktop_set_app_property_mode, }; static void @@ -867,6 +1393,14 @@ unbind_agl_shell(struct wl_resource *resource) struct ivi_surface *surf, *surf_tmp; ivi = wl_resource_get_user_data(resource); + + /* reset status to allow other clients issue legit requests */ + if (ivi->shell_client.resource && + ivi->shell_client.status == BOUND_FAILED) { + ivi->shell_client.status = BOUND_OK; + return; + } + wl_list_for_each(output, &ivi->outputs, link) { /* reset the active surf if there's one present */ if (output->active) { @@ -877,7 +1411,7 @@ unbind_agl_shell(struct wl_resource *resource) output->active = NULL; } - insert_black_surface(output); + insert_black_curtain(output); } wl_list_for_each_safe(surf, surf_tmp, &ivi->surfaces, link) { @@ -904,31 +1438,42 @@ bind_agl_shell(struct wl_client *client, { struct ivi_compositor *ivi = data; struct wl_resource *resource; - - resource = wl_resource_create(client, &agl_shell_interface, - 1, id); - if (!resource) { - wl_client_post_no_memory(client); + struct ivi_policy *policy; + void *interface; + + policy = ivi->policy; + interface = (void *) &agl_shell_interface; + if (policy && policy->api.shell_bind_interface && + !policy->api.shell_bind_interface(client, interface)) { + wl_client_post_implementation_error(client, + "client not authorized to use agl_shell"); return; } -#if 0 - if (ivi->shell_client.client != client) { - wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "client not authorized to use agl_shell"); + resource = wl_resource_create(client, &agl_shell_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); return; } -#endif if (ivi->shell_client.resource) { - wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "agl_shell has already been bound"); - return; + if (wl_resource_get_version(resource) == 1) { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound"); + return; + } + + agl_shell_send_bound_fail(resource); + ivi->shell_client.status = BOUND_FAILED; } wl_resource_set_implementation(resource, &agl_shell_implementation, ivi, unbind_agl_shell); ivi->shell_client.resource = resource; + + if (ivi->shell_client.status == BOUND_OK && + wl_resource_get_version(resource) >= AGL_SHELL_BOUND_OK_SINCE_VERSION) + agl_shell_send_bound_ok(ivi->shell_client.resource); } static void @@ -946,8 +1491,20 @@ bind_agl_shell_desktop(struct wl_client *client, { struct ivi_compositor *ivi = data; struct wl_resource *resource; - struct desktop_client *dclient = zalloc(sizeof(*dclient)); + struct ivi_policy *policy; + struct desktop_client *dclient; + void *interface; + + policy = ivi->policy; + interface = (void *) &agl_shell_desktop_interface; + if (policy && policy->api.shell_bind_interface && + !policy->api.shell_bind_interface(client, interface)) { + wl_client_post_implementation_error(client, + "client not authorized to use agl_shell_desktop"); + return; + } + dclient = zalloc(sizeof(*dclient)); if (!dclient) { wl_client_post_no_memory(client); return; @@ -975,7 +1532,7 @@ int ivi_shell_create_global(struct ivi_compositor *ivi) { ivi->agl_shell = wl_global_create(ivi->compositor->wl_display, - &agl_shell_interface, 1, + &agl_shell_interface, 2, ivi, bind_agl_shell); if (!ivi->agl_shell) { weston_log("Failed to create wayland global.\n"); @@ -983,7 +1540,7 @@ ivi_shell_create_global(struct ivi_compositor *ivi) } ivi->agl_shell_desktop = wl_global_create(ivi->compositor->wl_display, - &agl_shell_desktop_interface, 1, + &agl_shell_desktop_interface, 2, ivi, bind_agl_shell_desktop); if (!ivi->agl_shell_desktop) { weston_log("Failed to create wayland global (agl_shell_desktop).\n");