← Back to team overview

lightdm-gtk-greeter-team team mailing list archive

[Merge] lp:~kalgasnik/lightdm-gtk-greeter/background-transition into lp:lightdm-gtk-greeter

 

Andrew P. has proposed merging lp:~kalgasnik/lightdm-gtk-greeter/background-transition into lp:lightdm-gtk-greeter.

Requested reviews:
  LightDM Gtk+ Greeter Development Team (lightdm-gtk-greeter-team)

For more details, see:
https://code.launchpad.net/~kalgasnik/lightdm-gtk-greeter/background-transition/+merge/241082

Add transition to backgrounds change.

1. Transition function: easy-in-out
2. Animation: drawing new background with different alpha over old background
3. Redraw timeout: 30ms
4. Duration: 500ms
5. Delay before changing to user's background: 250ms

At first I thought to make all these things configurable, but someone can say that it is too much.
"transition-duration" is enough. 

Enabled by default, I'm not sure that it is good idea.
-- 
https://code.launchpad.net/~kalgasnik/lightdm-gtk-greeter/background-transition/+merge/241082
Your team LightDM Gtk+ Greeter Development Team is requested to review the proposed merge of lp:~kalgasnik/lightdm-gtk-greeter/background-transition into lp:lightdm-gtk-greeter.
=== modified file 'src/Makefile.am'
--- src/Makefile.am	2014-08-20 23:23:59 +0000
+++ src/Makefile.am	2014-11-07 14:12:38 +0000
@@ -41,7 +41,8 @@
 	$(LIBX11_LIBS) \
 	$(LIBINDICATOR_LIBS) \
 	$(LIBIDO_LIBS) \
-	$(LIBXKLAVIER_LIBS)
+	$(LIBXKLAVIER_LIBS)\
+	-lm
 
 if MAINTAINER_MODE
 
@@ -65,4 +66,4 @@
 EXTRA_DIST = \
 	lightdm-gtk-greeter.glade \
 	lightdm-gtk-greeter-fallback.css \
-	lightdm-gtk-greeter-application.css
\ No newline at end of file
+	lightdm-gtk-greeter-application.css

=== modified file 'src/greeterbackground.c'
--- src/greeterbackground.c	2014-08-31 17:45:52 +0000
+++ src/greeterbackground.c	2014-11-07 14:12:38 +0000
@@ -1,4 +1,5 @@
 
+#include <math.h>
 #include <cairo-xlib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
@@ -34,6 +35,9 @@
 
 static const gchar* SCALING_MODE_PREFIXES[] = {"#source:", "#zoomed:", "#stretched:", NULL};
 
+typedef gdouble (*TransitionFunction)(gdouble x);
+typedef void (*TransitionDraw)(gpointer monitor, cairo_t* cr);
+
 /* Background configuration (parsed from background=... option).
    Used to fill <Background> */
 typedef struct
@@ -50,18 +54,34 @@
     } options;
 } BackgroundConfig;
 
+/* Transition configuration
+   Used to as part of <MonitorConfig> and <Monitor> */
+typedef struct
+{
+    /* Transition duration, in ms */
+    glong duration;
+    /* Timer timeout, in ms */
+    glong timeout;
+    TransitionFunction func;
+    /* Function to draw monitor background */
+    TransitionDraw draw;
+} TransitionConfig;
+
 /* Store monitor configuration */
 typedef struct
 {
     BackgroundConfig bg;
     gboolean user_bg;
     gboolean laptop;
+
+    TransitionConfig transition;
 } MonitorConfig;
 
 /* Actual drawing information attached to monitor.
  * Used to separate configured monitor background and user background. */
 typedef struct
 {
+    gint ref_count;
     BackgroundType type;
     union
     {
@@ -80,12 +100,25 @@
     gulong window_draw_handler_id;
 
     /* Configured background */
-    Background background_configured;
-    /* Background used to display user-background */
-    Background background_custom;
+    Background* background_configured;
     /* Current monitor background: &background_configured or &background_custom
      * Monitors with type = BACKGROUND_TYPE_SKIP have background = NULL */
-    const Background* background;
+    Background* background;
+
+    struct
+    {
+        TransitionConfig config;
+
+        /* Old background, stage == 0.0 */
+        Background* from;
+        /* New background, stage == 1.0 */
+        Background* to;
+
+        gint timer_id;
+        gint64 started;
+        /* Current stage */
+        gdouble stage;
+    } transition;
 } Monitor;
 
 struct _GreeterBackground
@@ -141,6 +174,9 @@
     gboolean follow_cursor;
     /* Use cursor position to determinate initial active monitor */
     gboolean follow_cursor_to_init;
+
+    /* Name => transition function, inited in set_monitor_config() */
+    GHashTable* transition_types;
 };
 
 enum
