[PATCH weston v5] libweston: Position layers in an absolute way

Quentin Glidic sardemff7+wayland at sardemff7.net
Sat Dec 17 12:40:51 UTC 2016


From: Quentin Glidic <sardemff7+git at sardemff7.net>

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.

Signed-off-by: Quentin Glidic <sardemff7+git at sardemff7.net>
---
v5:                                                   
    - Made set_position/unset_position safe (+ doc)   
    - Commented weston_compositor::layer_list member  
    - Put weston-test layer on top                    
    - Commented layer ordering                        
    - Updated workspace layer code                    

 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 58a4cd0..40a4092 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 3913f95..161b3b5 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);
 
@@ -4899,11 +4897,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);
@@ -4925,13 +4930,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 b3083d8..daf024e 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 b0ab2ba..57d1cb2 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 60d05c4..ada7a7c 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 6bdd238..c8d5982 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 6b90c14..124f2dd 100644
--- a/libweston-desktop/xwayland.c
+++ b/libweston-desktop/xwayland.c
@@ -382,7 +382,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 508c2a9..327fbf9 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 ce3d9ab..973d2ee 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 eec2c3c..c12b2e3 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)
-- 
2.10.0



More information about the wayland-devel mailing list