X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fshell.c;h=c29d89eabf2416548536d961735f1be1bd8b25bf;hb=HEAD;hp=fbd1b726067d4f46707612338ac72841edc09db0;hpb=359a0612e48d7d21d5247199ca57063bd5965f71;p=src%2Fagl-compositor.git diff --git a/src/shell.c b/src/shell.c index fbd1b72..c29d89e 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1,5 +1,5 @@ /* - * Copyright © 2019, 2022 Collabora, Ltd. + * Copyright © 2019, 2022, 2024 Collabora, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -38,7 +38,7 @@ #include #include -#include +#include #include "shared/os-compatibility.h" #include "shared/helpers.h" #include "shared/process-util.h" @@ -46,13 +46,15 @@ #include "agl-shell-server-protocol.h" #include "agl-shell-desktop-server-protocol.h" -#ifdef HAVE_WALTHAM -#include -#endif - static void create_black_curtain_view(struct ivi_output *output); +static uint32_t +reverse_orientation(uint32_t orientation); + +const char * +split_orientation_to_string(uint32_t orientation); + void agl_shell_desktop_advertise_application_id(struct ivi_compositor *ivi, struct ivi_surface *surface) @@ -125,88 +127,6 @@ ivi_set_desktop_surface_fullscreen(struct ivi_surface *surface) 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) { @@ -227,9 +147,6 @@ ivi_set_desktop_surface_remote(struct ivi_surface *surface) if (view->is_mapped || view->surface->is_mapped) remove_black_curtain(output); - if (output->type == OUTPUT_WALTHAM) - ivi_output_notify_waltham_plugin(surface); - wl_list_insert(&ivi->surfaces, &surface->link); } @@ -676,6 +593,24 @@ ivi_check_pending_surface_desktop(struct ivi_surface *surface, *role = IVI_SURFACE_ROLE_DESKTOP; } +struct pending_app * +ivi_check_pending_app_type(struct ivi_surface *surface, enum ivi_surface_role role) +{ + struct pending_app *papp; + const char *app_id = NULL; + + app_id = weston_desktop_surface_get_app_id(surface->dsurface); + if (!app_id) + return NULL; + + wl_list_for_each(papp, &surface->ivi->pending_apps, link) { + if (strcmp(app_id, papp->app_id) == 0 && papp->role == role) + return papp; + } + + return NULL; +} + void ivi_check_pending_desktop_surface(struct ivi_surface *surface) @@ -706,7 +641,46 @@ ivi_check_pending_desktop_surface(struct ivi_surface *surface) ret = ivi_check_pending_desktop_surface_remote(surface); if (ret) { ivi_set_desktop_surface_remote(surface); - ivi_layout_desktop_committed(surface); + ivi_layout_remote_committed(surface); + return; + } + + /* new way of doing it */ + struct pending_app *papp = + ivi_check_pending_app_type(surface, IVI_SURFACE_ROLE_TILE); + if (papp) { + struct pending_app_tile *papp_tile = + container_of(papp, struct pending_app_tile, base); + + // handle the currently active surface + if (papp->ioutput->active) { + int width_prev_app = 0; + + if (papp_tile->width > 0) { + if (papp_tile->orientation == AGL_SHELL_TILE_ORIENTATION_TOP || + papp_tile->orientation == AGL_SHELL_TILE_ORIENTATION_BOTTOM) + width_prev_app = papp->ioutput->area.height - papp_tile->width; + else + width_prev_app = papp->ioutput->area.width - papp_tile->width; + } + _ivi_set_shell_surface_split(papp->ioutput->active, NULL, + reverse_orientation(papp_tile->orientation), + width_prev_app, false, false); + } + + surface->role = IVI_SURFACE_ROLE_TILE; + surface->current_completed_output = papp->ioutput; + wl_list_insert(&surface->ivi->surfaces, &surface->link); + + _ivi_set_shell_surface_split(surface, papp->ioutput, + papp_tile->orientation, papp_tile->width, + papp_tile->sticky, true); + + /* remove it from pending */ + wl_list_remove(&papp->link); + free(papp->app_id); + free(papp); + return; } @@ -804,7 +778,7 @@ ivi_shell_finalize(struct ivi_compositor *ivi) wl_list_for_each(output, &ivi->outputs, link) { if (output->fullscreen_view.fs && output->fullscreen_view.fs->view) { - weston_surface_destroy(output->fullscreen_view.fs->view->surface); + weston_surface_unref(output->fullscreen_view.fs->view->surface); output->fullscreen_view.fs->view = NULL; } } @@ -829,9 +803,9 @@ ivi_shell_advertise_xdg_surfaces(struct ivi_compositor *ivi, struct wl_resource static struct wl_client * client_launch(struct weston_compositor *compositor, - struct weston_process *proc, + struct wet_process *proc, const char *path, - weston_process_cleanup_func_t cleanup) + wet_process_cleanup_func_t cleanup) { struct wl_client *client = NULL; struct custom_env child_env; @@ -936,14 +910,14 @@ client_launch(struct weston_compositor *compositor, } struct process_info { - struct weston_process proc; + struct wet_process proc; char *path; }; int sigchld_handler(int signal_number, void *data) { - struct weston_process *p; + struct wet_process *p; struct ivi_compositor *ivi = data; int status; pid_t pid; @@ -961,7 +935,7 @@ sigchld_handler(int signal_number, void *data) wl_list_remove(&p->link); wl_list_init(&p->link); - p->cleanup(p, status); + p->cleanup(p, status, NULL); } if (pid < 0 && errno != ECHILD) @@ -972,7 +946,7 @@ sigchld_handler(int signal_number, void *data) static void -process_handle_sigchld(struct weston_process *process, int status) +process_handle_sigchld(struct wet_process *process, int status, void *data) { struct process_info *pinfo = container_of(process, struct process_info, proc); @@ -1048,41 +1022,72 @@ destroy_black_curtain_view(struct wl_listener *listener, void *data) } +int +curtain_get_label(struct weston_surface *surface, char *buf, size_t len) +{ + return snprintf(buf, len, "%s", "black curtain"); +} + +static void +curtain_surface_committed(struct weston_surface *es, struct weston_coord_surface new_origin) +{ + +} + + static void create_black_curtain_view(struct ivi_output *output) { struct weston_surface *surface = NULL; struct weston_view *view; struct ivi_compositor *ivi = output->ivi; - struct weston_compositor *wc= ivi->compositor; + struct weston_compositor *ec = ivi->compositor; struct weston_output *woutput = output->output; + struct weston_buffer_reference *buffer_ref; if (!woutput) return; - surface = weston_surface_create(wc); + surface = weston_surface_create(ec); if (!surface) return; + view = weston_view_create(surface); - if (!view) { - weston_surface_destroy(surface); - return; - } + if (!view) + goto err_surface; + + buffer_ref = weston_buffer_create_solid_rgba(ec, 0.0, 0.0, 0.0, 1.0); + if (buffer_ref == NULL) + goto err_view; - weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1); + surface->committed = curtain_surface_committed; + surface->committed_private = NULL; weston_surface_set_size(surface, woutput->width, woutput->height); - weston_view_set_position(view, woutput->x, woutput->y); + + weston_surface_attach_solid(surface, buffer_ref, + woutput->width, woutput->height); + + weston_surface_set_label_func(surface, curtain_get_label); + weston_view_set_position(view, woutput->pos); output->fullscreen_view.fs = zalloc(sizeof(struct ivi_surface)); - if (!output->fullscreen_view.fs) { - weston_surface_destroy(surface); - return; - } + if (!output->fullscreen_view.fs) + goto err_view; + output->fullscreen_view.fs->view = view; + output->fullscreen_view.buffer_ref = buffer_ref; - output->fullscreen_view.fs_destroy.notify = destroy_black_curtain_view; + output->fullscreen_view.fs_destroy.notify = + destroy_black_curtain_view; wl_signal_add(&woutput->destroy_signal, &output->fullscreen_view.fs_destroy); + + return; + +err_view: + weston_view_destroy(view); +err_surface: + weston_surface_unref(surface); } bool @@ -1098,6 +1103,7 @@ void remove_black_curtain(struct ivi_output *output) { struct weston_view *view; + struct weston_surface *wsurface; if ((!output && !output->fullscreen_view.fs && @@ -1108,17 +1114,13 @@ remove_black_curtain(struct ivi_output *output) } view = output->fullscreen_view.fs->view; + wsurface = view->surface; assert(view->is_mapped == true || view->surface->is_mapped == true); - view->is_mapped = false; - view->surface->is_mapped = false; - - weston_layer_entry_remove(&view->layer_link); - weston_view_update_transform(view); - - weston_view_damage_below(view); + weston_surface_unmap(wsurface); + weston_view_move_to_layer(view, NULL); weston_log("Removed black curtain from output %s\n", output->output->name); } @@ -1126,29 +1128,23 @@ void insert_black_curtain(struct ivi_output *output) { struct weston_view *view; + struct weston_surface *wsurface; if ((!output && !output->fullscreen_view.fs && - !output->fullscreen_view.fs->view) || !output->output || - !output->fullscreen_view.fs) { + !output->fullscreen_view.fs->view) || + !output->output || !output->fullscreen_view.fs) { weston_log("Output %s doesn't have a surface installed!\n", output->name); return; } view = output->fullscreen_view.fs->view; + wsurface = view->surface; if (view->is_mapped || view->surface->is_mapped) return; - weston_layer_entry_remove(&view->layer_link); - weston_layer_entry_insert(&output->ivi->fullscreen.view_list, - &view->layer_link); - - view->is_mapped = true; - view->surface->is_mapped = true; - - weston_view_update_transform(view); - weston_view_damage_below(view); - + weston_surface_map(wsurface); + weston_view_move_to_layer(view, &output->ivi->fullscreen.view_list); weston_log("Added black curtain to output %s\n", output->output->name); } @@ -1168,6 +1164,23 @@ shell_send_app_state(struct ivi_compositor *ivi, const char *app_id, } } +void +shell_send_app_on_output(struct ivi_compositor *ivi, const char *app_id, + const char *output_name) +{ + if (app_id && ivi->shell_client.resource && + wl_resource_get_version(ivi->shell_client.resource) >= + AGL_SHELL_APP_ON_OUTPUT_SINCE_VERSION) { + + agl_shell_send_app_on_output(ivi->shell_client.resource, + app_id, output_name); + + if (ivi->shell_client.resource_ext) + agl_shell_send_app_on_output(ivi->shell_client.resource_ext, + app_id, output_name); + } +} + static void shell_ready(struct wl_client *client, struct wl_resource *shell_res) { @@ -1180,8 +1193,8 @@ shell_ready(struct wl_client *client, struct wl_resource *shell_res) 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"); + "agl_shell (ready quest) has already " + "been bound. Check out bound_fail event"); return; } @@ -1237,8 +1250,8 @@ shell_set_background(struct wl_client *client, ivi->shell_client.resource_ext == shell_res) { wl_resource_post_error(shell_res, WL_DISPLAY_ERROR_INVALID_OBJECT, - "agl_shell has already been bound. " - "Check out bound_fail event"); + "agl_shell (set_background) has already " + "been bound. Check out bound_fail event"); return; } @@ -1302,7 +1315,7 @@ shell_set_panel(struct wl_client *client, ivi->shell_client.resource_ext == shell_res) { wl_resource_post_error(shell_res, WL_DISPLAY_ERROR_INVALID_OBJECT, - "agl_shell has already been bound. " + "agl_shell (set_panel) has already been bound. " "Check out bound_fail event"); return; } @@ -1467,13 +1480,28 @@ shell_set_app_float(struct wl_client *client, struct wl_resource *shell_res, struct weston_view *ev = surf->view; struct weston_desktop_surface *dsurf = surf->dsurface; struct ivi_bounding_box bb = {}; + const char *prev_activate_app_id = NULL; /* XXX: if this is useful we could bring it as active then make * it float, but avoid doing it for the moment */ if (surf != ivi_output->active) return; - ivi_layout_deactivate(ivi, app_id); + if (ivi_output->previous_active) + prev_activate_app_id = + weston_desktop_surface_get_app_id(ivi_output->previous_active->dsurface); + + /* only deactivate if previous_active is different, otherwise + * this will blow up, because we're trying to activate the same + * app_id as the this one! */ + if (prev_activate_app_id && strcmp(app_id, prev_activate_app_id)) { + ivi_layout_deactivate(ivi, app_id); + } else if (prev_activate_app_id) { + weston_layer_entry_remove(&ev->layer_link); + weston_view_geometry_dirty(ev); + weston_surface_damage(ev->surface); + } + surf->hidden_layer_output = ivi_output; /* set attributes */ @@ -1505,6 +1533,59 @@ shell_set_app_float(struct wl_client *client, struct wl_resource *shell_res, } } +static void +shell_set_app_fullscreen(struct wl_client *client, + struct wl_resource *shell_res, const char *app_id) +{ + struct ivi_compositor *ivi = wl_resource_get_user_data(shell_res); + struct weston_output *output = get_focused_output(ivi->compositor); + struct ivi_output *ivi_output; + struct ivi_surface *surf = ivi_find_app(ivi, app_id); + + if (!output) + output = get_default_output(ivi->compositor); + + ivi_output = to_ivi_output(output); + + if (surf && surf->role == IVI_SURFACE_ROLE_DESKTOP) { + struct weston_view *ev = surf->view; + struct weston_desktop_surface *dsurf = surf->dsurface; + + if (surf != ivi_output->active) + return; + + weston_layer_entry_remove(&surf->view->layer_link); + weston_view_geometry_dirty(surf->view); + weston_surface_damage(surf->view->surface); + + surf->hidden_layer_output = ivi_output; + + /* set attributes */ + surf->fullscreen.output = ivi_output; + + /* change the role */ + surf->role = IVI_SURFACE_ROLE_NONE; + + wl_list_remove(&surf->link); + wl_list_init(&surf->link); + + ivi_set_desktop_surface_fullscreen(surf); + + weston_desktop_surface_set_maximized(dsurf, false); + weston_desktop_surface_set_fullscreen(dsurf, true); + weston_desktop_surface_set_size(dsurf, + ivi_output->output->width, + ivi_output->output->height); + + /* add to hidden layer */ + weston_layer_entry_insert(&ivi->hidden.view_list, &ev->layer_link); + weston_compositor_schedule_repaint(ivi->compositor); + } else if (!surf || (surf && surf->role != IVI_SURFACE_ROLE_FULLSCREEN)) { + ivi_set_pending_desktop_surface_fullscreen(ivi_output, app_id); + } +} + + static void shell_set_app_normal(struct wl_client *client, struct wl_resource *shell_res, const char *app_id) @@ -1532,6 +1613,7 @@ shell_set_app_normal(struct wl_client *client, struct wl_resource *shell_res, /* change the role */ surf->role = IVI_SURFACE_ROLE_NONE; + surf->state = NORMAL; surf->desktop.pending_output = ivi_output; wl_list_remove(&surf->link); @@ -1545,6 +1627,9 @@ shell_set_app_normal(struct wl_client *client, struct wl_resource *shell_res, else area = ivi_output->area; + if (weston_desktop_surface_get_fullscreen(dsurf)) + weston_desktop_surface_set_fullscreen(dsurf, false); + weston_desktop_surface_set_maximized(dsurf, true); weston_desktop_surface_set_size(dsurf, area.width, area.height); @@ -1613,9 +1698,410 @@ shell_set_activate_region(struct wl_client *client, struct wl_resource *res, ioutput->area_activation = area; } +static void +shell_set_app_output(struct wl_client *client, struct wl_resource *res, + const char *app_id, struct wl_resource *output) +{ + struct ivi_compositor *ivi = wl_resource_get_user_data(res); + struct weston_head *head = weston_head_from_resource(output); + struct weston_output *woutput = weston_head_get_output(head); + struct ivi_output *ioutput = to_ivi_output(woutput); + struct ivi_surface *surf = ivi_find_app(ivi, app_id); + struct ivi_output *desktop_last_output; + struct ivi_output *current_completed_output; + + if (!app_id || !ioutput) + return; + + /* handle the case we're not mapped at all */ + if (!surf) { + ivi_set_pending_desktop_surface_remote(ioutput, app_id); + shell_send_app_on_output(ivi, app_id, woutput->name); + return; + } + + desktop_last_output = surf->desktop.last_output; + current_completed_output = surf->current_completed_output; + + if (surf->remote.output) + surf->hidden_layer_output = surf->remote.output; + else + surf->hidden_layer_output = desktop_last_output; + assert(surf->hidden_layer_output); + + if (ivi_surface_count_one(current_completed_output, IVI_SURFACE_ROLE_REMOTE) || + ivi_surface_count_one(current_completed_output, IVI_SURFACE_ROLE_DESKTOP)) { + if (!current_completed_output->background) + insert_black_curtain(current_completed_output); + } else { + ivi_layout_deactivate(ivi, app_id); + } + + /* update the remote output */ + surf->remote.output = ioutput; + + if (surf->role != IVI_SURFACE_ROLE_REMOTE) { + wl_list_remove(&surf->link); + wl_list_init(&surf->link); + + surf->role = IVI_SURFACE_ROLE_NONE; + ivi_set_desktop_surface_remote(surf); + } + + shell_send_app_on_output(ivi, app_id, woutput->name); +} + +static void +shell_set_app_position(struct wl_client *client, struct wl_resource *res, + const char *app_id, int32_t x, int32_t y) +{ + struct weston_coord_global pos; + struct ivi_compositor *ivi = wl_resource_get_user_data(res); + struct ivi_surface *surf = ivi_find_app(ivi, app_id); + + if (!surf || !app_id || surf->role != IVI_SURFACE_ROLE_POPUP) + return; + + pos.c.x = x; + pos.c.y = y; + weston_view_set_position(surf->view, pos); + weston_compositor_schedule_repaint(ivi->compositor); +} + +static void +shell_set_app_scale(struct wl_client *client, struct wl_resource *res, + const char *app_id, int32_t width, int32_t height) +{ + + struct ivi_compositor *ivi = wl_resource_get_user_data(res); + struct ivi_surface *surf = ivi_find_app(ivi, app_id); + + if (!surf || !app_id || surf->role != IVI_SURFACE_ROLE_POPUP) + return; + + weston_desktop_surface_set_size(surf->dsurface, width, height); + weston_compositor_schedule_repaint(ivi->compositor); +} + +static void +_ivi_set_pending_desktop_surface_split(struct wl_resource *output, + const char *app_id, uint32_t orientation) +{ + weston_log("%s() added split surface for app_id '%s' with " + "orientation %d to pending\n", __func__, app_id, orientation); + + struct weston_head *head = weston_head_from_resource(output); + struct weston_output *woutput = weston_head_get_output(head); + struct ivi_output *ivi_output = to_ivi_output(woutput); + + struct pending_app_tile *app_tile = zalloc(sizeof(*app_tile)); + + app_tile->base.app_id = strdup(app_id); + app_tile->base.ioutput = ivi_output; + app_tile->base.role = IVI_SURFACE_ROLE_TILE; + + app_tile->orientation = orientation; + wl_list_insert(&ivi_output->ivi->pending_apps, &app_tile->base.link); +} + + +const char * +split_orientation_to_string(uint32_t orientation) +{ + switch (orientation) { + case AGL_SHELL_TILE_ORIENTATION_LEFT: + return "tile_left"; + break; + case AGL_SHELL_TILE_ORIENTATION_RIGHT: + return "tile_right"; + break; + case AGL_SHELL_TILE_ORIENTATION_TOP: + return "title_top"; + break; + case AGL_SHELL_TILE_ORIENTATION_BOTTOM: + return "tile_bottom"; + break; + default: + return "none"; + } +} + +static uint32_t +reverse_orientation(uint32_t orientation) +{ + + switch (orientation) { + case AGL_SHELL_TILE_ORIENTATION_LEFT: + return AGL_SHELL_TILE_ORIENTATION_RIGHT; + break; + case AGL_SHELL_TILE_ORIENTATION_RIGHT: + return AGL_SHELL_TILE_ORIENTATION_LEFT; + break; + case AGL_SHELL_TILE_ORIENTATION_TOP: + return AGL_SHELL_TILE_ORIENTATION_BOTTOM; + break; + case AGL_SHELL_TILE_ORIENTATION_BOTTOM: + return AGL_SHELL_TILE_ORIENTATION_TOP; + break; + default: + return AGL_SHELL_TILE_ORIENTATION_NONE; + } +} + +void +_ivi_set_shell_surface_split(struct ivi_surface *surface, struct ivi_output *ioutput, + uint32_t orientation, uint32_t width, int32_t sticky, + bool to_activate) +{ + struct ivi_compositor *ivi = surface->ivi; + struct weston_view *ev = surface->view; + struct weston_geometry geom = {}; + struct ivi_output *output = NULL; + struct weston_coord_global pos; + + int new_width, new_height; + int x, y; + + geom = weston_desktop_surface_get_geometry(surface->dsurface); + output = ivi_layout_get_output_from_surface(surface); + + if (!output) + output = ioutput; + + // if we don't supply a width we automatically default to doing a half + // split, each window taking half of the current output + switch (orientation) { + case AGL_SHELL_TILE_ORIENTATION_LEFT: + case AGL_SHELL_TILE_ORIENTATION_RIGHT: + if (width == 0) { + new_width = output->area.width / 2; + new_height = output->area.height; + } else { + new_width = width; + new_height = output->area.height; + } + break; + case AGL_SHELL_TILE_ORIENTATION_TOP: + case AGL_SHELL_TILE_ORIENTATION_BOTTOM: + if (width == 0) { + new_width = output->area.width; + new_height = output->area.height / 2; + } else { + new_width = output->area.width; + new_height = width; + } + break; + case AGL_SHELL_TILE_ORIENTATION_NONE: + /* use the current_completed_output because the sticky window + * might have changed the output area */ + new_width = surface->current_completed_output->area_activation.width; + new_height = surface->current_completed_output->area_activation.height; + + if (new_width != output->area.width) + output->area.width = new_width; + + if (new_height != output->area.height) + output->area.height = new_height; + + weston_log("Adjusting activation area " + "to %dX%d\n", output->area.width, output->area.height); + + if (surface->sticky) { + surface->sticky = 0; + weston_log("Resetting sticky window\n"); + } + + surface->role = surface->prev_role; + weston_log("Resetting tile role to previous role\n"); + break; + default: + /* nothing */ + assert(!"Invalid orientation passed"); + + } + + x = output->area.x - geom.x; + y = output->area.y - geom.y; + + if (orientation == AGL_SHELL_TILE_ORIENTATION_RIGHT) + x += output->area.width - new_width; + else if (orientation == AGL_SHELL_TILE_ORIENTATION_BOTTOM) + y += output->area.height - new_height; + + + if (to_activate) { + struct ivi_shell_seat *ivi_seat = NULL; + struct weston_seat *wseat = get_ivi_shell_weston_first_seat(ivi); + + if (wseat) + ivi_seat = get_ivi_shell_seat(wseat); + + if (!weston_view_is_mapped(ev)) + weston_view_update_transform(ev); + else + weston_layer_entry_remove(&ev->layer_link); + + + // mark view as mapped + ev->is_mapped = true; + ev->surface->is_mapped = true; + surface->mapped = true; + + // update older/new active surface + output->previous_active = output->active; + output->active = surface; + + // add to the layer and inflict damage + weston_view_set_output(ev, output->output); + weston_layer_entry_insert(&ivi->normal.view_list, &ev->layer_link); + weston_view_geometry_dirty(ev); + weston_surface_damage(ev->surface); + + // handle input / keyboard + if (ivi_seat) + ivi_shell_activate_surface(surface, ivi_seat, WESTON_ACTIVATE_FLAG_NONE); + } + + pos.c.x = x; + pos.c.y = y; + + weston_view_set_position(surface->view, pos); + weston_desktop_surface_set_size(surface->dsurface, new_width, new_height); + weston_desktop_surface_set_orientation(surface->dsurface, orientation); + surface->orientation = orientation; + + weston_compositor_schedule_repaint(ivi->compositor); + + if (sticky) + surface->sticky = sticky; + + if (orientation != AGL_SHELL_TILE_ORIENTATION_NONE) { + surface->prev_role = surface->role; + surface->role = IVI_SURFACE_ROLE_TILE; + weston_log("Found split orientation different that none, " + "setting surface role to orientation tile\n"); + } + + if (surface->sticky) { + if (orientation == AGL_SHELL_TILE_ORIENTATION_LEFT || + orientation == AGL_SHELL_TILE_ORIENTATION_RIGHT) + output->area.width -= new_width; + + if (orientation == AGL_SHELL_TILE_ORIENTATION_TOP || + orientation == AGL_SHELL_TILE_ORIENTATION_BOTTOM) + output->area.height -= new_height; + + weston_log("Found sticky window, adjusting activation area " + "to %dX%d\n", output->area.width, output->area.height); + } +} + +static int +shell_ivi_surf_count_split_surfaces(struct ivi_compositor *ivi) +{ + int count = 0; + struct ivi_surface *surf; + + wl_list_for_each(surf, &ivi->surfaces, link) { + if (surf->orientation > AGL_SHELL_TILE_ORIENTATION_NONE) + count++; + } + + return count; +} + + +static +void shell_set_app_split(struct wl_client *client, struct wl_resource *res, + const char *app_id, uint32_t orientation, int32_t width, + int32_t sticky, struct wl_resource *output_res) +{ + struct ivi_surface *surf; + struct ivi_compositor *ivi = wl_resource_get_user_data(res); + + struct weston_head *head = weston_head_from_resource(output_res); + struct weston_output *woutput = weston_head_get_output(head); + struct ivi_output *output = to_ivi_output(woutput); + + if (!app_id) + return; + + if (shell_ivi_surf_count_split_surfaces(ivi) > 2) { + weston_log("Found more than two split surfaces in tile orientation.\n"); + return; + } + + /* add it as pending until */ + surf = ivi_find_app(ivi, app_id); + if (!surf) { + _ivi_set_pending_desktop_surface_split(output_res, app_id, orientation); + return; + } + + if (output->previous_active && output->background != output->previous_active) { + int width_prev_app = 0; + struct weston_view *ev = output->previous_active->view; + const char *prev_app_id = + weston_desktop_surface_get_app_id(output->previous_active->dsurface); + + if (orientation != AGL_SHELL_TILE_ORIENTATION_NONE) { + if (!weston_view_is_mapped(ev)) + weston_view_update_transform(ev); + else + weston_layer_entry_remove(&ev->layer_link); + + ev->is_mapped = true; + ev->surface->is_mapped = true; + output->previous_active->mapped = true; + + weston_view_set_output(ev, woutput); + weston_layer_entry_insert(&ivi->normal.view_list, + &ev->layer_link); + } else { + ev->is_mapped = false; + ev->surface->is_mapped = false; + + weston_layer_entry_remove(&ev->layer_link); + + weston_view_geometry_dirty(ev); + weston_surface_damage(ev->surface); + } + + /* a 0 width means we have no explicit width set-up */ + if (width > 0) { + if (orientation == AGL_SHELL_TILE_ORIENTATION_TOP || + orientation == AGL_SHELL_TILE_ORIENTATION_BOTTOM) + width_prev_app = output->area.height - width; + else + width_prev_app = output->area.width - width; + } + + weston_log("Setting previous application '%s' to orientation '%s' width %d, not sticky\n", + prev_app_id, split_orientation_to_string(reverse_orientation(orientation)), + width_prev_app); + + _ivi_set_shell_surface_split(output->previous_active, NULL, + reverse_orientation(orientation), + width_prev_app, false, false); + + if (orientation == AGL_SHELL_TILE_ORIENTATION_NONE && + output->active == surf) { + output->active = output->previous_active; + } + } + + weston_log("Setting application '%s' to orientation '%s' width %d, %s\n", + app_id, split_orientation_to_string(orientation), + width, sticky == 1 ? "sticky" : "not sticky"); + _ivi_set_shell_surface_split(surf, NULL, orientation, width, sticky, false); +} + static void shell_ext_destroy(struct wl_client *client, struct wl_resource *res) { + struct ivi_compositor *ivi = wl_resource_get_user_data(res); + + ivi->shell_client_ext.doas_requested = false; wl_resource_destroy(res); } @@ -1625,8 +2111,17 @@ shell_ext_doas(struct wl_client *client, struct wl_resource *res) struct ivi_compositor *ivi = wl_resource_get_user_data(res); ivi->shell_client_ext.doas_requested = true; - agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource, - AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS); + + if (ivi->shell_client_ext.resource && ivi->shell_client.resource) { + ivi->shell_client_ext.doas_requested_pending_bind = true; + + agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource, + AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS); + } else { + agl_shell_ext_send_doas_done(ivi->shell_client_ext.resource, + AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_FAILED); + } + } static const struct agl_shell_interface agl_shell_implementation = { @@ -1639,6 +2134,11 @@ static const struct agl_shell_interface agl_shell_implementation = { .deactivate_app = shell_new_deactivate_app, .set_app_float = shell_set_app_float, .set_app_normal = shell_set_app_normal, + .set_app_fullscreen = shell_set_app_fullscreen, + .set_app_output = shell_set_app_output, + .set_app_position = shell_set_app_position, + .set_app_scale = shell_set_app_scale, + .set_app_split = shell_set_app_split, }; static const struct agl_shell_ext_interface agl_shell_ext_implementation = { @@ -1742,18 +2242,20 @@ unbind_agl_shell(struct wl_resource *resource) } wl_list_for_each(output, &ivi->outputs, link) { - struct weston_geometry area = {}; /* reset the active surf if there's one present */ if (output->active) { + struct weston_geometry area = {}; + output->active->view->is_mapped = false; output->active->view->surface->is_mapped = false; weston_layer_entry_remove(&output->active->view->layer_link); output->active = NULL; + + output->area_activation = area; } - output->area_activation = area; insert_black_curtain(output); } @@ -1772,6 +2274,7 @@ unbind_agl_shell(struct wl_resource *resource) ivi->shell_client.ready = false; ivi->shell_client.resource = NULL; + ivi->shell_client.resource_ext = NULL; ivi->shell_client.client = NULL; } @@ -1781,6 +2284,8 @@ unbind_agl_shell_ext(struct wl_resource *resource) struct ivi_compositor *ivi = wl_resource_get_user_data(resource); ivi->shell_client_ext.resource = NULL; + ivi->shell_client.resource_ext = NULL; + ivi->shell_client_ext.doas_requested = false; } static void @@ -1807,54 +2312,55 @@ bind_agl_shell(struct wl_client *client, return; } - if (ivi->shell_client.resource) { - if (wl_resource_get_version(resource) == 1) { - wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "agl_shell has already been bound"); - return; - } - - if (ivi->shell_client_ext.resource && - ivi->shell_client_ext.doas_requested) { - - /* reset status in case client-ext doesn't send an - * explicit agl_shell_destroy request, see - * shell_destroy() */ - if (ivi->shell_client.status == BOUND_FAILED) - ivi->shell_client.status = BOUND_OK; + if (ivi->shell_client.resource && wl_resource_get_version(resource) == 1) { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "agl_shell has already been bound (version 1)"); + wl_resource_destroy(resource); + return; + } - wl_resource_set_implementation(resource, &agl_shell_implementation, - ivi, NULL); - ivi->shell_client.resource_ext = resource; + // for agl_shell client proxy + if (ivi->shell_client.resource && + ivi->shell_client_ext.doas_requested_pending_bind) { - ivi->shell_client_ext.status = BOUND_OK; - agl_shell_send_bound_ok(ivi->shell_client.resource_ext); + ivi->shell_client_ext.doas_requested_pending_bind = false; - return; - } else { - wl_resource_set_implementation(resource, &agl_shell_implementation, - ivi, NULL); - agl_shell_send_bound_fail(resource); - ivi->shell_client.status = BOUND_FAILED; + // if there's one connected + if (ivi->shell_client.resource_ext) { + ivi->shell_client_ext.status = BOUND_FAILED; + agl_shell_send_bound_fail(ivi->shell_client.resource_ext); + wl_resource_destroy(resource); return; } + + wl_resource_set_implementation(resource, &agl_shell_implementation, + ivi, NULL); + ivi->shell_client.resource_ext = resource; + ivi->shell_client_ext.status = BOUND_OK; + agl_shell_send_bound_ok(ivi->shell_client.resource_ext); + return; + } + + + // if we already have an agl_shell client + if (ivi->shell_client.resource) { + agl_shell_send_bound_fail(resource); + ivi->shell_client.status = BOUND_FAILED; + wl_resource_destroy(resource); + return; } + // default agl_shell client + wl_resource_set_implementation(resource, &agl_shell_implementation, + ivi, unbind_agl_shell); + ivi->shell_client.resource = resource; if (wl_resource_get_version(resource) >= AGL_SHELL_BOUND_OK_SINCE_VERSION) { - wl_resource_set_implementation(resource, &agl_shell_implementation, - ivi, unbind_agl_shell); - ivi->shell_client.resource = resource; /* if we land here we'll have BOUND_OK by default, but still do the assignment */ ivi->shell_client.status = BOUND_OK; agl_shell_send_bound_ok(ivi->shell_client.resource); - } else { - /* fallback for just version 1 of the protocol */ - wl_resource_set_implementation(resource, &agl_shell_implementation, - ivi, unbind_agl_shell); - ivi->shell_client.resource = resource; } } @@ -1938,7 +2444,7 @@ int ivi_shell_create_global(struct ivi_compositor *ivi) { ivi->agl_shell = wl_global_create(ivi->compositor->wl_display, - &agl_shell_interface, 6, + &agl_shell_interface, 11, ivi, bind_agl_shell); if (!ivi->agl_shell) { weston_log("Failed to create wayland global.\n");