From 82681571cf2407ed61bd1d29065583ddd4c2e525 Mon Sep 17 00:00:00 2001 From: Quentin Glidic Date: Sat, 17 Dec 2016 13:40:51 +0100 Subject: [PATCH] libweston: Position layers in an absolute way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, layers’ order depends on the module loading order and it does not survive runtime modifications (like shell locking/unlocking). With this patch, modules can safely add their own layer at the expected position in the stack, with runtime persistence. v4 Reviewed-by: Giulio Camuffo Signed-off-by: Quentin Glidic Acked-by: Daniel Stone [Pekka: fix three whitespace issues] Signed-off-by: Pekka Paalanen --- desktop-shell/input-panel.c | 6 +-- desktop-shell/shell.c | 79 +++++++++++++++-------------- fullscreen-shell/fullscreen-shell.c | 4 +- ivi-shell/input-panel-ivi.c | 6 +-- ivi-shell/ivi-layout.c | 4 +- ivi-shell/ivi-shell.c | 2 +- libweston-desktop/xwayland.c | 6 ++- libweston/compositor.c | 62 ++++++++++++++++++++-- libweston/compositor.h | 72 ++++++++++++++++++++++++-- tests/weston-test.c | 3 +- 10 files changed, 187 insertions(+), 57 deletions(-) diff --git a/desktop-shell/input-panel.c b/desktop-shell/input-panel.c index 58a4cd05..40a4092e 100644 --- a/desktop-shell/input-panel.c +++ b/desktop-shell/input-panel.c @@ -115,8 +115,8 @@ show_input_panels(struct wl_listener *listener, void *data) shell->showing_input_panels = true; if (!shell->locked) - wl_list_insert(&shell->compositor->cursor_layer.link, - &shell->input_panel_layer.link); + weston_layer_set_position(&shell->input_panel_layer, + WESTON_LAYER_POSITION_TOP_UI); wl_list_for_each_safe(ipsurf, next, &shell->input_panel.surfaces, link) { @@ -141,7 +141,7 @@ hide_input_panels(struct wl_listener *listener, void *data) shell->showing_input_panels = false; if (!shell->locked) - wl_list_remove(&shell->input_panel_layer.link); + weston_layer_unset_position(&shell->input_panel_layer); wl_list_for_each_safe(view, next, &shell->input_panel_layer.view_list.link, diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index ce4b8704..1b182110 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -892,13 +892,13 @@ seat_destroyed(struct wl_listener *listener, void *data) } static struct workspace * -workspace_create(void) +workspace_create(struct desktop_shell *shell) { struct workspace *ws = malloc(sizeof *ws); if (ws == NULL) return NULL; - weston_layer_init(&ws->layer, NULL); + weston_layer_init(&ws->layer, shell->compositor); wl_list_init(&ws->focus_list); wl_list_init(&ws->seat_destroyed_listener.link); @@ -937,7 +937,7 @@ activate_workspace(struct desktop_shell *shell, unsigned int index) struct workspace *ws; ws = get_workspace(shell, index); - wl_list_insert(&shell->panel_layer.link, &ws->layer.link); + weston_layer_set_position(&ws->layer, WESTON_LAYER_POSITION_NORMAL); shell->workspaces.current = index; } @@ -1018,6 +1018,9 @@ reverse_workspace_change_animation(struct desktop_shell *shell, shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir; shell->workspaces.anim_timestamp = 0; + weston_layer_set_position(&to->layer, WESTON_LAYER_POSITION_NORMAL); + weston_layer_set_position(&from->layer, WESTON_LAYER_POSITION_NORMAL - 1); + weston_compositor_schedule_repaint(shell->compositor); } @@ -1065,7 +1068,7 @@ finish_workspace_change_animation(struct desktop_shell *shell, workspace_deactivate_transforms(to); shell->workspaces.anim_to = NULL; - wl_list_remove(&shell->workspaces.anim_from->layer.link); + weston_layer_unset_position(&shell->workspaces.anim_from->layer); } static void @@ -1147,7 +1150,8 @@ animate_workspace_change(struct desktop_shell *shell, wl_list_insert(&output->animation_list, &shell->workspaces.animation.link); - wl_list_insert(from->layer.link.prev, &to->layer.link); + weston_layer_set_position(&to->layer, WESTON_LAYER_POSITION_NORMAL); + weston_layer_set_position(&from->layer, WESTON_LAYER_POSITION_NORMAL - 1); workspace_translate_in(to, 0); @@ -1161,8 +1165,8 @@ update_workspace(struct desktop_shell *shell, unsigned int index, struct workspace *from, struct workspace *to) { shell->workspaces.current = index; - wl_list_insert(&from->layer.link, &to->layer.link); - wl_list_remove(&from->layer.link); + weston_layer_set_position(&to->layer, WESTON_LAYER_POSITION_NORMAL); + weston_layer_unset_position(&from->layer); } static void @@ -1286,9 +1290,6 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell, if (shell->workspaces.anim_from == to && shell->workspaces.anim_to == from) { - wl_list_remove(&to->layer.link); - wl_list_insert(from->layer.link.prev, &to->layer.link); - reverse_workspace_change_animation(shell, index, from, to); return; @@ -3064,20 +3065,16 @@ resume_desktop(struct desktop_shell *shell) { struct workspace *ws = get_current_workspace(shell); - wl_list_remove(&shell->lock_layer.link); - if (shell->showing_input_panels) { - wl_list_insert(&shell->compositor->cursor_layer.link, - &shell->input_panel_layer.link); - wl_list_insert(&shell->input_panel_layer.link, - &shell->fullscreen_layer.link); - } else { - wl_list_insert(&shell->compositor->cursor_layer.link, - &shell->fullscreen_layer.link); - } - wl_list_insert(&shell->fullscreen_layer.link, - &shell->panel_layer.link); - wl_list_insert(&shell->panel_layer.link, - &ws->layer.link), + weston_layer_unset_position(&shell->lock_layer); + + if (shell->showing_input_panels) + weston_layer_set_position(&shell->input_panel_layer, + WESTON_LAYER_POSITION_TOP_UI); + weston_layer_set_position(&shell->fullscreen_layer, + WESTON_LAYER_POSITION_FULLSCREEN); + weston_layer_set_position(&shell->panel_layer, + WESTON_LAYER_POSITION_UI); + weston_layer_set_position(&ws->layer, WESTON_LAYER_POSITION_NORMAL); restore_focus_state(shell, get_current_workspace(shell)); @@ -3757,13 +3754,14 @@ lock(struct desktop_shell *shell) * toplevel layers. This way nothing else can show or receive * input events while we are locked. */ - wl_list_remove(&shell->panel_layer.link); - wl_list_remove(&shell->fullscreen_layer.link); + weston_layer_unset_position(&shell->panel_layer); + weston_layer_unset_position(&shell->fullscreen_layer); if (shell->showing_input_panels) - wl_list_remove(&shell->input_panel_layer.link); - wl_list_remove(&ws->layer.link); - wl_list_insert(&shell->compositor->cursor_layer.link, - &shell->lock_layer.link); + weston_layer_unset_position(&shell->input_panel_layer); + weston_layer_unset_position(&ws->layer); + + weston_layer_set_position(&shell->lock_layer, + WESTON_LAYER_POSITION_LOCK); weston_compositor_sleep(shell->compositor); @@ -4900,11 +4898,18 @@ module_init(struct weston_compositor *ec, shell->transform_listener.notify = transform_handler; wl_signal_add(&ec->transform_signal, &shell->transform_listener); - weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link); - weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link); - weston_layer_init(&shell->background_layer, &shell->panel_layer.link); - weston_layer_init(&shell->lock_layer, NULL); - weston_layer_init(&shell->input_panel_layer, NULL); + weston_layer_init(&shell->fullscreen_layer, ec); + weston_layer_init(&shell->panel_layer, ec); + weston_layer_init(&shell->background_layer, ec); + weston_layer_init(&shell->lock_layer, ec); + weston_layer_init(&shell->input_panel_layer, ec); + + weston_layer_set_position(&shell->fullscreen_layer, + WESTON_LAYER_POSITION_FULLSCREEN); + weston_layer_set_position(&shell->panel_layer, + WESTON_LAYER_POSITION_UI); + weston_layer_set_position(&shell->background_layer, + WESTON_LAYER_POSITION_BACKGROUND); wl_array_init(&shell->workspaces.array); wl_list_init(&shell->workspaces.client_list); @@ -4926,13 +4931,13 @@ module_init(struct weston_compositor *ec, if (pws == NULL) return -1; - *pws = workspace_create(); + *pws = workspace_create(shell); if (*pws == NULL) return -1; } activate_workspace(shell, 0); - weston_layer_init(&shell->minimized_layer, NULL); + weston_layer_init(&shell->minimized_layer, ec); wl_list_init(&shell->workspaces.anim_sticky_list); wl_list_init(&shell->workspaces.animation.link); diff --git a/fullscreen-shell/fullscreen-shell.c b/fullscreen-shell/fullscreen-shell.c index b3083d88..daf024e5 100644 --- a/fullscreen-shell/fullscreen-shell.c +++ b/fullscreen-shell/fullscreen-shell.c @@ -912,7 +912,9 @@ module_init(struct weston_compositor *compositor, shell->client_destroyed.notify = client_destroyed; - weston_layer_init(&shell->layer, &compositor->cursor_layer.link); + weston_layer_init(&shell->layer, compositor); + weston_layer_set_position(&shell->layer, + WESTON_LAYER_POSITION_FULLSCREEN); wl_list_init(&shell->output_list); shell->output_created_listener.notify = output_created; diff --git a/ivi-shell/input-panel-ivi.c b/ivi-shell/input-panel-ivi.c index b0ab2baa..57d1cb29 100644 --- a/ivi-shell/input-panel-ivi.c +++ b/ivi-shell/input-panel-ivi.c @@ -116,8 +116,8 @@ show_input_panels(struct wl_listener *listener, void *data) shell->showing_input_panels = true; if (!shell->locked) - wl_list_insert(&shell->compositor->cursor_layer.link, - &shell->input_panel_layer.link); + weston_layer_set_position(&shell->input_panel_layer, + WESTON_LAYER_POSITION_TOP_UI); wl_list_for_each_safe(ipsurf, next, &shell->input_panel.surfaces, link) { @@ -142,7 +142,7 @@ hide_input_panels(struct wl_listener *listener, void *data) shell->showing_input_panels = false; if (!shell->locked) - wl_list_remove(&shell->input_panel_layer.link); + weston_layer_unset_position(&shell->input_panel_layer); wl_list_for_each_safe(view, next, &shell->input_panel_layer.view_list.link, diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c index 60d05c4f..ada7a7c6 100644 --- a/ivi-shell/ivi-layout.c +++ b/ivi-shell/ivi-layout.c @@ -2019,7 +2019,9 @@ ivi_layout_init_with_compositor(struct weston_compositor *ec) wl_signal_init(&layout->surface_notification.configure_changed); /* Add layout_layer at the last of weston_compositor.layer_list */ - weston_layer_init(&layout->layout_layer, ec->layer_list.prev); + weston_layer_init(&layout->layout_layer, ec); + weston_layer_set_position(&layout->layout_layer, + WESTON_LAYER_POSITION_NORMAL); create_screen(ec); diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c index 6bdd238c..c8d59820 100644 --- a/ivi-shell/ivi-shell.c +++ b/ivi-shell/ivi-shell.c @@ -392,7 +392,7 @@ init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell, wl_list_init(&shell->ivi_surface_list); - weston_layer_init(&shell->input_panel_layer, NULL); + weston_layer_init(&shell->input_panel_layer, compositor); if (setting->developermode) { weston_install_debug_key_binding(compositor, MODIFIER_SUPER); diff --git a/libweston-desktop/xwayland.c b/libweston-desktop/xwayland.c index 663734a8..1b19e224 100644 --- a/libweston-desktop/xwayland.c +++ b/libweston-desktop/xwayland.c @@ -386,7 +386,11 @@ weston_desktop_xwayland_init(struct weston_desktop *desktop) xwayland->desktop = desktop; xwayland->client = weston_desktop_client_create(desktop, NULL, NULL, NULL, NULL, 0, 0); - weston_layer_init(&xwayland->layer, &compositor->cursor_layer.link); + weston_layer_init(&xwayland->layer, compositor); + /* We put this layer on top of regular shell surfaces, but hopefully + * below any UI the shell would add */ + weston_layer_set_position(&xwayland->layer, + WESTON_LAYER_POSITION_NORMAL + 1); compositor->xwayland = xwayland; compositor->xwayland_interface = &weston_desktop_xwayland_interface; diff --git a/libweston/compositor.c b/libweston/compositor.c index f9175fbd..a5ce76d0 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -2422,14 +2422,62 @@ weston_layer_entry_remove(struct weston_layer_entry *entry) entry->layer = NULL; } + +/** Initialize the weston_layer struct. + * + * \param compositor The compositor instance + * \param layer The layer to initialize + */ WL_EXPORT void -weston_layer_init(struct weston_layer *layer, struct wl_list *below) +weston_layer_init(struct weston_layer *layer, + struct weston_compositor *compositor) { + layer->compositor = compositor; + wl_list_init(&layer->link); wl_list_init(&layer->view_list.link); layer->view_list.layer = layer; weston_layer_set_mask_infinite(layer); - if (below != NULL) - wl_list_insert(below, &layer->link); +} + +/** Sets the position of the layer in the layer list. The layer will be placed + * below any layer with the same position value, if any. + * This function is safe to call if the layer is already on the list, but the + * layer may be moved below other layers at the same position, if any. + * + * \param layer The layer to modify + * \param position The position the layer will be placed at + */ +WL_EXPORT void +weston_layer_set_position(struct weston_layer *layer, + enum weston_layer_position position) +{ + struct weston_layer *below; + + wl_list_remove(&layer->link); + + /* layer_list is ordered from top to bottom, the last layer being the + * background with the smallest position value */ + + layer->position = position; + wl_list_for_each_reverse(below, &layer->compositor->layer_list, link) { + if (below->position >= layer->position) { + wl_list_insert(&below->link, &layer->link); + return; + } + } + wl_list_insert(&layer->compositor->layer_list, &layer->link); +} + +/** Hide a layer by taking it off the layer list. + * This function is safe to call if the layer is not on the list. + * + * \param layer The layer to hide + */ +WL_EXPORT void +weston_layer_unset_position(struct weston_layer *layer) +{ + wl_list_remove(&layer->link); + wl_list_init(&layer->link); } WL_EXPORT void @@ -5036,8 +5084,12 @@ weston_compositor_create(struct wl_display *display, void *user_data) loop = wl_display_get_event_loop(ec->wl_display); ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec); - weston_layer_init(&ec->fade_layer, &ec->layer_list); - weston_layer_init(&ec->cursor_layer, &ec->fade_layer.link); + weston_layer_init(&ec->fade_layer, ec); + weston_layer_init(&ec->cursor_layer, ec); + + weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE); + weston_layer_set_position(&ec->cursor_layer, + WESTON_LAYER_POSITION_CURSOR); weston_compositor_add_debug_binding(ec, KEY_T, timeline_key_binding_handler, ec); diff --git a/libweston/compositor.h b/libweston/compositor.h index ce3d9abf..973d2ee0 100644 --- a/libweston/compositor.h +++ b/libweston/compositor.h @@ -632,10 +632,68 @@ struct weston_layer_entry { struct weston_layer *layer; }; +/** + * Higher value means higher in the stack. + * + * These values are based on well-known concepts in a classic desktop + * environment. Third-party modules based on libweston are encouraged to use + * them to integrate better with other projects. + * + * A fully integrated environment can use any value, based on these or not, + * at their discretion. + */ +enum weston_layer_position { + /* + * Special value to make the layer invisible and still rendered. + * This is used by compositors wanting e.g. minimized surfaces to still + * receive frame callbacks. + */ + WESTON_LAYER_POSITION_HIDDEN = 0x00000000, + + /* + * There should always be a background layer with a surface covering + * the visible area. + * + * If the compositor handles the background itself, it should use + * BACKGROUND. + * + * If the compositor supports runtime-loadable modules to set the + * background, it should put a solid color surface at (BACKGROUND - 1) + * and modules must use BACKGROUND. + */ + WESTON_LAYER_POSITION_BACKGROUND = 0x00000002, + + /* For "desktop widgets" and applications like conky. */ + WESTON_LAYER_POSITION_BOTTOM_UI = 0x30000000, + + /* For regular applications, only one layer should have this value + * to ensure proper stacking control. */ + WESTON_LAYER_POSITION_NORMAL = 0x50000000, + + /* For desktop UI, like panels. */ + WESTON_LAYER_POSITION_UI = 0x80000000, + + /* For fullscreen applications that should cover UI. */ + WESTON_LAYER_POSITION_FULLSCREEN = 0xb0000000, + + /* For special UI like on-screen keyboard that fullscreen applications + * will need. */ + WESTON_LAYER_POSITION_TOP_UI = 0xe0000000, + + /* For the lock surface. */ + WESTON_LAYER_POSITION_LOCK = 0xffff0000, + + /* Values reserved for libweston internal usage */ + WESTON_LAYER_POSITION_CURSOR = 0xfffffffe, + WESTON_LAYER_POSITION_FADE = 0xffffffff, +}; + struct weston_layer { - struct weston_layer_entry view_list; - struct wl_list link; + struct weston_compositor *compositor; + struct wl_list link; /* weston_compositor::layer_list */ + enum weston_layer_position position; pixman_box32_t mask; + struct weston_layer_entry view_list; }; struct weston_plane { @@ -773,7 +831,7 @@ struct weston_compositor { struct wl_list pending_output_list; struct wl_list output_list; struct wl_list seat_list; - struct wl_list layer_list; + struct wl_list layer_list; /* struct weston_layer::link */ struct wl_list view_list; /* struct weston_view::link */ struct wl_list plane_list; struct wl_list key_binding_list; @@ -1297,7 +1355,13 @@ weston_layer_entry_insert(struct weston_layer_entry *list, void weston_layer_entry_remove(struct weston_layer_entry *entry); void -weston_layer_init(struct weston_layer *layer, struct wl_list *below); +weston_layer_init(struct weston_layer *layer, + struct weston_compositor *compositor); +void +weston_layer_set_position(struct weston_layer *layer, + enum weston_layer_position position); +void +weston_layer_unset_position(struct weston_layer *layer); void weston_layer_set_mask(struct weston_layer *layer, int x, int y, int width, int height); diff --git a/tests/weston-test.c b/tests/weston-test.c index eec2c3c7..e4dd36f0 100644 --- a/tests/weston-test.c +++ b/tests/weston-test.c @@ -596,7 +596,8 @@ module_init(struct weston_compositor *ec, return -1; test->compositor = ec; - weston_layer_init(&test->layer, &ec->cursor_layer.link); + weston_layer_init(&test->layer, ec); + weston_layer_set_position(&test->layer, WESTON_LAYER_POSITION_CURSOR - 1); if (wl_global_create(ec->wl_display, &weston_test_interface, 1, test, bind_test) == NULL)