X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fshell.c;h=16d924c2d9932108461fb4d608d57ec9d4a9c2c8;hb=e7ccf51adc37748d3ca000109d16d0495dc0a7e8;hp=2b6bd63f8e09dd9c64693a21f9001d70fd74f40e;hpb=ae3ef78cb1a01b690917eb8d93a3e68517a7a93d;p=src%2Fagl-compositor.git diff --git a/src/shell.c b/src/shell.c index 2b6bd63..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); @@ -1695,6 +1758,315 @@ 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) { @@ -1737,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 = { @@ -2042,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");