diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 497e4ffd..3b71403b 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) { @@ -261,6 +298,8 @@ panel_redraw_handler(struct widget *widget, void *data) cairo_destroy(cr); surface = window_get_surface(panel->window); cairo_surface_destroy(surface); + panel->painted = 1; + check_desktop_ready(panel->window); } static int @@ -690,6 +729,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 @@ -1095,8 +1137,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 d48c3dd3..65e44a73 100644 --- a/protocol/desktop-shell.xml +++ b/protocol/desktop-shell.xml @@ -1,6 +1,6 @@ - + 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 @@ + + + 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. + + + diff --git a/src/shell.c b/src/shell.c index e23c09b5..eb8d802d 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) @@ -3077,6 +3102,67 @@ shell_fade(struct desktop_shell *shell, enum fade_type type) shell_fade_done, shell); } +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) { @@ -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; }