@@ -151,20 +187,6 @@
 
 static guint background_signals[BACKGROUND_SIGNAL_LAST] = {0};
 
-static const MonitorConfig DEFAULT_MONITOR_CONFIG =
-{
-    .bg =
-    {
-        .type = BACKGROUND_TYPE_COLOR,
-        .options =
-        {
-            .color = {.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}
-        }
-    },
-    .user_bg = TRUE,
-    .laptop = FALSE
-};
-
 static const gchar* DBUS_UPOWER_NAME                = "org.freedesktop.UPower";
 static const gchar* DBUS_UPOWER_PATH                = "/org/freedesktop/UPower";
 static const gchar* DBUS_UPOWER_INTERFACE           = "org.freedesktop.UPower";
@@ -177,15 +199,13 @@
 
 void greeter_background_set_active_monitor_config   (GreeterBackground* background,
                                                      const gchar* value);
-void greeter_background_set_default_config          (GreeterBackground* background,
-                                                     const gchar* bg,
-                                                     gboolean user_bg,
-                                                     gboolean laptop);
 void greeter_background_set_monitor_config          (GreeterBackground* background,
                                                      const gchar* name,
-                                                     const gchar* bg,
+                                                     const gchar* bg,               /* NULL to use fallback value */
                                                      gboolean user_bg, gboolean user_bg_used,
-                                                     gboolean laptop, gboolean laptop_used);
+                                                     gboolean laptop, gboolean laptop_used,
+                                                     gint transition_duration,      /* -1 to use fallback value */
+                                                     const gchar* transition_type); /* NULL to use fallback value */
 void greeter_background_remove_monitor_config       (GreeterBackground* background,
                                                      const gchar* name);
 gchar** greeter_background_get_configured_monitors  (GreeterBackground* background);
@@ -227,17 +247,26 @@
                                                      MonitorConfig* dest);
 
 /* struct Background */
-static gboolean background_initialize               (Background* bg,
-                                                     const BackgroundConfig* config,
+static Background* background_new                   (const BackgroundConfig* config,
                                                      const Monitor* monitor,
                                                      GHashTable* images_cache);
+static Background* background_ref                   (Background* bg);
+static void background_unref                        (Background** bg);
 static void background_finalize                     (Background* bg);
 
 /* struct Monitor */
 static void monitor_finalize                        (Monitor* info);
 static void monitor_set_background                  (Monitor* monitor,
-                                                     const Background* background);
+                                                     Background* background);
+static void monitor_start_transition                (Monitor* monitor,
+                                                     Background* from,
+                                                     Background* to);
+static void monitor_stop_transition                 (Monitor* monitor);
+static gboolean monitor_transition_cb               (Monitor* monitor);
+static void monitor_transition_draw_alpha           (const Monitor* monitor,
+                                                     cairo_t* cr);
 static void monitor_draw_background                 (const Monitor* monitor,
+                                                     const Background* background,
                                                      cairo_t* cr);
 static gboolean monitor_window_draw_cb              (GtkWidget* widget,
                                                      cairo_t* cr,
@@ -259,7 +288,29 @@
                                                      Pixmap xpixmap);
 static void set_surface_as_root                     (GdkScreen* screen,
                                                      cairo_surface_t* surface);
+static gdouble transition_func_linear               (gdouble x);
+static gdouble transition_func_easy_in_out          (gdouble x);
 
+static const MonitorConfig DEFAULT_MONITOR_CONFIG =
+{
+    .bg =
+    {
+        .type = BACKGROUND_TYPE_COLOR,
+        .options =
+        {
+            .color = {.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}
+        }
+    },
+    .user_bg = TRUE,
+    .laptop = FALSE,
+    .transition =
+    {
+        .duration = 500,
+        .timeout = 30,
+        .func = transition_func_easy_in_out,
+        .draw = (TransitionDraw)monitor_transition_draw_alpha
+    }
+};
 
 /* Implementation */
 
