X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fshell.c;h=16d924c2d9932108461fb4d608d57ec9d4a9c2c8;hb=754636273ffc6b872d6fb194009c857e76e7cec1;hp=f5dc3e3458e022733b20ca61a23b572e221a4948;hpb=ca537df2c52990acf97fb1c42ec2d993c60eae2d;p=src%2Fagl-compositor.git diff --git a/src/shell.c b/src/shell.c index f5dc3e3..16d924c 100644 --- a/src/shell.c +++ b/src/shell.c @@ -49,6 +49,12 @@ 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) @@ -587,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) @@ -621,6 +645,45 @@ ivi_check_pending_desktop_surface(struct ivi_surface *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; + } + /* if we end up here means we have a regular desktop app and * try to activate it */ ivi_set_desktop_surface(surface); @@ -1108,8 +1171,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; } @@ -1165,8 +1228,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; } @@ -1230,7 +1293,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; } @@ -1622,9 +1685,8 @@ shell_set_app_output(struct wl_client *client, struct wl_resource *res, 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 = surf->desktop.last_output; - struct ivi_output *current_completed_output = - surf->current_completed_output; + struct ivi_output *desktop_last_output; + struct ivi_output *current_completed_output; if (!app_id || !ioutput) return; @@ -1636,6 +1698,9 @@ shell_set_app_output(struct wl_client *client, struct wl_resource *res, 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 @@ -1693,9 +1758,321 @@ shell_set_app_scale(struct wl_client *client, struct wl_resource *res, 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; + + 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); + } + + weston_view_set_position(surface->view, x, y); + 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); } @@ -1705,8 +2082,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 = { @@ -1723,6 +2109,7 @@ static const struct agl_shell_interface agl_shell_implementation = { .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 = { @@ -1858,6 +2245,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; } @@ -1867,6 +2255,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 @@ -1893,54 +2283,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; } } @@ -2024,7 +2415,7 @@ int ivi_shell_create_global(struct ivi_compositor *ivi) { ivi->agl_shell = wl_global_create(ivi->compositor->wl_display, - &agl_shell_interface, 10, + &agl_shell_interface, 11, ivi, bind_agl_shell); if (!ivi->agl_shell) { weston_log("Failed to create wayland global.\n");