[PATCH weston 06/18] shell: wait for desktop-shell init before fade in

ppaalanen at gmail.com ppaalanen at gmail.com
Wed May 22 08:03:09 PDT 2013


From: Pekka Paalanen <ppaalanen at gmail.com>

On Raspberry Pi, weston-desktop-shell is so slow to start, that the
compositor has time to run the fade-in before the wallpaper is up. The
user launching Weston sees the screen flipping to black, the fbcon
fading in, and then the desktop popping up.

To fix this, wait for the weston-desktop-shell to draw
everything before starting the initial fade-in. A new request is
added to the private desktop-shell protocol to signal it. If a
desktop-shell client does not support the new request, the fade-in
happens already at bind time.

If weston-desktop-shell crashes, or does not send the 'desktop_ready'
request in 15 seconds, the compositor will fade in anyway. This should
avoid a blocked screen in case weston-desktop-shell malfunction.

shell_fade_startup() does not directly start the fade-in but schedules
an idle callback, so that the compositor can process all pending events
before starting the fade clock. Otherwise (on RPi) we risk skipping part
of the animation. Yes, it is a hack, that should have been done in
window.c and weston-desktop-shell instead.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
 clients/desktop-shell.c    |  46 +++++++++++++++++-
 protocol/desktop-shell.xml |  13 ++++-
 src/shell.c                | 119 +++++++++++++++++++++++++++++++++++++++------
 3 files changed, 162 insertions(+), 16 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 3949975..4a39653 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -49,6 +49,7 @@ extern char **environ; /* defined by libc */
 struct desktop {
 	struct display *display;
 	struct desktop_shell *shell;
+	uint32_t interface_version;
 	struct unlock_dialog *unlock_dialog;
 	struct task unlock_task;
 	struct wl_list outputs;
@@ -57,6 +58,8 @@ struct desktop {
 	struct widget *grab_widget;
 
 	enum cursor_type grab_cursor;
+
+	int painted;
 };
 
 struct surface {
@@ -72,12 +75,14 @@ struct panel {
 	struct widget *widget;
 	struct wl_list launcher_list;
 	struct panel_clock *clock;
+	int painted;
 };
 
 struct background {
 	struct surface base;
 	struct window *window;
 	struct widget *widget;
+	int painted;
 };
 
 struct output {
@@ -175,6 +180,38 @@ show_menu(struct panel *panel, struct input *input, uint32_t time)
 			 x - 10, y - 10, menu_func, entries, 4);
 }
 
+static int
+is_desktop_painted(struct desktop *desktop)
+{
+	struct output *output;
+
+	wl_list_for_each(output, &desktop->outputs, link) {
+		if (output->panel && !output->panel->painted)
+			return 0;
+		if (output->background && !output->background->painted)
+			return 0;
+	}
+
+	return 1;
+}
+
+static void
+check_desktop_ready(struct window *window)
+{
+	struct display *display;
+	struct desktop *desktop;
+
+	display = window_get_display(window);
+	desktop = display_get_user_data(display);
+
+	if (!desktop->painted && is_desktop_painted(desktop)) {
+		desktop->painted = 1;
+
+		if (desktop->interface_version >= 2)
+			desktop_shell_desktop_ready(desktop->shell);
+	}
+}
+
 static void
 panel_launcher_activate(struct panel_launcher *widget)
 {
@@ -263,6 +300,8 @@ panel_redraw_handler(struct widget *widget, void *data)
 
 	cairo_destroy(cr);
 	cairo_surface_destroy(surface);
+	panel->painted = 1;
+	check_desktop_ready(panel->window);
 }
 
 static int
@@ -694,6 +733,9 @@ background_draw(struct widget *widget, void *data)
 		      allocation.width, allocation.height);
 	wl_surface_set_opaque_region(window_get_wl_surface(background->window), opaque);
 	wl_region_destroy(opaque);
+
+	background->painted = 1;
+	check_desktop_ready(background->window);
 }
 
 static void