@@ -302,7 +353,7 @@
     self->priv->laptop_lid_closed = FALSE;
 }
 
-GreeterBackground* 
+GreeterBackground*
 greeter_background_new(GtkWidget* child)
 {
     GreeterBackground* background = GREETER_BACKGROUND(g_object_new(greeter_background_get_type(), NULL));
@@ -346,42 +397,56 @@
 }
 
 void
-greeter_background_set_default_config(GreeterBackground* background,
-                                      const gchar* bg,
-                                      gboolean user_bg,
-                                      gboolean laptop)
-{
-    g_return_if_fail(GREETER_IS_BACKGROUND(background));
-    GreeterBackgroundPrivate* priv = background->priv;
-
-    if(priv->default_config)
-        monitor_config_free(priv->default_config);
-
-    priv->default_config = g_new0(MonitorConfig, 1);
-    if(!background_config_initialize(&priv->default_config->bg, bg))
-        background_config_copy(&DEFAULT_MONITOR_CONFIG.bg, &priv->default_config->bg);
-    priv->default_config->user_bg = user_bg;
-    priv->default_config->laptop = laptop;
-}
-
-void
 greeter_background_set_monitor_config(GreeterBackground* background,
                                       const gchar* name,
                                       const gchar* bg,
                                       gboolean user_bg, gboolean user_bg_used,
-                                      gboolean laptop, gboolean laptop_used)
+                                      gboolean laptop, gboolean laptop_used,
+                                      gint transition_duration,
+                                      const gchar* transition_type)
 {
     g_return_if_fail(GREETER_IS_BACKGROUND(background));
     GreeterBackgroundPrivate* priv = background->priv;
 
     MonitorConfig* config = g_new0(MonitorConfig, 1);
 
+    const MonitorConfig* FALLBACK = (g_strcmp0(name, GREETER_BACKGROUND_DEFAULT) == 0) ? &DEFAULT_MONITOR_CONFIG : priv->default_config;
+
     if(!background_config_initialize(&config->bg, bg))
-        background_config_copy(&priv->default_config->bg, &config->bg);
-    config->user_bg = user_bg_used ? user_bg : priv->default_config->user_bg;
-    config->laptop = laptop_used ? laptop : priv->default_config->laptop;
-
-    g_hash_table_insert(priv->configs, g_strdup(name), config);
+        background_config_copy(&FALLBACK->bg, &config->bg);
+    config->user_bg = user_bg_used ? user_bg : FALLBACK->user_bg;
+    config->laptop = laptop_used ? laptop : FALLBACK->laptop;
+    config->transition.duration = transition_duration >= 0 ? transition_duration : FALLBACK->transition.duration;
+    config->transition.timeout = FALLBACK->transition.timeout;
+    config->transition.draw = FALLBACK->transition.draw;
+
+    if(transition_type)
+    {
+        if(!priv->transition_types)
+        {
+            priv->transition_types = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+            g_hash_table_insert(priv->transition_types, g_strdup("none"), NULL);
+            g_hash_table_insert(priv->transition_types, g_strdup("linear"), transition_func_linear);
+            g_hash_table_insert(priv->transition_types, g_strdup("easy-in-out"), transition_func_easy_in_out);
+        }
+        if(!g_hash_table_lookup_extended(priv->transition_types, transition_type, NULL, (gpointer*)&config->transition.func))
+        {
+            g_warning("[Background] Invalid transition type for '%s' monitor: '%s'. Using fallback value.",
+                      name, transition_type);
+            config->transition.func = FALLBACK->transition.func;
+        }
+    }
+    else
+        config->transition.func = FALLBACK->transition.func;
+
+    if(FALLBACK == priv->default_config)
+        g_hash_table_insert(priv->configs, g_strdup(name), config);
+    else
+    {
+        if(priv->default_config)
+            monitor_config_free(priv->default_config);
+        priv->default_config = config;
+    }
 }
 
 void
@@ -503,9 +568,13 @@
         if(config->laptop)
             priv->laptop_monitors = g_slist_prepend(priv->laptop_monitors, monitor);
 
