From: Scott Anderson Date: Tue, 10 Dec 2019 11:48:04 +0000 (+0000) Subject: src/: Add basic support for app switching X-Git-Tag: 9.0.0~14 X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=commitdiff_plain;h=2d7243208d3e455decd730e7e33ab2452b1a0508;p=src%2Fagl-compositor.git src/: Add basic support for app switching - adds a new request for agl-shell, 'activate_app', which allows to specify which application should switch to. With it, client shell commands which application to switch to. - ties the layout (panel and background initizatlon) bits into its own specific file Bug-AGL: SPEC-3117 Change-Id: I1b3d89ff77c0e0e439666227ef3319b2107406c0 Signed-off-by: Daniel Stone --- diff --git a/meson.build b/meson.build index a7e1bfc..08548f8 100644 --- a/meson.build +++ b/meson.build @@ -92,6 +92,7 @@ deps_libweston = [ srcs_agl_compositor = [ 'src/main.c', 'src/desktop.c', + 'src/layout.c', 'src/shell.c', 'shared/option-parser.c', 'shared/os-compatibility.c', diff --git a/protocol/agl-shell.xml b/protocol/agl-shell.xml index 59548e7..1096c64 100644 --- a/protocol/agl-shell.xml +++ b/protocol/agl-shell.xml @@ -96,5 +96,22 @@ + + + + Ask the compositor to make a toplevel to become the current/focused + window for window management purposes. + + See xdg_toplevel.set_app_id from the xdg-shell protocol for a + description of app_id. + + If multiple toplevels have the same app_id, the result is unspecified. + + XXX: Do we need feedback to say it didn't work? (e.g. client does + not exist) + + + + diff --git a/src/desktop.c b/src/desktop.c index fbeefec..ed6208f 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -69,18 +69,21 @@ desktop_surface_added(struct weston_desktop_surface *dsurface, void *userdata) return; } + surface->view = weston_desktop_surface_create_view(dsurface); + if (!surface->view) { + free(surface); + wl_client_post_no_memory(client); + return; + } + surface->ivi = ivi; surface->dsurface = dsurface; surface->role = IVI_SURFACE_ROLE_NONE; - surface->old_geom.width = -1; - surface->old_geom.height = -1; weston_desktop_surface_set_user_data(dsurface, surface); if (ivi->shell_client.ready) { ivi_set_desktop_surface(surface); - - ivi_reflow_outputs(ivi); } else { /* * We delay creating "normal" desktop surfaces until later, to @@ -98,112 +101,17 @@ desktop_surface_removed(struct weston_desktop_surface *dsurface, void *userdata) weston_desktop_surface_get_user_data(dsurface); struct weston_surface *wsurface = weston_desktop_surface_get_surface(dsurface); - struct ivi_compositor *ivi = surface->ivi; /* TODO */ if (surface->role != IVI_SURFACE_ROLE_DESKTOP) return; if (weston_surface_is_mapped(wsurface)) { - weston_desktop_surface_unlink_view(surface->desktop.view); - weston_view_destroy(surface->desktop.view); + weston_desktop_surface_unlink_view(surface->view); + weston_view_destroy(surface->view); wl_list_remove(&surface->link); } free(surface); - - ivi_reflow_outputs(ivi); -} - -static void -surface_committed(struct ivi_surface *surface) -{ - struct ivi_compositor *ivi = surface->ivi; - struct weston_desktop_surface *dsurface = surface->dsurface; - struct weston_geometry geom, old_geom; - - old_geom = surface->old_geom; - geom = weston_desktop_surface_get_geometry(dsurface); - - surface->old_geom = geom; - - if (geom.width != old_geom.width || geom.height != old_geom.height) { - ivi_reflow_outputs(ivi); - } - - //wl_list_insert(&ivi->surfaces, &surface->link); -} - -static void -background_committed(struct ivi_surface *surface) -{ - struct ivi_compositor *ivi = surface->ivi; - struct ivi_output *output = surface->bg.output; - struct weston_output *woutput = output->output; - struct weston_desktop_surface *dsurface = surface->dsurface; - struct weston_surface *wsurface = - weston_desktop_surface_get_surface(dsurface); - - if (wsurface->is_mapped) - return; - - surface->bg.view = weston_desktop_surface_create_view(dsurface); - - weston_view_set_output(surface->bg.view, woutput); - weston_view_set_position(surface->bg.view, - woutput->x, - woutput->y); - weston_layer_entry_insert(&ivi->background.view_list, - &surface->bg.view->layer_link); - - weston_view_update_transform(surface->bg.view); - weston_view_schedule_repaint(surface->bg.view); - - wsurface->is_mapped = true; -} - -static void -panel_committed(struct ivi_surface *surface) -{ - struct ivi_compositor *ivi = surface->ivi; - struct ivi_output *output = surface->bg.output; - struct weston_output *woutput = output->output; - struct weston_desktop_surface *dsurface = surface->dsurface; - struct weston_surface *wsurface = - weston_desktop_surface_get_surface(dsurface); - struct weston_geometry geom; - int32_t x = woutput->x; - int32_t y = woutput->y; - - if (wsurface->is_mapped) - return; - - surface->panel.view = weston_desktop_surface_create_view(dsurface); - - geom = weston_desktop_surface_get_geometry(dsurface); - switch (surface->panel.edge) { - case AGL_SHELL_EDGE_TOP: - /* Do nothing */ - break; - case AGL_SHELL_EDGE_BOTTOM: - y += woutput->height - geom.height; - break; - case AGL_SHELL_EDGE_LEFT: - /* Do nothing */ - break; - case AGL_SHELL_EDGE_RIGHT: - x += woutput->width - geom.width; - break; - } - - weston_view_set_output(surface->panel.view, woutput); - weston_view_set_position(surface->panel.view, x, y); - weston_layer_entry_insert(&ivi->normal.view_list, - &surface->panel.view->layer_link); - - weston_view_update_transform(surface->panel.view); - weston_view_schedule_repaint(surface->panel.view); - - wsurface->is_mapped = true; } static void @@ -212,22 +120,8 @@ desktop_committed(struct weston_desktop_surface *dsurface, { struct ivi_surface *surface = weston_desktop_surface_get_user_data(dsurface); - - weston_compositor_schedule_repaint(surface->ivi->compositor); - - switch (surface->role) { - case IVI_SURFACE_ROLE_NONE: - break; - case IVI_SURFACE_ROLE_DESKTOP: - surface_committed(surface); - break; - case IVI_SURFACE_ROLE_BACKGROUND: - background_committed(surface); - break; - case IVI_SURFACE_ROLE_PANEL: - panel_committed(surface); - break; - } + if (surface->role == IVI_SURFACE_ROLE_DESKTOP) + ivi_layout_desktop_committed(surface); } static void diff --git a/src/ivi-compositor.h b/src/ivi-compositor.h index 65e06ad..3765f65 100644 --- a/src/ivi-compositor.h +++ b/src/ivi-compositor.h @@ -68,18 +68,17 @@ struct ivi_compositor { } shell_client; struct wl_list outputs; /* ivi_output.link */ - struct wl_list surfaces; /* ivi_desktop_surface.link */ + struct wl_list surfaces; /* ivi_surface.link */ struct weston_desktop *desktop; struct wl_list pending_surfaces; + struct weston_layer hidden; struct weston_layer background; struct weston_layer normal; struct weston_layer panel; struct weston_layer fullscreen; - - struct wl_list shell_clients; /* ivi_shell_client.link */ }; struct ivi_surface; @@ -107,8 +106,7 @@ struct ivi_output { */ struct weston_geometry area; - //int32_t width; - //int32_t height; + struct ivi_surface *active; /* Temporary: only used during configuration */ size_t add_len; @@ -123,18 +121,16 @@ enum ivi_surface_role { }; struct ivi_desktop_surface { - struct weston_view *view; + struct ivi_output *pending_output; }; struct ivi_background_surface { struct ivi_output *output; - struct weston_view *view; }; struct ivi_panel_surface { struct ivi_output *output; enum agl_shell_edge edge; - struct weston_view *view; }; enum ivi_surface_flags { @@ -146,6 +142,7 @@ enum ivi_surface_flags { struct ivi_surface { struct ivi_compositor *ivi; struct weston_desktop_surface *dsurface; + struct weston_view *view; struct wl_list link; @@ -155,8 +152,6 @@ struct ivi_surface { int32_t width, height; } pending; - struct weston_geometry old_geom; - enum ivi_surface_role role; union { struct ivi_desktop_surface desktop; @@ -217,4 +212,13 @@ ivi_layout_set_position(struct ivi_surface *surface, void ivi_layout_commit(struct ivi_compositor *ivi); +void +ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output); + +void +ivi_layout_activate(struct ivi_output *output, const char *app_id); + +void +ivi_layout_desktop_committed(struct ivi_surface *surf); + #endif diff --git a/src/layout.c b/src/layout.c new file mode 100644 index 0000000..1088bd5 --- /dev/null +++ b/src/layout.c @@ -0,0 +1,254 @@ +/* + * Copyright © 2019 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ivi-compositor.h" + +#include +#include + +#include +#include + +static void +ivi_background_init(struct ivi_compositor *ivi, struct ivi_output *output) +{ + struct weston_output *woutput = output->output; + struct ivi_surface *bg = output->background; + struct weston_view *view; + + if (!bg) { + weston_log("WARNING: Output does not have a background\n"); + return; + } + + assert(bg->role == IVI_SURFACE_ROLE_BACKGROUND); + + view = bg->view; + + weston_view_set_output(view, woutput); + weston_view_set_position(view, woutput->x, woutput->y); + + view->is_mapped = true; + view->surface->is_mapped = true; + + weston_layer_entry_insert(&ivi->background.view_list, &view->layer_link); +} + +static void +ivi_panel_init(struct ivi_compositor *ivi, struct ivi_output *output, + struct ivi_surface *panel) +{ + struct weston_output *woutput = output->output; + struct weston_desktop_surface *dsurface; + struct weston_view *view; + struct weston_geometry geom; + int x = woutput->x; + int y = woutput->y; + + if (!panel) + return; + + assert(panel->role == IVI_SURFACE_ROLE_PANEL); + dsurface = panel->dsurface; + view = panel->view; + geom = weston_desktop_surface_get_geometry(dsurface); + + switch (panel->panel.edge) { + case AGL_SHELL_EDGE_TOP: + output->area.y += geom.height; + output->area.height -= geom.height; + break; + case AGL_SHELL_EDGE_BOTTOM: + y += woutput->height - geom.height; + output->area.height -= geom.height; + break; + case AGL_SHELL_EDGE_LEFT: + output->area.x += geom.width; + output->area.width -= geom.width; + break; + case AGL_SHELL_EDGE_RIGHT: + x += woutput->width - geom.width; + output->area.width -= geom.width; + break; + } + + x -= geom.x; + y -= geom.y; + + weston_view_set_output(view, woutput); + weston_view_set_position(view, x, y); + + view->is_mapped = true; + view->surface->is_mapped = true; + + weston_layer_entry_insert(&ivi->panel.view_list, &view->layer_link); +} + +/* + * Initializes all static parts of the layout, i.e. the background and panels. + */ +void +ivi_layout_init(struct ivi_compositor *ivi, struct ivi_output *output) +{ + ivi_background_init(ivi, output); + + output->area.x = 0; + output->area.y = 0; + output->area.width = output->output->width; + output->area.height = output->output->height; + + ivi_panel_init(ivi, output, output->top); + ivi_panel_init(ivi, output, output->bottom); + ivi_panel_init(ivi, output, output->left); + ivi_panel_init(ivi, output, output->right); + + weston_compositor_schedule_repaint(ivi->compositor); + + weston_log("Usable area: %dx%d+%d,%d\n", + output->area.width, output->area.height, + output->area.x, output->area.y); +} + +static struct ivi_surface * +ivi_find_app(struct ivi_compositor *ivi, const char *app_id) +{ + struct ivi_surface *surf; + const char *id; + + wl_list_for_each(surf, &ivi->surfaces, link) { + id = weston_desktop_surface_get_app_id(surf->dsurface); + if (id && strcmp(app_id, id) == 0) + return surf; + } + + return NULL; +} + +static void +ivi_layout_activate_complete(struct ivi_output *output, + struct ivi_surface *surf) +{ + struct ivi_compositor *ivi = output->ivi; + struct weston_output *woutput = output->output; + struct weston_view *view = surf->view; + + if (weston_view_is_mapped(view)) { + weston_layer_entry_remove(&view->layer_link); + } + + weston_view_set_output(view, woutput); + weston_view_set_position(view, + woutput->x + output->area.x, + woutput->y + output->area.y); + + view->is_mapped = true; + view->surface->is_mapped = true; + + if (output->active) { + output->active->view->is_mapped = false; + output->active->view->surface->is_mapped = false; + + weston_layer_entry_remove(&output->active->view->layer_link); + } + output->active = surf; + + weston_layer_entry_insert(&ivi->normal.view_list, &view->layer_link); + weston_view_update_transform(view); + + weston_view_schedule_repaint(view); + surf->desktop.pending_output = NULL; +} + +void +ivi_layout_desktop_committed(struct ivi_surface *surf) +{ + struct weston_desktop_surface *dsurf = surf->dsurface; + struct weston_geometry geom = weston_desktop_surface_get_geometry(dsurf); + struct ivi_output *output; + + assert(surf->role == IVI_SURFACE_ROLE_DESKTOP); + + output = surf->desktop.pending_output; + if (!output) + return; + + if (!weston_desktop_surface_get_maximized(dsurf) || + geom.width != output->area.width || + geom.height != output->area.height) + return; + + ivi_layout_activate_complete(output, surf); +} + +void +ivi_layout_activate(struct ivi_output *output, const char *app_id) +{ + struct ivi_compositor *ivi = output->ivi; + struct ivi_surface *surf; + struct weston_desktop_surface *dsurf; + struct weston_view *view; + struct weston_geometry geom; + + surf = ivi_find_app(ivi, app_id); + if (!surf) + return; + + weston_log("Found app_id %s\n", app_id); + + if (surf == output->active) + return; + + dsurf = surf->dsurface; + view = surf->view; + geom = weston_desktop_surface_get_geometry(dsurf); + + if (weston_desktop_surface_get_maximized(dsurf) && + geom.width == output->area.width && + geom.height == output->area.height) { + ivi_layout_activate_complete(output, surf); + return; + } + + weston_desktop_surface_set_maximized(dsurf, true); + weston_desktop_surface_set_size(dsurf, + output->area.width, + output->area.height); + + /* + * If the view isn't mapped, we put it onto the hidden layer so it will + * start receiving frame events, and will be able to act on our + * configure event. + */ + if (!weston_view_is_mapped(view)) { + view->is_mapped = true; + view->surface->is_mapped = true; + + weston_view_set_output(view, output->output); + weston_layer_entry_insert(&ivi->hidden.view_list, &view->layer_link); + weston_view_schedule_repaint(view); + } + + surf->desktop.pending_output = output; +} diff --git a/src/main.c b/src/main.c index 71a99ea..fd0006f 100644 --- a/src/main.c +++ b/src/main.c @@ -114,15 +114,6 @@ ivi_ensure_output(struct ivi_compositor *ivi, char *name, return output; } -static void -ivi_output_destroy(struct ivi_output *output) -{ - weston_output_destroy(output->output); - free(output->name); - wl_list_remove(&output->link); - free(output); -} - static int count_heads(struct weston_output *output) { @@ -421,7 +412,6 @@ head_disable(struct ivi_compositor *ivi, struct weston_head *head) weston_head_detach(head); if (count_heads(ivi_output->output) == 0) { - ivi_output_destroy(ivi_output); weston_output_disable(ivi_output->output); } } @@ -865,7 +855,7 @@ activate_binding(struct weston_seat *seat, struct ivi_surface *surface; surface = to_ivi_surface(main_surface); - if (!surface || surface->role != IVI_SURFACE_ROLE_DESKTOP) + if (!surface) return; weston_seat_set_keyboard_focus(seat, focus); @@ -938,14 +928,6 @@ static bool global_filter(const struct wl_client *client, const struct wl_global *global, void *data) { -#if 0 - struct ivi_compositor *ivi = data; - const struct wl_interface *iface = wl_global_get_interface(global); - - if (iface == &agl_shell_interface) - return client == ivi->shell_client.client; -#endif - return true; } @@ -1136,7 +1118,6 @@ int main(int argc, char *argv[]) wl_list_init(&ivi.outputs); wl_list_init(&ivi.surfaces); - wl_list_init(&ivi.shell_clients); wl_list_init(&ivi.pending_surfaces); /* Prevent any clients we spawn getting our stdin */ @@ -1184,25 +1165,12 @@ int main(int argc, char *argv[]) if (!signals[i]) goto error_signals; -#if 0 - log_ctx = weston_log_ctx_compositor_create(); - if (!log_ctx) { - weston_log("Failed to initialize weston debug framework.\n"); - goto error_signals; - } -#endif - ivi.compositor = weston_compositor_create(display, &ivi); if (!ivi.compositor) { weston_log("fatal: failed to create compositor.\n"); goto error_signals; } -#if 0 - if (debug_protocol) - weston_compositor_enable_debug_protocol(ivi.compositor); -#endif - if (compositor_init_config(ivi.compositor, ivi.config) < 0) goto error_compositor; diff --git a/src/shell.c b/src/shell.c index cac8fa2..67f6d88 100644 --- a/src/shell.c +++ b/src/shell.c @@ -49,133 +49,17 @@ ivi_set_desktop_surface(struct ivi_surface *surface) wl_list_insert(&surface->ivi->surfaces, &surface->link); } -/* TODO: Replace this with some callback or similar, to have - * adjustable window management policy. - */ -void -ivi_reflow_outputs(struct ivi_compositor *ivi) -{ - struct ivi_surface *surface; - struct ivi_output *output; - int i = 0; - - if (wl_list_empty(&ivi->outputs)) - return; - - output = wl_container_of(ivi->outputs.next, output, link); - - wl_list_for_each(surface, &ivi->surfaces, link) { - struct weston_desktop_surface *dsurface = surface->dsurface; - - int32_t w = output->area.width / 4; - int32_t h = output->area.height / 2; - int32_t x = output->output->x + output->area.x + w * (i % 4); - int32_t y = output->output->y + output->area.y + h * (i / 4); - - if (surface->old_geom.width == -1) { - weston_desktop_surface_set_size(dsurface, w, h); - continue; - } else { - ivi_layout_set_mapped(surface); - ivi_layout_set_position(surface, x, y, w, h); - } - - if (++i == 8) { - if (output->link.next == &ivi->outputs) - break; - - output = wl_container_of(output->link.next, - output, link); - i = 0; - } - } - - ivi_layout_commit(ivi); -} - -void -ivi_layout_set_mapped(struct ivi_surface *surface) -{ - surface->pending.flags |= IVI_SURFACE_PROP_MAP; -} - -void -ivi_layout_set_position(struct ivi_surface *surface, - int32_t x, int32_t y, - int32_t width, int32_t height) -{ - surface->pending.flags |= IVI_SURFACE_PROP_POSITION; - surface->pending.x = x; - surface->pending.y = y; - surface->pending.width = width; - surface->pending.height = height; -} - -void -ivi_layout_commit(struct ivi_compositor *ivi) -{ - struct ivi_surface *surface; - - wl_list_for_each(surface, &ivi->surfaces, link) { - struct weston_desktop_surface *dsurface = surface->dsurface; - struct weston_surface *wsurface = - weston_desktop_surface_get_surface(dsurface); - struct weston_geometry geom; - struct weston_view *view; - - /* - * TODO: Hoist view into ivi_struct. It doesn't need ot be part - * of the tagged union. - */ - switch (surface->role) { - case IVI_SURFACE_ROLE_DESKTOP: - view = surface->desktop.view; - break; - case IVI_SURFACE_ROLE_BACKGROUND: - view = surface->bg.view; - break; - case IVI_SURFACE_ROLE_PANEL: - view = surface->panel.view; - break; - default: - continue; - } - - if (surface->pending.flags & IVI_SURFACE_PROP_MAP) { - view = weston_desktop_surface_create_view(dsurface); - wsurface->is_mapped = true; - - surface->desktop.view = view; - weston_layer_entry_insert(&ivi->normal.view_list, - &view->layer_link); - weston_view_update_transform(view); - weston_view_set_mask_infinite(view); - weston_view_schedule_repaint(view); - } - - geom = weston_desktop_surface_get_geometry(dsurface); - - if (surface->pending.flags & IVI_SURFACE_PROP_POSITION) { - weston_desktop_surface_set_size(dsurface, - surface->pending.width, - surface->pending.height); - weston_view_set_position(view, - surface->pending.x - geom.x, - surface->pending.y - geom.y); - } - - surface->pending.flags = 0; - } -} - int ivi_shell_init(struct ivi_compositor *ivi) { + weston_layer_init(&ivi->hidden, ivi->compositor); weston_layer_init(&ivi->background, ivi->compositor); weston_layer_init(&ivi->normal, ivi->compositor); weston_layer_init(&ivi->panel, ivi->compositor); weston_layer_init(&ivi->fullscreen, ivi->compositor); + weston_layer_set_position(&ivi->hidden, + WESTON_LAYER_POSITION_HIDDEN); weston_layer_set_position(&ivi->background, WESTON_LAYER_POSITION_BACKGROUND); weston_layer_set_position(&ivi->normal, @@ -298,44 +182,7 @@ shell_ready(struct wl_client *client, struct wl_resource *shell_res) /* TODO: Create a black screen and remove it here */ wl_list_for_each(output, &ivi->outputs, link) { - struct weston_desktop_surface *dsurf; - struct weston_geometry geom; - - output->area.x = 0; - output->area.y = 0; - output->area.width = output->output->width; - output->area.height = output->output->height; - - if (output->top) { - dsurf = output->top->dsurface; - geom = weston_desktop_surface_get_geometry(dsurf); - - output->area.y += geom.height; - output->area.height -= geom.height; - } - if (output->bottom) { - dsurf = output->bottom->dsurface; - geom = weston_desktop_surface_get_geometry(dsurf); - - output->area.height -= geom.height; - } - if (output->left) { - dsurf = output->left->dsurface; - geom = weston_desktop_surface_get_geometry(dsurf); - - output->area.x += geom.width; - output->area.width -= geom.width; - } - if (output->right) { - dsurf = output->right->dsurface; - geom = weston_desktop_surface_get_geometry(dsurf); - - output->area.width -= geom.width; - } - - weston_log("Usable area: %dx%d+%d,%d\n", - output->area.width, output->area.height, - output->area.x, output->area.y); + ivi_layout_init(ivi, output); } wl_list_for_each_safe(surface, tmp, &ivi->pending_surfaces, link) { @@ -474,10 +321,24 @@ shell_set_panel(struct wl_client *client, weston_desktop_surface_set_size(dsurface, width, height); } +static void +shell_activate_app(struct wl_client *client, + struct wl_resource *shell_res, + const char *app_id, + struct wl_resource *output_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); + + ivi_layout_activate(output, app_id); +} + static const struct agl_shell_interface agl_shell_implementation = { .ready = shell_ready, .set_background = shell_set_background, .set_panel = shell_set_panel, + .activate_app = shell_activate_app, }; static void