@@ -1046,8 +1088,10 @@ global_handler(struct display *display, uint32_t id,
 	struct desktop *desktop = data;
 
 	if (!strcmp(interface, "desktop_shell")) {
+		desktop->interface_version = (version < 2) ? version : 2;
 		desktop->shell = display_bind(desktop->display,
-					      id, &desktop_shell_interface, 1);
+					      id, &desktop_shell_interface,
+					      desktop->interface_version);
 		desktop_shell_add_listener(desktop->shell, &listener, desktop);
 	} else if (!strcmp(interface, "wl_output")) {
 		create_output(desktop, id);
diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml
index d48c3dd..65e44a7 100644
--- a/protocol/desktop-shell.xml
+++ b/protocol/desktop-shell.xml
@@ -1,6 +1,6 @@
 <protocol name="desktop">
 
-  <interface name="desktop_shell" version="1">
+  <interface name="desktop_shell" version="2">
     <description summary="create desktop widgets and helpers">
       Traditional user interfaces can rely on this interface to define the
       foundations of typical desktops. Currently it's possible to set up
@@ -33,6 +33,17 @@
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
 
+    <request name="desktop_ready" since="2">
+      <description summary="desktop is ready to be shown">
+	Tell the server, that enough desktop elements have been drawn
+	to make the desktop look ready for use. During start-up, the
+	server can wait for this request with a black screen before
+	starting to fade in the desktop, for instance. If the client
+	parts of a desktop take a long time to initialize, we avoid
+	showing temporary garbage.
+      </description>
+    </request>
+
     <!-- We'll fold most of wl_shell into this interface and then
          they'll share the configure event.  -->
     <event name="configure">
diff --git a/src/shell.c b/src/shell.c
index e23c09b..eb8d802 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -156,6 +156,7 @@ struct desktop_shell {
 		struct weston_surface *surface;
 		struct weston_surface_animation *animation;
 		enum fade_type type;
+		struct wl_event_source *startup_timer;
 	} fade;
 
 	uint32_t binding_modifier;
@@ -275,6 +276,9 @@ shell_surface_get_shell(struct shell_surface *shsurf);
 static void
 surface_rotate(struct shell_surface *surface, struct weston_seat *seat);
 
+static void
+shell_fade_startup(struct desktop_shell *shell);
+
 static bool
 shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
 {
@@ -2548,12 +2552,22 @@ desktop_shell_set_grab_surface(struct wl_client *client,
 	shell->grab_surface = surface_resource->data;
 }
 
+static void
+desktop_shell_desktop_ready(struct wl_client *client,
+			    struct wl_resource *resource)
+{
+	struct desktop_shell *shell = resource->data;
+
+	shell_fade_startup(shell);
+}
+
 static const struct desktop_shell_interface desktop_shell_implementation = {
 	desktop_shell_set_background,
 	desktop_shell_set_panel,
 	desktop_shell_set_lock_surface,
 	desktop_shell_unlock,
-	desktop_shell_set_grab_surface
+	desktop_shell_set_grab_surface,
+	desktop_shell_desktop_ready
 };
 
 static enum shell_surface_type
@@ -3031,11 +3045,28 @@ shell_fade_done(struct weston_surface_animation *animation, void *data)
 	}
 }
 