-        if(!background_initialize(&monitor->background_configured, &config->bg, monitor, images_cache))
-            background_initialize(&monitor->background_configured, &DEFAULT_MONITOR_CONFIG.bg, monitor, images_cache);
-        monitor_set_background(monitor, &monitor->background_configured);
+        monitor->background_configured = background_new(&config->bg, monitor, images_cache);
+        if(!monitor->background_configured)
+            monitor->background_configured = background_new(&DEFAULT_MONITOR_CONFIG.bg, monitor, images_cache);
+        monitor_set_background(monitor, monitor->background_configured);
+
+        if(config->transition.duration && config->transition.func)
+            monitor->transition.config = config->transition;
 
         if(monitor->name)
             g_hash_table_insert(priv->monitors_map, g_strdup(monitor->name), monitor);
@@ -809,13 +878,19 @@
     {
         Monitor *monitor = iter->data;
 
-        background_finalize(&monitor->background_custom);
-        if(config.type != BACKGROUND_TYPE_INVALID &&
-           background_initialize(&monitor->background_custom, &config, monitor, images_cache))
-            monitor_set_background(monitor, &monitor->background_custom);
+        /* Old background_custom (if used) will be unrefed in monitor_set_background() */
+        Background* bg = NULL;
+        if(config.type != BACKGROUND_TYPE_INVALID)
+            bg = background_new(&config, monitor, images_cache);
+        if(bg)
+        {
+            monitor_set_background(monitor, bg);
+            background_unref(&bg);
+        }
         else
-            monitor_set_background(monitor, &monitor->background_configured);
+            monitor_set_background(monitor, monitor->background_configured);
     }
+
     if(images_cache)
         g_hash_table_unref(images_cache);
     if(config.type != BACKGROUND_TYPE_INVALID)
@@ -841,7 +916,7 @@
             monitor = priv->active_monitor;
         cairo_save(cr);
         cairo_translate(cr, monitor->geometry.x, monitor->geometry.y);
-        monitor_draw_background(monitor, cr);
+        monitor_draw_background(monitor, monitor->background, cr);
         cairo_restore(cr);
     }
     set_surface_as_root(priv->screen, surface);
@@ -904,7 +979,7 @@
             config->options.image.mode = SCALING_MODE_ZOOMED;
 
         config->options.image.path = g_strdup(value);
-        config->type = BACKGROUND_TYPE_IMAGE;        
+        config->type = BACKGROUND_TYPE_IMAGE;
     }
     return TRUE;
 }
@@ -941,15 +1016,16 @@
     background_config_copy(&source->bg, &dest->bg);
     dest->user_bg = source->user_bg;
     dest->laptop = source->laptop;
+    dest->transition = source->transition;
     return dest;
 }
 
