============================================================ Listen for new "transitioned" signal and react We now emit "transitioned" when switching frames in a slide show instead of "changed" so we could potentially apply a crossfade when switching backgrounds but not interfere with the slide show transitions. diff --git a/eel/eel-background.c b/eel/eel-background.c --- a/eel/eel-background.c +++ b/eel/eel-background.c @@ -143,6 +143,13 @@ on_bg_changed (GnomeBG *bg, EelBackground *background) } static void +on_bg_transitioned (GnomeBG *bg, EelBackground *background) +{ + g_signal_emit (G_OBJECT (background), + signals[APPEARANCE_CHANGED], 0); +} + +static void eel_background_init (gpointer object, gpointer klass) { EelBackground *background; @@ -157,6 +164,8 @@ eel_background_init (gpointer object, gpointer klass) g_signal_connect (background->details->bg, "changed", G_CALLBACK (on_bg_changed), background); + g_signal_connect (background->details->bg, "transitioned", + G_CALLBACK (on_bg_transitioned), background); } ============================================================ Move root window setup to independent function Previously it was called open coded in eel_background_set_up_widget (). We're going to need to delay calling it in some cases later when we add the cross fade transitions, so better to factor it out now. diff --git a/eel/eel-background.c b/eel/eel-background.c --- a/eel/eel-background.c +++ b/eel/eel-background.c @@ -620,11 +620,38 @@ eel_background_reset (EelBackground *background) } static void +set_root_pixmap (EelBackground *background, + GdkWindow *window) +{ + GdkPixmap *pixmap, *root_pixmap; + GdkScreen *screen; + GdkColor color; + gboolean changes_with_size; + + pixmap = eel_background_get_pixmap_and_color (background, + window, + &color, + &changes_with_size); + screen = gdk_drawable_get_screen (window); + + if (background->details->use_common_pixmap) { + root_pixmap = g_object_ref (pixmap); + } else { + root_pixmap = gnome_bg_create_pixmap (background->details->bg, window, + gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE); + } + + gnome_bg_set_pixmap_as_root (screen, pixmap); + + g_object_unref (pixmap); + g_object_unref (root_pixmap); +} + +static void eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) { GtkStyle *style; GdkPixmap *pixmap; - GdkPixmap *root_pixmap; GdkColor color; int window_width; @@ -666,18 +693,7 @@ eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) gnome_bg_changes_with_size (background->details->bg); if (background->details->is_desktop) { - - root_pixmap = NULL; - - if (background->details->use_common_pixmap) { - root_pixmap = g_object_ref (pixmap); - } else { - root_pixmap = gnome_bg_create_pixmap (background->details->bg, window, - window_width, window_height, TRUE); - } - - gnome_bg_set_pixmap_as_root (gdk_drawable_get_screen (window), root_pixmap); - g_object_unref (root_pixmap); + set_root_pixmap (background, window); } if (pixmap) { ============================================================ Store widget in background details It will get used in various places, so keeping diff --git a/eel/eel-background.c b/eel/eel-background.c --- a/eel/eel-background.c +++ b/eel/eel-background.c @@ -74,6 +74,7 @@ struct EelBackgroundDetails { char *color; GnomeBG *bg; + GtkWidget *widget; /* Realized data: */ gboolean background_changes_with_size; @@ -806,6 +807,12 @@ eel_background_is_desktop (EelBackground *background) return background->details->is_desktop; } +static void +on_widget_destroyed (GtkWidget *widget, EelBackground *background) +{ + background->details->widget = NULL; +} + /* Gets the background attached to a widget. If the widget doesn't already have a EelBackground object, @@ -841,6 +848,8 @@ eel_get_widget_background (GtkWidget *widget) gtk_object_sink (GTK_OBJECT (background)); g_object_set_data_full (G_OBJECT (widget), "eel_background", background, g_object_unref); + background->details->widget = widget; + g_signal_connect_object (widget, "destroy", G_CALLBACK (on_widget_destroyed), background, 0); /* Arrange to get the signal whenever the background changes. */ g_signal_connect_object (background, "appearance_changed", ============================================================ Compress multiple background change requests into 1 We may end up in a situation where we need to deal with a few different things trying to change the background at the same time in quick succession. This change avoids duplicated effort by deferring the work to an idle handler. diff --git a/eel/eel-background.c b/eel/eel-background.c --- a/eel/eel-background.c +++ b/eel/eel-background.c @@ -91,6 +90,7 @@ struct EelBackgroundDetails { gulong screen_size_handler; /* Can we use common pixmap for root window and desktop window */ gboolean use_common_pixmap; + guint change_idle_id; }; static void @@ -702,13 +702,35 @@ eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) } } -static void -eel_widget_background_changed (GtkWidget *widget, EelBackground *background) +static gboolean +on_background_changed (EelBackground *background) { + if (background->details->change_idle_id == 0) { + return FALSE; + } + + background->details->change_idle_id = 0; + eel_background_unrealize (background); - eel_background_set_up_widget (background, widget); + eel_background_set_up_widget (background, background->details->widget); + + gtk_widget_queue_draw (background->details->widget); - gtk_widget_queue_draw (widget); + return FALSE; +} + +static void +eel_widget_queue_background_change (GtkWidget *widget) +{ + EelBackground *background; + + background = eel_get_widget_background (widget); + + if (background->details->change_idle_id > 0) { + return; + } + + background->details->change_idle_id = g_idle_add ((GSourceFunc) on_background_changed, background); } /* Callback used when the style of a widget changes. We have to regenerate its @@ -721,7 +743,7 @@ widget_style_set_cb (GtkWidget *widget, GtkStyle *previous_style, gpointer data) background = EEL_BACKGROUND (data); - eel_widget_background_changed (widget, background); + eel_widget_queue_background_change (widget); } static void @@ -810,6 +832,11 @@ eel_background_is_desktop (EelBackground *background) static void on_widget_destroyed (GtkWidget *widget, EelBackground *background) { + if (background->details->change_idle_id != 0) { + g_source_remove (background->details->change_idle_id); + background->details->change_idle_id = 0; + } + background->details->widget = NULL; } @@ -853,8 +880,8 @@ eel_get_widget_background (GtkWidget *widget) /* Arrange to get the signal whenever the background changes. */ g_signal_connect_object (background, "appearance_changed", - G_CALLBACK (eel_widget_background_changed), widget, G_CONNECT_SWAPPED); - eel_widget_background_changed (widget, background); + G_CALLBACK (eel_widget_queue_background_change), widget, G_CONNECT_SWAPPED); + eel_widget_queue_background_change (widget); g_signal_connect_object (widget, "style_set", G_CALLBACK (widget_style_set_cb), ============================================================ Add the crossfade transition diff --git a/eel/eel-background.c b/eel/eel-background.c --- a/eel/eel-background.c +++ b/eel/eel-background.c @@ -53,6 +53,9 @@ static GdkPixmap *eel_background_get_pixmap_and_color (EelBackground *backg gboolean *changes_with_size); static void set_image_properties (EelBackground *background); +static void init_fade (EelBackground *background, GtkWidget *widget); +static void free_fade (EelBackground *background); + EEL_CLASS_BOILERPLATE (EelBackground, eel_background, GTK_TYPE_OBJECT) enum { @@ -78,6 +81,7 @@ struct EelBackgroundDetails { /* Realized data: */ gboolean background_changes_with_size; GdkPixmap *background_pixmap; + GnomeBGCrossfade *fade; int background_entire_width; int background_entire_height; GdkColor default_color; @@ -139,6 +143,7 @@ eel_background_class_init (gpointer klass) static void on_bg_changed (GnomeBG *bg, EelBackground *background) { + init_fade (background, background->details->widget); g_signal_emit (G_OBJECT (background), signals[APPEARANCE_CHANGED], 0); } @@ -146,6 +151,7 @@ on_bg_changed (GnomeBG *bg, EelBackground *background) static void on_bg_transitioned (GnomeBG *bg, EelBackground *background) { + free_fade (background); g_signal_emit (G_OBJECT (background), signals[APPEARANCE_CHANGED], 0); } @@ -185,6 +191,15 @@ eel_background_remove_current_image (EelBackground *background) } static void +free_fade (EelBackground *background) +{ + if (background->details->fade != NULL) { + g_object_unref (background->details->fade); + background->details->fade = NULL; + } +} + +static void eel_background_finalize (GObject *object) { EelBackground *background; @@ -199,6 +214,8 @@ eel_background_finalize (GObject *object) background->details->background_pixmap = NULL; } + free_fade (background); + g_free (background->details); EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); @@ -648,6 +665,33 @@ set_root_pixmap (EelBackground *background, g_object_unref (root_pixmap); } +static gboolean +fade_to_pixmap (EelBackground *background, + GdkWindow *window, + GdkPixmap *pixmap) +{ + if (background->details->fade == NULL) { + return FALSE; + } + + if (!gnome_bg_crossfade_set_end_pixmap (background->details->fade, + pixmap)) { + return FALSE; + } + + if (!gnome_bg_crossfade_is_started (background->details->fade)) { + gnome_bg_crossfade_start (background->details->fade, window); + if (background->details->is_desktop) { + g_signal_connect_swapped (background->details->fade, + "finished", + G_CALLBACK (set_root_pixmap), background); + } + } + + return gnome_bg_crossfade_is_started (background->details->fade); +} + + static void eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) { @@ -660,6 +704,7 @@ eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) GdkWindow *window; gboolean changes_with_size; + gboolean in_fade; if (!GTK_WIDGET_REALIZED (widget)) { return; @@ -682,18 +727,25 @@ eel_background_set_up_widget (EelBackground *background, GtkWidget *widget) window = widget->window; } + if (background->details->fade != NULL) { + in_fade = fade_to_pixmap (background, window, pixmap); + } else { + in_fade = FALSE; + } + + if (!in_fade) { if (!changes_with_size || background->details->is_desktop) { gdk_window_set_back_pixmap (window, pixmap, FALSE); } else { gdk_window_set_back_pixmap (window, NULL, FALSE); gdk_window_set_background (window, &color); } + } - background->details->background_changes_with_size = gnome_bg_changes_with_size (background->details->bg); - if (background->details->is_desktop) { + if (background->details->is_desktop && !in_fade) { set_root_pixmap (background, window); } @@ -720,6 +772,44 @@ on_background_changed (EelBackground *background) } static void +init_fade (EelBackground *background, GtkWidget *widget) +{ + if (widget == NULL || !GTK_WIDGET_REALIZED (widget)) + return; + + if (background->details->fade == NULL) { + int old_width, old_height, width, height; + + /* If this was the result of a screen size change, + * we don't want to crossfade + */ + gdk_drawable_get_size (widget->window, &old_width, &old_height); + drawable_get_adjusted_size (background, widget->window, + &width, &height); + if (old_width == width && old_height == height) { + background->details->fade = gnome_bg_crossfade_new (width, height); + g_signal_connect_swapped (background->details->fade, + "finished", + G_CALLBACK (free_fade), + background); + } + } + + if (background->details->fade != NULL && !gnome_bg_crossfade_is_started (background->details->fade)) { + GdkPixmap *start_pixmap; + + if (background->details->background_pixmap == NULL) { + start_pixmap = gnome_bg_get_pixmap_from_root (gtk_widget_get_screen (widget)); + } else { + start_pixmap = g_object_ref (background->details->background_pixmap); + } + gnome_bg_crossfade_set_start_pixmap (background->details->fade, + start_pixmap); + g_object_unref (start_pixmap); + } +} + +static void eel_widget_queue_background_change (GtkWidget *widget) { EelBackground *background; @@ -782,6 +872,8 @@ widget_realized_setup (GtkWidget *widget, gpointer data) } else { background->details->use_common_pixmap = FALSE; } + + init_fade (background, widget); } }