-static void
-shell_fade(struct desktop_shell *shell, enum fade_type type)
+static struct weston_surface *
+shell_fade_create_surface(struct desktop_shell *shell)
 {
 	struct weston_compositor *compositor = shell->compositor;
 	struct weston_surface *surface;
+
+	surface = weston_surface_create(compositor);
+	if (!surface)
+		return NULL;
+
+	weston_surface_configure(surface, 0, 0, 8192, 8192);
+	weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
+	wl_list_insert(&compositor->fade_layer.surface_list,
+		       &surface->layer_link);
+	pixman_region32_init(&surface->input);
+
+	return surface;
+}
+
+static void
+shell_fade(struct desktop_shell *shell, enum fade_type type)
+{
 	float tint;
 
 	switch (type) {
@@ -3053,18 +3084,12 @@ shell_fade(struct desktop_shell *shell, enum fade_type type)
 	shell->fade.type = type;
 
 	if (shell->fade.surface == NULL) {
-		surface = weston_surface_create(compositor);
-		if (!surface)
+		shell->fade.surface = shell_fade_create_surface(shell);
+		if (!shell->fade.surface)
 			return;
 
-		weston_surface_configure(surface, 0, 0, 8192, 8192);
-		weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
-		surface->alpha = 1.0 - tint;
-		wl_list_insert(&compositor->fade_layer.surface_list,
-			       &surface->layer_link);
-		weston_surface_update_transform(surface);
-		shell->fade.surface = surface;
-		pixman_region32_init(&surface->input);
+		shell->fade.surface->alpha = 1.0 - tint;
+		weston_surface_update_transform(shell->fade.surface);
 	}
 
 	if (shell->fade.animation)
@@ -3078,6 +3103,67 @@ shell_fade(struct desktop_shell *shell, enum fade_type type)
 }
 
 static void
+do_shell_fade_startup(void *data)
+{
+	struct desktop_shell *shell = data;
+
+	shell_fade(shell, FADE_IN);
+}
+
+static void
+shell_fade_startup(struct desktop_shell *shell)
+{
+	struct wl_event_loop *loop;
+
+	if (!shell->fade.startup_timer)
+		return;
+
+	wl_event_source_remove(shell->fade.startup_timer);
+	shell->fade.startup_timer = NULL;
+
+	loop = wl_display_get_event_loop(shell->compositor->wl_display);
+	wl_event_loop_add_idle(loop, do_shell_fade_startup, shell);
+}
+
+static int
+fade_startup_timeout(void *data)
+{
+	struct desktop_shell *shell = data;
+
+	shell_fade_startup(shell);
+	return 0;
+}
+
+static void
+shell_fade_init(struct desktop_shell *shell)
+{
+	/* Make compositor output all black, and wait for the desktop-shell
+	 * client to signal it is ready, then fade in. The timer triggers a
+	 * fade-in, in case the desktop-shell client takes too long.
+	 */
+
+	struct wl_event_loop *loop;
+
+	if (shell->fade.surface != NULL) {
+		weston_log("%s: warning: fade surface already exists\n",
+			   __func__);
+		return;
+	}
+
+	shell->fade.surface = shell_fade_create_surface(shell);
+	if (!shell->fade.surface)
+		return;
+
+	weston_surface_update_transform(shell->fade.surface);
+	weston_surface_damage(shell->fade.surface);
+
+	loop = wl_display_get_event_loop(shell->compositor->wl_display);
+	shell->fade.startup_timer =
+		wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
+	wl_event_source_timer_update(shell->fade.startup_timer, 15000);
+}
+
+static void
 idle_handler(struct wl_listener *listener, void *data)
 {
 	struct desktop_shell *shell =
@@ -3444,6 +3530,7 @@ desktop_shell_sigchld(struct weston_process *process, int status)
 
 	weston_log("weston-desktop-shell died, respawning...\n");
 	launch_desktop_shell_process(shell);
+	shell_fade_startup(shell);
 }
 
 static void
@@ -3497,6 +3584,10 @@ bind_desktop_shell(struct wl_client *client,
 	if (client == shell->child.client) {
 		resource->destroy = unbind_desktop_shell;
 		shell->child.desktop_shell = resource;
+
+		if (version < 2)
+			shell_fade_startup(shell);
+
 		return;
 	}
 
@@ -4391,7 +4482,7 @@ module_init(struct weston_compositor *ec,
 
 	shell_add_bindings(ec, shell);
 
-	shell_fade(shell, FADE_IN);
+	shell_fade_init(shell);
 
 	return 0;
 }
-- 
1.8.1.5



More information about the wayland-devel mailing list