-static gboolean
-background_initialize(Background* bg,
-                      const BackgroundConfig* config,
-                      const Monitor* monitor,
-                      GHashTable* images_cache)
+static Background*
+background_new(const BackgroundConfig* config,
+               const Monitor* monitor,
+               GHashTable* images_cache)
 {
+    Background* bg = NULL;
     if(config->type == BACKGROUND_TYPE_IMAGE)
     {
         GdkPixbuf* pixbuf = scale_image_file(config->options.image.path,
@@ -959,16 +1035,42 @@
         if(!pixbuf)
         {
             g_warning("Failed to read wallpaper: %s", config->options.image.path);
-            return FALSE;
+            return NULL;
         }
+        bg = g_new0(Background, 1);
         bg->options.image = pixbuf;
     }
     else if(config->type == BACKGROUND_TYPE_COLOR)
+    {
+        bg = g_new0(Background, 1);
         bg->options.color = config->options.color;
+    }
     else
-        return FALSE;
+        return NULL;
     bg->type = config->type;
-    return TRUE;
+    bg->ref_count = 1;
+    return bg;
+}
+
+static Background*
+background_ref(Background* bg)
+{
+    bg->ref_count++;
+    return bg;
+}
+
+static void
+background_unref(Background** bg)
+{
+    if(*bg)
+    {
+        (*bg)->ref_count--;
+        if((*bg)->ref_count == 0)
+        {
+            background_finalize(*bg);
+            *bg = NULL;
+        }
+    }
 }
 
 static void
@@ -981,17 +1083,91 @@
 
 static void
 monitor_set_background(Monitor* monitor,
-                       const Background* background)
-{
-    monitor->background = background;
-    gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
+                       Background* background)
+{
+    if(monitor->background == background)
+        return;
+    monitor_stop_transition(monitor);
+    if(monitor->transition.config.duration > 0 && monitor->background)
+        monitor_start_transition(monitor, monitor->background, background);
+    background_unref(&monitor->background);
+    monitor->background = background_ref(background);
+    gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
+}
+
+static void
+monitor_start_transition(Monitor* monitor,
+                         Background* from,
+                         Background* to)
+{
+    monitor_stop_transition(monitor);
+
+    monitor->transition.from = background_ref(from);
+    monitor->transition.to = background_ref(to);
+
+    monitor->transition.started = g_get_monotonic_time();
+    monitor->transition.timer_id = g_timeout_add(monitor->transition.config.timeout,
+                                                 (GSourceFunc)monitor_transition_cb, monitor);
+    monitor->transition.stage = 0;
+}
+
+static void
+monitor_stop_transition(Monitor* monitor)
+{
+    if(!monitor->transition.timer_id)
+        return;
+    g_source_remove(monitor->transition.timer_id);
+    monitor->transition.timer_id = 0;
+    monitor->transition.started = 0;
+    monitor->transition.stage = 0;
+    background_unref(&monitor->transition.to);
+    background_unref(&monitor->transition.from);
+}
+
+static gboolean
+monitor_transition_cb(Monitor* monitor)
+{
+    if(!monitor->transition.timer_id)
+        return G_SOURCE_REMOVE;
+
+    gint64 span = g_get_monotonic_time() - monitor->transition.started;
+    gdouble x = CLAMP(span/monitor->transition.config.duration/1000.0, 0.0, 1.0);
+    monitor->transition.stage = monitor->transition.config.func(x);
+
+    if(x >= 1.0)
+        monitor_stop_transition(monitor);
+
+    gtk_widget_queue_draw(GTK_WIDGET(monitor->window));
+    return x >= 1.0 ? G_SOURCE_REMOVE : G_SOURCE_CONTINUE;
+}
+
+static void
+monitor_transition_draw_alpha(const Monitor* monitor,
+                              cairo_t* cr)
+{
+    monitor_draw_background(monitor, monitor->transition.from, cr);
+
+    cairo_push_group(cr);
+    monitor_draw_background(monitor, monitor->transition.to, cr);
+    cairo_pop_group_to_source(cr);
+
+    cairo_pattern_t* alpha_pattern = cairo_pattern_create_rgba(0.0, 0.0, 0.0, monitor->transition.stage);
+    cairo_mask(cr, alpha_pattern);
+    cairo_pattern_destroy(alpha_pattern);
 }
 
 static void
 monitor_finalize(Monitor* monitor)
 {
-    background_finalize(&monitor->background_configured);
-    background_finalize(&monitor->background_custom);
+    if(monitor->transition.config.duration)
+    {
+        monitor_stop_transition(monitor);
+        if(monitor->transition.timer_id)
+            g_source_remove(monitor->transition.timer_id);
+        monitor->transition.config.duration = 0;
+    }
+    background_unref(&monitor->background_configured);
+    background_unref(&monitor->background);
     g_free(monitor->name);
     if(monitor->window_draw_handler_id)
         g_signal_handler_disconnect(monitor->window, monitor->window_draw_handler_id);
@@ -1004,20 +1180,21 @@
 
 static void
 monitor_draw_background(const Monitor* monitor,
+                        const Background* background,
                         cairo_t* cr)
 {
     g_return_if_fail(monitor != NULL);
-    g_return_if_fail(monitor->background != NULL);
+    g_return_if_fail(background != NULL);
 
-    if(monitor->background->type == BACKGROUND_TYPE_IMAGE && monitor->background->options.image)
+    if(background->type == BACKGROUND_TYPE_IMAGE && background->options.image)
     {
-        gdk_cairo_set_source_pixbuf(cr, monitor->background->options.image, 0, 0);
+        gdk_cairo_set_source_pixbuf(cr, background->options.image, 0, 0);
         cairo_paint(cr);
     }
-    else if(monitor->background->type == BACKGROUND_TYPE_COLOR)
+    else if(background->type == BACKGROUND_TYPE_COLOR)
     {
         cairo_rectangle(cr, 0, 0, monitor->geometry.width, monitor->geometry.height);
-        gdk_cairo_set_source_rgba(cr, &monitor->background->options.color);
+        gdk_cairo_set_source_rgba(cr, &background->options.color);
         cairo_fill(cr);
     }
 }
@@ -1027,8 +1204,14 @@
                        cairo_t* cr,
                        const Monitor* monitor)
 {
-    if(monitor->background)
-        monitor_draw_background(monitor, cr);
+    if(!monitor->background)
+        return FALSE;
+
+    if(monitor->transition.started)
+        monitor_transition_draw_alpha(monitor, cr);
+    else
+        monitor_draw_background(monitor, monitor->background, cr);
+
     return FALSE;
 }
 
@@ -1165,7 +1348,7 @@
                    Display* display,
                    Pixmap xpixmap)
 {
-    
+
     Window xroot = RootWindow (display, gdk_screen_get_number (screen));
     char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
     Atom atoms[G_N_ELEMENTS(atom_names)] = {0};
@@ -1261,3 +1444,15 @@
     XFlush (display);
     XUngrabServer (display);
 }
+
+static gdouble
+transition_func_linear(gdouble x)
+{
+    return x;
+}
+
+static gdouble
+transition_func_easy_in_out(gdouble x)
+{
+    return (1 - cos(M_PI*x))/2;
+}

=== modified file 'src/greeterbackground.h'
--- src/greeterbackground.h	2014-08-31 17:45:52 +0000
+++ src/greeterbackground.h	2014-11-07 14:12:38 +0000
@@ -12,6 +12,8 @@
 #define GREETER_IS_BACKGROUND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), GREETER_BACKGROUND_TYPE))
 #define GREETER_IS_BACKGROUND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), GREETER_BACKGROUND_TYPE))
 
+#define GREETER_BACKGROUND_DEFAULT          "*"
+
 typedef struct _GreeterBackground           GreeterBackground;
 typedef struct _GreeterBackgroundClass      GreeterBackgroundClass;
 
@@ -20,15 +22,13 @@
 GreeterBackground* greeter_background_new           (GtkWidget* child);
 void greeter_background_set_active_monitor_config   (GreeterBackground* background,
                                                      const gchar* value);
-void greeter_background_set_default_config          (GreeterBackground* background,
-                                                     const gchar* bg,
-                                                     gboolean user_bg,
-                                                     gboolean laptop);
 void greeter_background_set_monitor_config          (GreeterBackground* background,
                                                      const gchar* name,
                                                      const gchar* bg,
                                                      gboolean user_bg, gboolean user_bg_used,
-                                                     gboolean laptop, gboolean laptop_used);
+                                                     gboolean laptop, gboolean laptop_used,
+                                                     gint transition_duration,
+                                                     const gchar* transition_func);
 void greeter_background_remove_monitor_config       (GreeterBackground* background,
                                                      const gchar* name);
 gchar** greeter_background_get_configured_monitors  (GreeterBackground* background);

=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c	2014-09-01 07:58:56 +0000
+++ src/lightdm-gtk-greeter.c	2014-11-07 14:12:38 +0000
@@ -127,9 +127,6 @@
 static const WindowPosition KEYBOARD_POSITION   = {.x = { 50, +1, TRUE,   0}, .y = {  0, -1, FALSE, +1}, .use_size = TRUE,
                                                    .width = {50, 0, TRUE, 0}, .height = {25, 0, TRUE, 0}};
 
-/* Configuration */
-static gboolean key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value);
-
 /* Clock */
 static gchar *clock_format;
 static gboolean clock_timeout_thread (void);
@@ -536,21 +533,6 @@
     return TRUE;
 }
 
-/* Configuration */
-
-static gboolean
-key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value)
-{
-    GError* error = NULL;
-    gboolean result = g_key_file_get_boolean (key_file, group_name, key, &error);
-    if (error)
-    {
-        g_clear_error (&error);
-        return default_value;
-    }
-    return result;
-}
-
 /* Clock */
 
 static gboolean
@@ -1778,17 +1760,42 @@
     gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
 }
 
+static guint set_user_background_delayed_id = 0;
+
+static gboolean
+set_user_background_delayed_cb (const gchar *value)
+{
+    greeter_background_set_custom_background (greeter_background, value);
+    set_user_background_delayed_id = 0;
+    return G_SOURCE_REMOVE;
+}
+
 static void
-set_user_background (const gchar *username)
+set_user_background (const gchar *user_name)
 {
-    const gchar *path = NULL;
-    if (username)
+    const gchar *value = NULL;
+    if (user_name)
     {
-        LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
+        LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), user_name);
         if (user)
-            path = lightdm_user_get_background (user);
-    }
-    greeter_background_set_custom_background (greeter_background, path);
+            value = lightdm_user_get_background (user);
+    }
+
+    if (set_user_background_delayed_id)
+    {
+        g_source_remove (set_user_background_delayed_id);
+        set_user_background_delayed_id = 0;
+    }
+
+    if (!value)
+        greeter_background_set_custom_background (greeter_background, NULL);
+    else
+    {
+        /* Small delay before changing background */
+        set_user_background_delayed_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 250,
+                                                             (GSourceFunc)set_user_background_delayed_cb,
+                                                             g_strdup (value), g_free);
+    }
 }
 
 static void
@@ -2852,36 +2859,45 @@
     greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor");
     g_free (value);
 
-    value = g_key_file_get_value (config, "greeter", "background", NULL);
-    greeter_background_set_default_config (greeter_background, value,
-                                           key_file_get_boolean_extended (config, "greeter", "user-background", TRUE),
-                                           key_file_get_boolean_extended (config, "greeter", "laptop", FALSE));
-    g_free (value);
-
     const gchar *CONFIG_MONITOR_PREFIX = "monitor:";
     gchar **config_group;
     gchar **config_groups = g_key_file_get_groups (config, NULL);
     for (config_group = config_groups; *config_group; ++config_group)
     {
-        if (!g_str_has_prefix (*config_group, CONFIG_MONITOR_PREFIX))
-            continue;
-        const gchar *name = *config_group + sizeof (CONFIG_MONITOR_PREFIX);
-        while (*name && g_ascii_isspace (*name))
-            ++name;
+        gchar *name_to_free = NULL;
+        const gchar *name = *config_group;
+
+        if (g_strcmp0 (*config_group, "greeter") != 0)
+        {
+            if (!g_str_has_prefix (name, CONFIG_MONITOR_PREFIX))
+                continue;
+            name = *config_group + sizeof (CONFIG_MONITOR_PREFIX);
+            while (*name && g_ascii_isspace (*name))
+                ++name;
+        }
+        else
+            name = name_to_free = g_strdup (GREETER_BACKGROUND_DEFAULT);
+
         g_debug ("Monitor configuration found: '%s'", name);
 
-        GError *user_bg_error = NULL, *laptop_error = NULL;
+        GError *user_bg_error = NULL, *laptop_error = NULL, *duration_error = NULL;
         gboolean user_bg = g_key_file_get_boolean (config, *config_group, "user-background", &user_bg_error);
         gboolean laptop = g_key_file_get_boolean (config, *config_group, "laptop", &laptop_error);
-        value = g_key_file_get_value (config, *config_group, "background", NULL);
+        gchar *background = g_key_file_get_value (config, *config_group, "background", NULL);
+        gchar *tr_type = g_key_file_get_string (config, *config_group, "transition-type", NULL);
+        gint tr_duration = g_key_file_get_integer (config, *config_group, "transition-duration", &duration_error);
 
-        greeter_background_set_monitor_config (greeter_background, name, value,
+        greeter_background_set_monitor_config (greeter_background, name, background,
                                                user_bg, user_bg_error == NULL,
-                                               laptop, laptop_error == NULL);
+                                               laptop, laptop_error == NULL,
+                                               duration_error == NULL ? tr_duration : -1,
+                                               tr_type);
 
-        g_free (value);
+        g_free (tr_type);
+        g_free (background);
+        g_free (name_to_free);
+        g_clear_error (&user_bg_error);
         g_clear_error (&laptop_error);
-        g_clear_error (&user_bg_error);
     }
     g_strfreev (config_groups);
 


Follow ups