diff options
Diffstat (limited to 'libgnome-desktop')
-rw-r--r-- | libgnome-desktop/Makefile.am | 4 | ||||
-rw-r--r-- | libgnome-desktop/gnome-bg-crossfade.c | 575 | ||||
-rw-r--r-- | libgnome-desktop/gnome-bg-crossfade.h | 74 | ||||
-rw-r--r-- | libgnome-desktop/gnome-bg.c | 2689 | ||||
-rw-r--r-- | libgnome-desktop/gnome-bg.h | 121 |
5 files changed, 0 insertions, 3463 deletions
diff --git a/libgnome-desktop/Makefile.am b/libgnome-desktop/Makefile.am index 2389eb18..dceda3dc 100644 --- a/libgnome-desktop/Makefile.am +++ b/libgnome-desktop/Makefile.am @@ -32,9 +32,7 @@ endif introspection_sources = \ gnome-desktop-thumbnail.c \ gnome-thumbnail-pixbuf-utils.c \ - gnome-bg.c \ gnome-bg-slide-show.c \ - gnome-bg-crossfade.c \ gnome-rr.c \ gnome-rr-config.c \ gnome-rr-output-info.c \ @@ -98,8 +96,6 @@ pkgconfig_DATA = gnome-desktop-3.0.pc libgnome_desktopdir = $(includedir)/gnome-desktop-3.0/libgnome-desktop libgnome_desktop_HEADERS = \ - gnome-bg.h \ - gnome-bg-crossfade.h \ gnome-bg-slide-show.h \ gnome-desktop-thumbnail.h \ gnome-rr.h \ diff --git a/libgnome-desktop/gnome-bg-crossfade.c b/libgnome-desktop/gnome-bg-crossfade.c deleted file mode 100644 index 2c112d0a..00000000 --- a/libgnome-desktop/gnome-bg-crossfade.c +++ /dev/null @@ -1,575 +0,0 @@ -/* gnome-bg-crossfade.h - fade window background between two surfaces - * - * Copyright (C) 2008 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License - * as published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * Author: Ray Strode <rstrode@redhat.com> -*/ - -#include <string.h> -#include <math.h> -#include <stdarg.h> - -#include <gio/gio.h> - -#include <gdk/gdk.h> -#include <gdk/gdkx.h> -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#include <gtk/gtk.h> - -#include <cairo.h> -#include <cairo-xlib.h> - -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include "gnome-bg.h" -#include "gnome-bg-crossfade.h" - -struct _GnomeBGCrossfadePrivate -{ - GdkWindow *window; - int width; - int height; - cairo_surface_t *fading_surface; - cairo_surface_t *end_surface; - gdouble start_time; - gdouble total_duration; - guint timeout_id; - guint is_first_frame : 1; -}; - -enum { - PROP_0, - PROP_WIDTH, - PROP_HEIGHT, -}; - -enum { - FINISHED, - NUMBER_OF_SIGNALS -}; - -static guint signals[NUMBER_OF_SIGNALS] = { 0 }; - -G_DEFINE_TYPE (GnomeBGCrossfade, gnome_bg_crossfade, G_TYPE_OBJECT) -#define GNOME_BG_CROSSFADE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),\ - GNOME_TYPE_BG_CROSSFADE,\ - GnomeBGCrossfadePrivate)) - -static void -gnome_bg_crossfade_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GnomeBGCrossfade *fade; - - g_assert (GNOME_IS_BG_CROSSFADE (object)); - - fade = GNOME_BG_CROSSFADE (object); - - switch (property_id) - { - case PROP_WIDTH: - fade->priv->width = g_value_get_int (value); - break; - case PROP_HEIGHT: - fade->priv->height = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gnome_bg_crossfade_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GnomeBGCrossfade *fade; - - g_assert (GNOME_IS_BG_CROSSFADE (object)); - - fade = GNOME_BG_CROSSFADE (object); - - switch (property_id) - { - case PROP_WIDTH: - g_value_set_int (value, fade->priv->width); - break; - case PROP_HEIGHT: - g_value_set_int (value, fade->priv->height); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gnome_bg_crossfade_finalize (GObject *object) -{ - GnomeBGCrossfade *fade; - - fade = GNOME_BG_CROSSFADE (object); - - gnome_bg_crossfade_stop (fade); - - if (fade->priv->fading_surface != NULL) { - cairo_surface_destroy (fade->priv->fading_surface); - fade->priv->fading_surface = NULL; - } - - if (fade->priv->end_surface != NULL) { - g_object_unref (fade->priv->end_surface); - fade->priv->end_surface = NULL; - } -} - -static void -gnome_bg_crossfade_class_init (GnomeBGCrossfadeClass *fade_class) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (fade_class); - - gobject_class->get_property = gnome_bg_crossfade_get_property; - gobject_class->set_property = gnome_bg_crossfade_set_property; - gobject_class->finalize = gnome_bg_crossfade_finalize; - - /** - * GnomeBGCrossfade:width: - * - * When a crossfade is running, this is width of the fading - * surface. - */ - g_object_class_install_property (gobject_class, - PROP_WIDTH, - g_param_spec_int ("width", - "Window Width", - "Width of window to fade", - 0, G_MAXINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - - /** - * GnomeBGCrossfade:height: - * - * When a crossfade is running, this is height of the fading - * surface. - */ - g_object_class_install_property (gobject_class, - PROP_HEIGHT, - g_param_spec_int ("height", "Window Height", - "Height of window to fade on", - 0, G_MAXINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - - /** - * GnomeBGCrossfade::finished: - * @fade: the #GnomeBGCrossfade that received the signal - * @window: the #GdkWindow the crossfade happend on. - * - * When a crossfade finishes, @window will have a copy - * of the end surface as its background, and this signal will - * get emitted. - */ - signals[FINISHED] = g_signal_new ("finished", - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - g_type_class_add_private (gobject_class, sizeof (GnomeBGCrossfadePrivate)); -} - -static void -gnome_bg_crossfade_init (GnomeBGCrossfade *fade) -{ - fade->priv = GNOME_BG_CROSSFADE_GET_PRIVATE (fade); - - fade->priv->fading_surface = NULL; - fade->priv->end_surface = NULL; - fade->priv->timeout_id = 0; -} - -/** - * gnome_bg_crossfade_new: - * @width: The width of the crossfading window - * @height: The height of the crossfading window - * - * Creates a new object to manage crossfading a - * window background between two #cairo_surface_ts. - * - * Return value: the new #GnomeBGCrossfade - **/ -GnomeBGCrossfade * -gnome_bg_crossfade_new (int width, - int height) -{ - GObject *object; - - object = g_object_new (GNOME_TYPE_BG_CROSSFADE, - "width", width, - "height", height, NULL); - - return (GnomeBGCrossfade *) object; -} - -static cairo_surface_t * -tile_surface (cairo_surface_t *surface, - int width, - int height) -{ - cairo_surface_t *copy; - cairo_t *cr; - - if (surface == NULL) { - copy = gdk_window_create_similar_surface (gdk_get_default_root_window (), - CAIRO_CONTENT_COLOR, - width, height); - } else { - copy = cairo_surface_create_similar (surface, - cairo_surface_get_content (surface), - width, height); - } - - cr = cairo_create (copy); - - if (surface != NULL) { - cairo_pattern_t *pattern; - cairo_set_source_surface (cr, surface, 0.0, 0.0); - pattern = cairo_get_source (cr); - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); - } else { - GtkStyle *style; - style = gtk_widget_get_default_style (); - gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]); - } - - cairo_paint (cr); - - if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy (copy); - copy = NULL; - } - cairo_destroy (cr); - - return copy; -} - -/** - * gnome_bg_crossfade_set_start_surface: - * @fade: a #GnomeBGCrossfade - * @surface: The cairo surface to fade from - * - * Before initiating a crossfade with gnome_bg_crossfade_start() - * a start and end surface have to be set. This function sets - * the surface shown at the beginning of the crossfade effect. - * - * Return value: %TRUE if successful, or %FALSE if the surface - * could not be copied. - **/ -gboolean -gnome_bg_crossfade_set_start_surface (GnomeBGCrossfade *fade, - cairo_surface_t *surface) -{ - g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE); - - if (fade->priv->fading_surface != NULL) { - cairo_surface_destroy (fade->priv->fading_surface); - fade->priv->fading_surface = NULL; - } - - fade->priv->fading_surface = tile_surface (surface, - fade->priv->width, - fade->priv->height); - - return fade->priv->fading_surface != NULL; -} - -static gdouble -get_current_time (void) -{ - const double microseconds_per_second = (double) G_USEC_PER_SEC; - double timestamp; - GTimeVal now; - - g_get_current_time (&now); - - timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) / - microseconds_per_second; - - return timestamp; -} - -/** - * gnome_bg_crossfade_set_end_surface: - * @fade: a #GnomeBGCrossfade - * @surface: The cairo surface to fade to - * - * Before initiating a crossfade with gnome_bg_crossfade_start() - * a start and end surface have to be set. This function sets - * the surface shown at the end of the crossfade effect. - * - * Return value: %TRUE if successful, or %FALSE if the surface - * could not be copied. - **/ -gboolean -gnome_bg_crossfade_set_end_surface (GnomeBGCrossfade *fade, - cairo_surface_t *surface) -{ - g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE); - - if (fade->priv->end_surface != NULL) { - cairo_surface_destroy (fade->priv->end_surface); - fade->priv->end_surface = NULL; - } - - fade->priv->end_surface = tile_surface (surface, - fade->priv->width, - fade->priv->height); - - /* Reset timer in case we're called while animating - */ - fade->priv->start_time = get_current_time (); - return fade->priv->end_surface != NULL; -} - -static gboolean -animations_are_disabled (GnomeBGCrossfade *fade) -{ - GtkSettings *settings; - GdkScreen *screen; - gboolean are_enabled; - - g_assert (fade->priv->window != NULL); - - screen = gdk_window_get_screen (fade->priv->window); - - settings = gtk_settings_get_for_screen (screen); - - g_object_get (settings, "gtk-enable-animations", &are_enabled, NULL); - - return !are_enabled; -} - -static void -send_root_property_change_notification (GnomeBGCrossfade *fade) -{ - long zero_length_pixmap; - - /* We do a zero length append to force a change notification, - * without changing the value */ - XChangeProperty (GDK_WINDOW_XDISPLAY (fade->priv->window), - GDK_WINDOW_XID (fade->priv->window), - gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"), - XA_PIXMAP, 32, PropModeAppend, - (guchar *) &zero_length_pixmap, 0); -} - -static void -draw_background (GnomeBGCrossfade *fade) -{ - if (gdk_window_get_window_type (fade->priv->window) == GDK_WINDOW_ROOT) { - XClearArea (GDK_WINDOW_XDISPLAY (fade->priv->window), - GDK_WINDOW_XID (fade->priv->window), - 0, 0, - gdk_window_get_width (fade->priv->window), - gdk_window_get_height (fade->priv->window), - False); - - send_root_property_change_notification (fade); - - gdk_flush (); - } else { - gdk_window_invalidate_rect (fade->priv->window, NULL, FALSE); - gdk_window_process_updates (fade->priv->window, FALSE); - } -} - -static gboolean -on_tick (GnomeBGCrossfade *fade) -{ - gdouble now, percent_done; - cairo_t *cr; - cairo_status_t status; - - g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE); - - now = get_current_time (); - - percent_done = (now - fade->priv->start_time) / fade->priv->total_duration; - percent_done = CLAMP (percent_done, 0.0, 1.0); - - /* If it's taking a long time to get to the first frame, - * then lengthen the duration, so the user will get to see - * the effect. - */ - if (fade->priv->is_first_frame && percent_done > .33) { - fade->priv->is_first_frame = FALSE; - fade->priv->total_duration *= 1.5; - return on_tick (fade); - } - - if (fade->priv->fading_surface == NULL) { - return FALSE; - } - - if (animations_are_disabled (fade)) { - return FALSE; - } - - /* We accumulate the results in place for performance reasons. - * - * This means 1) The fade is exponential, not linear (looks good!) - * 2) The rate of fade is not independent of frame rate. Slower machines - * will get a slower fade (but never longer than .75 seconds), and - * even the fastest machines will get *some* fade because the framerate - * is capped. - */ - cr = cairo_create (fade->priv->fading_surface); - - cairo_set_source_surface (cr, fade->priv->end_surface, - 0.0, 0.0); - cairo_paint_with_alpha (cr, percent_done); - - status = cairo_status (cr); - cairo_destroy (cr); - - if (status == CAIRO_STATUS_SUCCESS) { - draw_background (fade); - } - return percent_done <= .99; -} - -static void -on_finished (GnomeBGCrossfade *fade) -{ - cairo_pattern_t *pattern; - - if (fade->priv->timeout_id == 0) - return; - - g_assert (fade->priv->end_surface != NULL); - - pattern = cairo_pattern_create_for_surface (fade->priv->end_surface); - gdk_window_set_background_pattern (fade->priv->window, pattern); - cairo_pattern_destroy (pattern); - - draw_background (fade); - - cairo_surface_destroy (fade->priv->end_surface); - fade->priv->end_surface = NULL; - - g_assert (fade->priv->fading_surface != NULL); - - cairo_surface_destroy (fade->priv->fading_surface); - fade->priv->fading_surface = NULL; - - fade->priv->timeout_id = 0; - g_signal_emit (fade, signals[FINISHED], 0, fade->priv->window); -} - -/** - * gnome_bg_crossfade_start: - * @fade: a #GnomeBGCrossfade - * @window: The #GdkWindow to draw crossfade on - * - * This function initiates a quick crossfade between two surfaces on - * the background of @window. Before initiating the crossfade both - * gnome_bg_crossfade_start() and gnome_bg_crossfade_end() need to - * be called. If animations are disabled, the crossfade is skipped, - * and the window background is set immediately to the end surface. - **/ -void -gnome_bg_crossfade_start (GnomeBGCrossfade *fade, - GdkWindow *window) -{ - GSource *source; - GMainContext *context; - cairo_pattern_t *pattern; - - g_return_if_fail (GNOME_IS_BG_CROSSFADE (fade)); - g_return_if_fail (window != NULL); - g_return_if_fail (fade->priv->fading_surface != NULL); - g_return_if_fail (fade->priv->end_surface != NULL); - g_return_if_fail (!gnome_bg_crossfade_is_started (fade)); - g_return_if_fail (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN); - - source = g_timeout_source_new (1000 / 60.0); - g_source_set_callback (source, - (GSourceFunc) on_tick, - fade, - (GDestroyNotify) on_finished); - context = g_main_context_default (); - fade->priv->timeout_id = g_source_attach (source, context); - g_source_unref (source); - - fade->priv->window = window; - pattern = cairo_pattern_create_for_surface (fade->priv->fading_surface); - gdk_window_set_background_pattern (fade->priv->window, pattern); - cairo_pattern_destroy (pattern); - - draw_background (fade); - - fade->priv->is_first_frame = TRUE; - fade->priv->total_duration = .75; - fade->priv->start_time = get_current_time (); -} - - -/** - * gnome_bg_crossfade_is_started: - * @fade: a #GnomeBGCrossfade - * - * This function reveals whether or not @fade is currently - * running on a window. See gnome_bg_crossfade_start() for - * information on how to initiate a crossfade. - * - * Return value: %TRUE if fading, or %FALSE if not fading - **/ -gboolean -gnome_bg_crossfade_is_started (GnomeBGCrossfade *fade) -{ - g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE); - - return fade->priv->timeout_id != 0; -} - -/** - * gnome_bg_crossfade_stop: - * @fade: a #GnomeBGCrossfade - * - * This function stops any in progress crossfades that may be - * happening. It's harmless to call this function if @fade is - * already stopped. - **/ -void -gnome_bg_crossfade_stop (GnomeBGCrossfade *fade) -{ - g_return_if_fail (GNOME_IS_BG_CROSSFADE (fade)); - - if (!gnome_bg_crossfade_is_started (fade)) - return; - - g_assert (fade->priv->timeout_id != 0); - g_source_remove (fade->priv->timeout_id); - fade->priv->timeout_id = 0; -} diff --git a/libgnome-desktop/gnome-bg-crossfade.h b/libgnome-desktop/gnome-bg-crossfade.h deleted file mode 100644 index bfab93d2..00000000 --- a/libgnome-desktop/gnome-bg-crossfade.h +++ /dev/null @@ -1,74 +0,0 @@ -/* gnome-bg-crossfade.h - fade window background between two surfaces - - Copyright 2008, Red Hat, Inc. - - This file is part of the Gnome Library. - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - Author: Ray Strode <rstrode@redhat.com> -*/ - -#ifndef __GNOME_BG_CROSSFADE_H__ -#define __GNOME_BG_CROSSFADE_H__ - -#ifndef GNOME_DESKTOP_USE_UNSTABLE_API -#error GnomeBGCrossfade is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-bg-crossfade.h -#endif - -#include <gdk/gdk.h> - -G_BEGIN_DECLS - -#define GNOME_TYPE_BG_CROSSFADE (gnome_bg_crossfade_get_type ()) -#define GNOME_BG_CROSSFADE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfade)) -#define GNOME_BG_CROSSFADE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfadeClass)) -#define GNOME_IS_BG_CROSSFADE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_BG_CROSSFADE)) -#define GNOME_IS_BG_CROSSFADE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_BG_CROSSFADE)) -#define GNOME_BG_CROSSFADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfadeClass)) - -typedef struct _GnomeBGCrossfadePrivate GnomeBGCrossfadePrivate; -typedef struct _GnomeBGCrossfade GnomeBGCrossfade; -typedef struct _GnomeBGCrossfadeClass GnomeBGCrossfadeClass; - -struct _GnomeBGCrossfade -{ - GObject parent_object; - - GnomeBGCrossfadePrivate *priv; -}; - -struct _GnomeBGCrossfadeClass -{ - GObjectClass parent_class; - - void (* finished) (GnomeBGCrossfade *fade, GdkWindow *window); -}; - -GType gnome_bg_crossfade_get_type (void); -GnomeBGCrossfade *gnome_bg_crossfade_new (int width, int height); -gboolean gnome_bg_crossfade_set_start_surface (GnomeBGCrossfade *fade, - cairo_surface_t *surface); -gboolean gnome_bg_crossfade_set_end_surface (GnomeBGCrossfade *fade, - cairo_surface_t *surface); -void gnome_bg_crossfade_start (GnomeBGCrossfade *fade, - GdkWindow *window); -gboolean gnome_bg_crossfade_is_started (GnomeBGCrossfade *fade); -void gnome_bg_crossfade_stop (GnomeBGCrossfade *fade); - -G_END_DECLS - -#endif diff --git a/libgnome-desktop/gnome-bg.c b/libgnome-desktop/gnome-bg.c deleted file mode 100644 index 749ff6ae..00000000 --- a/libgnome-desktop/gnome-bg.c +++ /dev/null @@ -1,2689 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- - -gnomebg.c: Object for the desktop background. - -Copyright (C) 2000 Eazel, Inc. -Copyright (C) 2007-2008 Red Hat, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this program; if not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. - -Derived from eel-background.c and eel-gdk-pixbuf-extensions.c by -Darin Adler <darin@eazel.com> and Ramiro Estrugo <ramiro@eazel.com> - -Author: Soren Sandmann <sandmann@redhat.com> - -*/ - -#include <string.h> -#include <math.h> -#include <stdarg.h> -#include <stdlib.h> - -#include <glib/gstdio.h> -#include <gio/gio.h> - -#include <gdk/gdkx.h> -#include <X11/Xlib.h> -#include <X11/Xatom.h> - -#include <cairo.h> -#include <cairo-xlib.h> - -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include "gnome-bg.h" -#include "gnome-bg-slide-show.h" -#include "gnome-bg-crossfade.h" - -#define BG_KEY_PRIMARY_COLOR "primary-color" -#define BG_KEY_SECONDARY_COLOR "secondary-color" -#define BG_KEY_COLOR_TYPE "color-shading-type" -#define BG_KEY_PICTURE_PLACEMENT "picture-options" -#define BG_KEY_PICTURE_OPACITY "picture-opacity" -#define BG_KEY_PICTURE_URI "picture-uri" - -/* We keep the large pixbufs around if the next update - in the slideshow is less than 60 seconds away */ -#define KEEP_EXPENSIVE_CACHE_SECS 60 - -/* This is the size of the GdkRGB dither matrix, in order to avoid - * bad dithering when tiling the gradient - */ -#define GRADIENT_PIXMAP_TILE_SIZE 128 -#define THUMBNAIL_SIZE 256 - -typedef struct FileCacheEntry FileCacheEntry; -#define CACHE_SIZE 4 - -/* - * Implementation of the GnomeBG class - */ -struct _GnomeBG -{ - GObject parent_instance; - char * filename; - GDesktopBackgroundStyle placement; - GDesktopBackgroundShading color_type; - GdkColor primary; - GdkColor secondary; - - GFileMonitor * file_monitor; - - guint changed_id; - guint transitioned_id; - guint blow_caches_id; - - /* Cached information, only access through cache accessor functions */ - GnomeBGSlideShow * slideshow; - time_t file_mtime; - GdkPixbuf * pixbuf_cache; - int timeout_id; - - GList * file_cache; -}; - -struct _GnomeBGClass -{ - GObjectClass parent_class; -}; - -enum { - CHANGED, - TRANSITIONED, - N_SIGNALS -}; - -static const cairo_user_data_key_t average_color_key; - -static guint signals[N_SIGNALS] = { 0 }; - -G_DEFINE_TYPE (GnomeBG, gnome_bg, G_TYPE_OBJECT) - -static cairo_surface_t *make_root_pixmap (GdkScreen *screen, - gint width, - gint height); - -/* Pixbuf utils */ -static void pixbuf_average_value (GdkPixbuf *pixbuf, - GdkRGBA *result); -static GdkPixbuf *pixbuf_scale_to_fit (GdkPixbuf *src, - int max_width, - int max_height); -static GdkPixbuf *pixbuf_scale_to_min (GdkPixbuf *src, - int min_width, - int min_height); -static void pixbuf_draw_gradient (GdkPixbuf *pixbuf, - gboolean horizontal, - GdkColor *c1, - GdkColor *c2, - GdkRectangle *rect); -static void pixbuf_tile (GdkPixbuf *src, - GdkPixbuf *dest); -static void pixbuf_blend (GdkPixbuf *src, - GdkPixbuf *dest, - int src_x, - int src_y, - int width, - int height, - int dest_x, - int dest_y, - double alpha); - -/* Thumbnail utilities */ -static GdkPixbuf *create_thumbnail_for_filename (GnomeDesktopThumbnailFactory *factory, - const char *filename); -static gboolean get_thumb_annotations (GdkPixbuf *thumb, - int *orig_width, - int *orig_height); - -/* Cache */ -static GdkPixbuf *get_pixbuf_for_size (GnomeBG *bg, - gint num_monitor, - int width, - int height); -static void clear_cache (GnomeBG *bg); -static gboolean is_different (GnomeBG *bg, - const char *filename); -static time_t get_mtime (const char *filename); -static GdkPixbuf *create_img_thumbnail (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - GdkScreen *screen, - int dest_width, - int dest_height, - int frame_num); -static GnomeBGSlideShow * get_as_slideshow (GnomeBG *bg, - const char *filename); -static GnomeBGSlideShow *read_slideshow_file (const char *filename, - GError **err); - -static void -color_from_string (const char *string, - GdkColor *colorp) -{ - /* If all else fails use black */ - gdk_color_parse ("black", colorp); - - if (!string) - return; - - gdk_color_parse (string, colorp); -} - -static char * -color_to_string (const GdkColor *color) -{ - return g_strdup_printf ("#%02x%02x%02x", - color->red >> 8, - color->green >> 8, - color->blue >> 8); -} - -static gboolean -do_changed (GnomeBG *bg) -{ - gboolean ignore_pending_change; - bg->changed_id = 0; - - ignore_pending_change = - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (bg), - "ignore-pending-change")); - - if (!ignore_pending_change) { - g_signal_emit (G_OBJECT (bg), signals[CHANGED], 0); - } - - return FALSE; -} - -static void -queue_changed (GnomeBG *bg) -{ - if (bg->changed_id > 0) { - g_source_remove (bg->changed_id); - } - - /* We unset this here to allow apps to set it if they don't want - to get the change event. This is used by nautilus when it - gets the pixmap from the bg (due to a reason other than the changed - event). Because if there is no other change after this time the - pending changed event will just uselessly cause us to recreate - the pixmap. */ - g_object_set_data (G_OBJECT (bg), "ignore-pending-change", - GINT_TO_POINTER (FALSE)); - bg->changed_id = g_timeout_add_full (G_PRIORITY_LOW, - 100, - (GSourceFunc)do_changed, - bg, - NULL); -} - -static gboolean -do_transitioned (GnomeBG *bg) -{ - bg->transitioned_id = 0; - - if (bg->pixbuf_cache) { - g_object_unref (bg->pixbuf_cache); - bg->pixbuf_cache = NULL; - } - - g_signal_emit (G_OBJECT (bg), signals[TRANSITIONED], 0); - - return FALSE; -} - -static void -queue_transitioned (GnomeBG *bg) -{ - if (bg->transitioned_id > 0) { - g_source_remove (bg->transitioned_id); - } - - bg->transitioned_id = g_timeout_add_full (G_PRIORITY_LOW, - 100, - (GSourceFunc)do_transitioned, - bg, - NULL); -} - -static gboolean -bg_gsettings_mapping (GVariant *value, - gpointer *result, - gpointer user_data) -{ - const gchar *bg_key_value; - char *filename = NULL; - - /* The final fallback if nothing matches is with a NULL value. */ - if (value == NULL) { - *result = NULL; - return TRUE; - } - - bg_key_value = g_variant_get_string (value, NULL); - - if (bg_key_value && *bg_key_value != '\0') { - filename = g_filename_from_uri (bg_key_value, NULL, NULL); - - if (filename != NULL && g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE) { - g_free (filename); - return FALSE; - } - - if (filename != NULL) { - *result = filename; - return TRUE; - } - } - - return FALSE; -} - -void -gnome_bg_load_from_preferences (GnomeBG *bg, - GSettings *settings) -{ - char *tmp; - char *filename; - GDesktopBackgroundShading ctype; - GdkColor c1, c2; - GDesktopBackgroundStyle placement; - - g_return_if_fail (GNOME_IS_BG (bg)); - g_return_if_fail (G_IS_SETTINGS (settings)); - - /* Filename */ - filename = g_settings_get_mapped (settings, BG_KEY_PICTURE_URI, bg_gsettings_mapping, NULL); - - /* Colors */ - tmp = g_settings_get_string (settings, BG_KEY_PRIMARY_COLOR); - color_from_string (tmp, &c1); - g_free (tmp); - - tmp = g_settings_get_string (settings, BG_KEY_SECONDARY_COLOR); - color_from_string (tmp, &c2); - g_free (tmp); - - /* Color type */ - ctype = g_settings_get_enum (settings, BG_KEY_COLOR_TYPE); - - /* Placement */ - placement = g_settings_get_enum (settings, BG_KEY_PICTURE_PLACEMENT); - - gnome_bg_set_color (bg, ctype, &c1, &c2); - gnome_bg_set_placement (bg, placement); - gnome_bg_set_filename (bg, filename); - - g_free (filename); -} - -void -gnome_bg_save_to_preferences (GnomeBG *bg, - GSettings *settings) -{ - gchar *primary; - gchar *secondary; - gchar *uri; - - g_return_if_fail (GNOME_IS_BG (bg)); - g_return_if_fail (G_IS_SETTINGS (settings)); - - primary = color_to_string (&bg->primary); - secondary = color_to_string (&bg->secondary); - - g_settings_delay (settings); - - uri = NULL; - if (bg->filename != NULL) - uri = g_filename_to_uri (bg->filename, NULL, NULL); - if (uri == NULL) - uri = g_strdup (""); - g_settings_set_string (settings, BG_KEY_PICTURE_URI, uri); - g_settings_set_string (settings, BG_KEY_PRIMARY_COLOR, primary); - g_settings_set_string (settings, BG_KEY_SECONDARY_COLOR, secondary); - g_settings_set_enum (settings, BG_KEY_COLOR_TYPE, bg->color_type); - g_settings_set_enum (settings, BG_KEY_PICTURE_PLACEMENT, bg->placement); - - /* Apply changes atomically. */ - g_settings_apply (settings); - - g_free (primary); - g_free (secondary); - g_free (uri); -} - - -static void -gnome_bg_init (GnomeBG *bg) -{ -} - -static void -gnome_bg_dispose (GObject *object) -{ - GnomeBG *bg = GNOME_BG (object); - - if (bg->file_monitor) { - g_object_unref (bg->file_monitor); - bg->file_monitor = NULL; - } - - clear_cache (bg); - - G_OBJECT_CLASS (gnome_bg_parent_class)->dispose (object); -} - -static void -gnome_bg_finalize (GObject *object) -{ - GnomeBG *bg = GNOME_BG (object); - - if (bg->changed_id != 0) { - g_source_remove (bg->changed_id); - bg->changed_id = 0; - } - - if (bg->transitioned_id != 0) { - g_source_remove (bg->transitioned_id); - bg->transitioned_id = 0; - } - - if (bg->blow_caches_id != 0) { - g_source_remove (bg->blow_caches_id); - bg->blow_caches_id = 0; - } - - g_free (bg->filename); - bg->filename = NULL; - - G_OBJECT_CLASS (gnome_bg_parent_class)->finalize (object); -} - -static void -gnome_bg_class_init (GnomeBGClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gnome_bg_dispose; - object_class->finalize = gnome_bg_finalize; - - signals[CHANGED] = g_signal_new ("changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[TRANSITIONED] = g_signal_new ("transitioned", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -GnomeBG * -gnome_bg_new (void) -{ - return g_object_new (GNOME_TYPE_BG, NULL); -} - -void -gnome_bg_set_color (GnomeBG *bg, - GDesktopBackgroundShading type, - GdkColor *primary, - GdkColor *secondary) -{ - g_return_if_fail (bg != NULL); - g_return_if_fail (primary != NULL); - - if (bg->color_type != type || - !gdk_color_equal (&bg->primary, primary) || - (secondary && !gdk_color_equal (&bg->secondary, secondary))) { - - bg->color_type = type; - bg->primary = *primary; - if (secondary) { - bg->secondary = *secondary; - } - - queue_changed (bg); - } -} - -void -gnome_bg_set_placement (GnomeBG *bg, - GDesktopBackgroundStyle placement) -{ - g_return_if_fail (bg != NULL); - - if (bg->placement != placement) { - bg->placement = placement; - - queue_changed (bg); - } -} - -GDesktopBackgroundStyle -gnome_bg_get_placement (GnomeBG *bg) -{ - g_return_val_if_fail (bg != NULL, -1); - - return bg->placement; -} - -void -gnome_bg_get_color (GnomeBG *bg, - GDesktopBackgroundShading *type, - GdkColor *primary, - GdkColor *secondary) -{ - g_return_if_fail (bg != NULL); - - if (type) - *type = bg->color_type; - - if (primary) - *primary = bg->primary; - - if (secondary) - *secondary = bg->secondary; -} - -const gchar * -gnome_bg_get_filename (GnomeBG *bg) -{ - g_return_val_if_fail (bg != NULL, NULL); - - return bg->filename; -} - -static inline gchar * -get_wallpaper_cache_dir (void) -{ - return g_build_filename (g_get_user_cache_dir(), "wallpaper", NULL); -} - -static inline gchar * -get_wallpaper_cache_prefix_name (gint num_monitor, - GDesktopBackgroundStyle placement, - gint width, - gint height) -{ - return g_strdup_printf ("%i_%i_%i_%i", num_monitor, (gint) placement, width, height); -} - -static char * -get_wallpaper_cache_filename (const char *filename, - gint num_monitor, - GDesktopBackgroundStyle placement, - gint width, - gint height) -{ - gchar *cache_filename; - gchar *cache_prefix_name; - gchar *md5_filename; - gchar *cache_basename; - gchar *cache_dir; - - md5_filename = g_compute_checksum_for_data (G_CHECKSUM_MD5, (const guchar *) filename, strlen (filename)); - cache_prefix_name = get_wallpaper_cache_prefix_name (num_monitor, placement, width, height); - cache_basename = g_strdup_printf ("%s_%s", cache_prefix_name, md5_filename); - cache_dir = get_wallpaper_cache_dir (); - cache_filename = g_build_filename (cache_dir, cache_basename, NULL); - - g_free (cache_prefix_name); - g_free (md5_filename); - g_free (cache_basename); - g_free (cache_dir); - - return cache_filename; -} - -static void -cleanup_cache_for_monitor (gchar *cache_dir, - gint num_monitor) -{ - GDir *g_cache_dir; - gchar *monitor_prefix; - const gchar *file; - - g_cache_dir = g_dir_open (cache_dir, 0, NULL); - monitor_prefix = g_strdup_printf ("%i_", num_monitor); - - file = g_dir_read_name (g_cache_dir); - while (file != NULL) { - gchar *path; - - path = g_build_filename (cache_dir, file, NULL); - /* purge files with same monitor id */ - if (g_str_has_prefix (file, monitor_prefix) && - g_file_test (path, G_FILE_TEST_IS_REGULAR)) - g_unlink (path); - - g_free (path); - - file = g_dir_read_name (g_cache_dir); - } - - g_free (monitor_prefix); - g_dir_close (g_cache_dir); -} - -static gboolean -cache_file_is_valid (const char *filename, - const char *cache_filename) -{ - time_t mtime; - time_t cache_mtime; - - if (!g_file_test (cache_filename, G_FILE_TEST_IS_REGULAR)) - return FALSE; - - mtime = get_mtime (filename); - cache_mtime = get_mtime (cache_filename); - - return (mtime < cache_mtime); -} - -static void -refresh_cache_file (GnomeBG *bg, - GdkPixbuf *new_pixbuf, - gint num_monitor, - gint width, - gint height) -{ - gchar *cache_filename; - gchar *cache_dir; - GdkPixbufFormat *format; - gchar *format_name; - - if ((num_monitor == -1) || (width <= 300) || (height <= 300)) - return; - - cache_filename = get_wallpaper_cache_filename (bg->filename, num_monitor, bg->placement, width, height); - cache_dir = get_wallpaper_cache_dir (); - - /* Only refresh scaled file on disk if useful (and don't cache slideshow) */ - if (!cache_file_is_valid (bg->filename, cache_filename)) { - format = gdk_pixbuf_get_file_info (bg->filename, NULL, NULL); - - if (format != NULL) { - if (!g_file_test (cache_dir, G_FILE_TEST_IS_DIR)) { - g_mkdir_with_parents (cache_dir, 0700); - } else { - cleanup_cache_for_monitor (cache_dir, num_monitor); - } - - format_name = gdk_pixbuf_format_get_name (format); - - if (strcmp (format_name, "jpeg") == 0) - gdk_pixbuf_save (new_pixbuf, cache_filename, format_name, NULL, "quality", "100", NULL); - else - gdk_pixbuf_save (new_pixbuf, cache_filename, format_name, NULL, NULL); - - g_free (format_name); - } - } - - g_free (cache_filename); - g_free (cache_dir); -} - -static void -file_changed (GFileMonitor *file_monitor, - GFile *child, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - GnomeBG *bg = GNOME_BG (user_data); - - clear_cache (bg); - queue_changed (bg); -} - -void -gnome_bg_set_filename (GnomeBG *bg, - const char *filename) -{ - g_return_if_fail (bg != NULL); - - if (is_different (bg, filename)) { - g_free (bg->filename); - - bg->filename = g_strdup (filename); - bg->file_mtime = get_mtime (bg->filename); - - if (bg->file_monitor) { - g_object_unref (bg->file_monitor); - bg->file_monitor = NULL; - } - - if (bg->filename) { - GFile *f = g_file_new_for_path (bg->filename); - - bg->file_monitor = g_file_monitor_file (f, 0, NULL, NULL); - g_signal_connect (bg->file_monitor, "changed", - G_CALLBACK (file_changed), bg); - - g_object_unref (f); - } - - clear_cache (bg); - - queue_changed (bg); - } -} - -static void -draw_color_area (GnomeBG *bg, - GdkPixbuf *dest, - GdkRectangle *rect) -{ - guint32 pixel; - GdkRectangle extent; - - extent.x = 0; - extent.y = 0; - extent.width = gdk_pixbuf_get_width (dest); - extent.height = gdk_pixbuf_get_height (dest); - - gdk_rectangle_intersect (rect, &extent, rect); - - switch (bg->color_type) { - case G_DESKTOP_BACKGROUND_SHADING_SOLID: - /* not really a big deal to ignore the area of interest */ - pixel = ((bg->primary.red >> 8) << 24) | - ((bg->primary.green >> 8) << 16) | - ((bg->primary.blue >> 8) << 8) | - (0xff); - - gdk_pixbuf_fill (dest, pixel); - break; - - case G_DESKTOP_BACKGROUND_SHADING_HORIZONTAL: - pixbuf_draw_gradient (dest, TRUE, &(bg->primary), &(bg->secondary), rect); - break; - - case G_DESKTOP_BACKGROUND_SHADING_VERTICAL: - pixbuf_draw_gradient (dest, FALSE, &(bg->primary), &(bg->secondary), rect); - break; - - default: - break; - } -} - -static void -draw_color (GnomeBG *bg, - GdkPixbuf *dest) -{ - GdkRectangle rect; - rect.x = 0; - rect.y = 0; - rect.width = gdk_pixbuf_get_width (dest); - rect.height = gdk_pixbuf_get_height (dest); - draw_color_area (bg, dest, &rect); -} - -static void -draw_color_each_monitor (GnomeBG *bg, - GdkPixbuf *dest, - GdkScreen *screen) -{ - GdkRectangle rect; - gint num_monitors; - int monitor; - - num_monitors = gdk_screen_get_n_monitors (screen); - for (monitor = 0; monitor < num_monitors; monitor++) { - gdk_screen_get_monitor_geometry (screen, monitor, &rect); - draw_color_area (bg, dest, &rect); - } -} - -static GdkPixbuf * -pixbuf_clip_to_fit (GdkPixbuf *src, - int max_width, - int max_height) -{ - int src_width, src_height; - int w, h; - int src_x, src_y; - GdkPixbuf *pixbuf; - - src_width = gdk_pixbuf_get_width (src); - src_height = gdk_pixbuf_get_height (src); - - if (src_width < max_width && src_height < max_height) - return g_object_ref (src); - - w = MIN(src_width, max_width); - h = MIN(src_height, max_height); - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, - gdk_pixbuf_get_has_alpha (src), - 8, w, h); - - src_x = (src_width - w) / 2; - src_y = (src_height - h) / 2; - gdk_pixbuf_copy_area (src, - src_x, src_y, - w, h, - pixbuf, - 0, 0); - return pixbuf; -} - -static GdkPixbuf * -get_scaled_pixbuf (GDesktopBackgroundStyle placement, - GdkPixbuf *pixbuf, - int width, int height, - int *x, int *y, - int *w, int *h) -{ - GdkPixbuf *new; - -#if 0 - g_print ("original_width: %d %d\n", - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); -#endif - - switch (placement) { - case G_DESKTOP_BACKGROUND_STYLE_SPANNED: - new = pixbuf_scale_to_fit (pixbuf, width, height); - break; - case G_DESKTOP_BACKGROUND_STYLE_ZOOM: - new = pixbuf_scale_to_min (pixbuf, width, height); - break; - - case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: - new = gdk_pixbuf_scale_simple (pixbuf, width, height, - GDK_INTERP_BILINEAR); - break; - - case G_DESKTOP_BACKGROUND_STYLE_SCALED: - new = pixbuf_scale_to_fit (pixbuf, width, height); - break; - - case G_DESKTOP_BACKGROUND_STYLE_CENTERED: - case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: - default: - new = pixbuf_clip_to_fit (pixbuf, width, height); - break; - } - - *w = gdk_pixbuf_get_width (new); - *h = gdk_pixbuf_get_height (new); - *x = (width - *w) / 2; - *y = (height - *h) / 2; - - return new; -} - -static void -draw_image_area (GnomeBG *bg, - gint num_monitor, - GdkPixbuf *pixbuf, - GdkPixbuf *dest, - GdkRectangle *area) -{ - int dest_width = area->width; - int dest_height = area->height; - int x, y, w, h; - GdkPixbuf *scaled; - - if (!pixbuf) - return; - - scaled = get_scaled_pixbuf (bg->placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h); - - switch (bg->placement) { - case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: - pixbuf_tile (scaled, dest); - break; - case G_DESKTOP_BACKGROUND_STYLE_ZOOM: - case G_DESKTOP_BACKGROUND_STYLE_CENTERED: - case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: - case G_DESKTOP_BACKGROUND_STYLE_SCALED: - pixbuf_blend (scaled, dest, 0, 0, w, h, x + area->x, y + area->y, 1.0); - break; - case G_DESKTOP_BACKGROUND_STYLE_SPANNED: - pixbuf_blend (scaled, dest, 0, 0, w, h, x, y, 1.0); - break; - default: - g_assert_not_reached (); - break; - } - - refresh_cache_file (bg, scaled, num_monitor, dest_width, dest_height); - - g_object_unref (scaled); -} - -static void -draw_image_for_thumb (GnomeBG *bg, - GdkPixbuf *pixbuf, - GdkPixbuf *dest) -{ - GdkRectangle rect; - - rect.x = 0; - rect.y = 0; - rect.width = gdk_pixbuf_get_width (dest); - rect.height = gdk_pixbuf_get_height (dest); - - draw_image_area (bg, -1, pixbuf, dest, &rect); -} - -static void -draw_once (GnomeBG *bg, - GdkPixbuf *dest) -{ - GdkRectangle rect; - GdkPixbuf *pixbuf; - gint num_monitor; - - /* we just draw on the whole screen */ - num_monitor = 0; - - rect.x = 0; - rect.y = 0; - rect.width = gdk_pixbuf_get_width (dest); - rect.height = gdk_pixbuf_get_height (dest); - - pixbuf = get_pixbuf_for_size (bg, num_monitor, rect.width, rect.height); - if (pixbuf) { - draw_image_area (bg, - num_monitor, - pixbuf, - dest, - &rect); - g_object_unref (pixbuf); - } -} - -static void -draw_each_monitor (GnomeBG *bg, - GdkPixbuf *dest, - GdkScreen *screen) -{ - GdkRectangle rect; - gint num_monitors; - int monitor; - - num_monitors = gdk_screen_get_n_monitors (screen); - for (monitor = 0; monitor < num_monitors; monitor++) { - GdkPixbuf *pixbuf; - gdk_screen_get_monitor_geometry (screen, monitor, &rect); - pixbuf = get_pixbuf_for_size (bg, monitor, rect.width, rect.height); - if (pixbuf) { - draw_image_area (bg, - monitor, - pixbuf, - dest, &rect); - g_object_unref (pixbuf); - } - } -} - -void -gnome_bg_draw (GnomeBG *bg, - GdkPixbuf *dest, - GdkScreen *screen, - gboolean is_root) -{ - if (!bg) - return; - - if (is_root && (bg->placement != G_DESKTOP_BACKGROUND_STYLE_SPANNED)) { - draw_color_each_monitor (bg, dest, screen); - if (bg->placement != G_DESKTOP_BACKGROUND_STYLE_NONE) { - draw_each_monitor (bg, dest, screen); - } - } else { - draw_color (bg, dest); - if (bg->placement != G_DESKTOP_BACKGROUND_STYLE_NONE) { - draw_once (bg, dest); - } - } -} - -gboolean -gnome_bg_has_multiple_sizes (GnomeBG *bg) -{ - GnomeBGSlideShow *show; - gboolean ret; - - g_return_val_if_fail (bg != NULL, FALSE); - - ret = FALSE; - - show = get_as_slideshow (bg, bg->filename); - if (show) { - ret = gnome_bg_slide_show_get_has_multiple_sizes (show); - g_object_unref (show); - } - - return ret; -} - -static void -gnome_bg_get_pixmap_size (GnomeBG *bg, - int width, - int height, - int *pixmap_width, - int *pixmap_height) -{ - int dummy; - - if (!pixmap_width) - pixmap_width = &dummy; - if (!pixmap_height) - pixmap_height = &dummy; - - *pixmap_width = width; - *pixmap_height = height; - - if (!bg->filename) { - switch (bg->color_type) { - case G_DESKTOP_BACKGROUND_SHADING_SOLID: - *pixmap_width = 1; - *pixmap_height = 1; - break; - - case G_DESKTOP_BACKGROUND_SHADING_HORIZONTAL: - case G_DESKTOP_BACKGROUND_SHADING_VERTICAL: - break; - } - - return; - } -} - -/** - * gnome_bg_create_surface: - * @bg: GnomeBG - * @window: - * @width: - * @height: - * @root: - * - * Create a surface that can be set as background for @window. If @is_root is - * TRUE, the surface created will be created by a temporary X server connection - * so that if someone calls XKillClient on it, it won't affect the application - * who created it. - * - * Returns: %NULL on error (e.g. out of X connections) - **/ -cairo_surface_t * -gnome_bg_create_surface (GnomeBG *bg, - GdkWindow *window, - int width, - int height, - gboolean root) -{ - int pm_width, pm_height; - cairo_surface_t *surface; - GdkRGBA average; - cairo_t *cr; - - g_return_val_if_fail (bg != NULL, NULL); - g_return_val_if_fail (window != NULL, NULL); - - if (bg->pixbuf_cache && - gdk_pixbuf_get_width (bg->pixbuf_cache) != width && - gdk_pixbuf_get_height (bg->pixbuf_cache) != height) { - g_object_unref (bg->pixbuf_cache); - bg->pixbuf_cache = NULL; - } - - /* has the side effect of loading and caching pixbuf only when in tile mode */ - gnome_bg_get_pixmap_size (bg, width, height, &pm_width, &pm_height); - - if (root) { - surface = make_root_pixmap (gdk_window_get_screen (window), - pm_width, pm_height); - } - else { - surface = gdk_window_create_similar_surface (window, - CAIRO_CONTENT_COLOR, - pm_width, pm_height); - } - - if (surface == NULL) - return NULL; - - cr = cairo_create (surface); - if (!bg->filename && bg->color_type == G_DESKTOP_BACKGROUND_SHADING_SOLID) { - gdk_cairo_set_source_color (cr, &(bg->primary)); - average.red = bg->primary.red / 65535.0; - average.green = bg->primary.green / 65535.0; - average.blue = bg->primary.blue / 65535.0; - average.alpha = 1.0; - } - else { - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, - width, height); - gnome_bg_draw (bg, pixbuf, gdk_window_get_screen (window), root); - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); - pixbuf_average_value (pixbuf, &average); - g_object_unref (pixbuf); - } - - cairo_paint (cr); - - cairo_destroy (cr); - - cairo_surface_set_user_data (surface, &average_color_key, - gdk_rgba_copy (&average), - (cairo_destroy_func_t) gdk_rgba_free); - - return surface; -} - - -/* determine if a background is darker or lighter than average, to help - * clients know what colors to draw on top with - */ -gboolean -gnome_bg_is_dark (GnomeBG *bg, - int width, - int height) -{ - GdkColor color; - int intensity; - GdkPixbuf *pixbuf; - - g_return_val_if_fail (bg != NULL, FALSE); - - if (bg->color_type == G_DESKTOP_BACKGROUND_SHADING_SOLID) { - color = bg->primary; - } else { - color.red = (bg->primary.red + bg->secondary.red) / 2; - color.green = (bg->primary.green + bg->secondary.green) / 2; - color.blue = (bg->primary.blue + bg->secondary.blue) / 2; - } - pixbuf = get_pixbuf_for_size (bg, -1, width, height); - if (pixbuf) { - GdkRGBA argb; - guchar a, r, g, b; - - pixbuf_average_value (pixbuf, &argb); - a = argb.alpha * 0xff; - r = argb.red * 0xff; - g = argb.green * 0xff; - b = argb.blue * 0xff; - - color.red = (color.red * (0xFF - a) + r * 0x101 * a) / 0xFF; - color.green = (color.green * (0xFF - a) + g * 0x101 * a) / 0xFF; - color.blue = (color.blue * (0xFF - a) + b * 0x101 * a) / 0xFF; - g_object_unref (pixbuf); - } - - intensity = (color.red * 77 + - color.green * 150 + - color.blue * 28) >> 16; - - return intensity < 160; /* biased slightly to be dark */ -} - -/* - * Create a persistent pixmap. We create a separate display - * and set the closedown mode on it to RetainPermanent. - */ -static cairo_surface_t * -make_root_pixmap (GdkScreen *screen, gint width, gint height) -{ - Display *display; - const char *display_name; - Pixmap result; - cairo_surface_t *surface; - int screen_num; - int depth; - - screen_num = gdk_screen_get_number (screen); - - gdk_flush (); - - display_name = gdk_display_get_name (gdk_screen_get_display (screen)); - display = XOpenDisplay (display_name); - - if (display == NULL) { - g_warning ("Unable to open display '%s' when setting " - "background pixmap\n", - (display_name) ? display_name : "NULL"); - return NULL; - } - - /* Desktop background pixmap should be created from - * dummy X client since most applications will try to - * kill it with XKillClient later when changing pixmap - */ - - XSetCloseDownMode (display, RetainPermanent); - - depth = DefaultDepth (display, screen_num); - - result = XCreatePixmap (display, - RootWindow (display, screen_num), - width, height, depth); - - XCloseDisplay (display); - - surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen), - result, - GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)), - width, height); - - return surface; -} - -static gboolean -get_original_size (const char *filename, - int *orig_width, - int *orig_height) -{ - gboolean result; - - if (gdk_pixbuf_get_file_info (filename, orig_width, orig_height)) - result = TRUE; - else - result = FALSE; - - return result; -} - -static const char * -get_filename_for_size (GnomeBG *bg, gint best_width, gint best_height) -{ - GnomeBGSlideShow *show; - const char *file = NULL; - - if (!bg->filename) - return NULL; - - show = get_as_slideshow (bg, bg->filename); - if (!show) { - return bg->filename; - } - - gnome_bg_slide_show_get_current_slide (show, best_width, best_height, NULL, NULL, NULL, &file, NULL); - g_object_unref (show); - - return file; -} - -gboolean -gnome_bg_get_image_size (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - int best_width, - int best_height, - int *width, - int *height) -{ - GdkPixbuf *thumb; - gboolean result = FALSE; - const gchar *filename; - - g_return_val_if_fail (bg != NULL, FALSE); - g_return_val_if_fail (factory != NULL, FALSE); - - if (!bg->filename) - return FALSE; - - filename = get_filename_for_size (bg, best_width, best_height); - thumb = create_thumbnail_for_filename (factory, filename); - if (thumb) { - if (get_thumb_annotations (thumb, width, height)) - result = TRUE; - - g_object_unref (thumb); - } - - if (!result) { - if (get_original_size (filename, width, height)) - result = TRUE; - } - - return result; -} - -static double -fit_factor (int from_width, int from_height, - int to_width, int to_height) -{ - return MIN (to_width / (double) from_width, to_height / (double) from_height); -} - -/** - * gnome_bg_create_thumbnail: - * - * Returns: (transfer full): a #GdkPixbuf showing the background as a thumbnail - */ -GdkPixbuf * -gnome_bg_create_thumbnail (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - GdkScreen *screen, - int dest_width, - int dest_height) -{ - GdkPixbuf *result; - GdkPixbuf *thumb; - - g_return_val_if_fail (bg != NULL, NULL); - - result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, dest_width, dest_height); - - draw_color (bg, result); - - if (bg->placement != G_DESKTOP_BACKGROUND_STYLE_NONE) { - thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, -1); - - if (thumb) { - draw_image_for_thumb (bg, thumb, result); - g_object_unref (thumb); - } - } - - return result; -} - -/** - * gnome_bg_get_surface_from_root: - * @screen: a #GdkScreen - * - * This function queries the _XROOTPMAP_ID property from - * the root window associated with @screen to determine - * the current root window background pixmap and returns - * a copy of it. If the _XROOTPMAP_ID is not set, then - * a black surface is returned. - * - * Return value: a #cairo_surface_t if successful or %NULL - **/ -cairo_surface_t * -gnome_bg_get_surface_from_root (GdkScreen *screen) -{ - int result; - gint format; - gulong nitems; - gulong bytes_after; - guchar *data; - Atom type; - Display *display; - int screen_num; - cairo_surface_t *surface; - cairo_surface_t *source_pixmap; - int width, height; - cairo_t *cr; - - display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); - screen_num = gdk_screen_get_number (screen); - - result = XGetWindowProperty (display, - RootWindow (display, screen_num), - gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"), - 0L, 1L, False, XA_PIXMAP, - &type, &format, &nitems, &bytes_after, - &data); - surface = NULL; - source_pixmap = NULL; - - if (result != Success || type != XA_PIXMAP || - format != 32 || nitems != 1) { - XFree (data); - data = NULL; - } - - if (data != NULL) { - Pixmap xpixmap = *(Pixmap *) data; - Window root_return; - int x_ret, y_ret; - unsigned int w_ret, h_ret, bw_ret, depth_ret; - - gdk_error_trap_push (); - if (XGetGeometry (GDK_SCREEN_XDISPLAY (screen), - xpixmap, - &root_return, - &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret)) { - source_pixmap = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen), - xpixmap, - GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)), - w_ret, h_ret); - } - - gdk_error_trap_pop_ignored (); - } - - width = gdk_screen_get_width (screen); - height = gdk_screen_get_height (screen); - - if (source_pixmap) { - surface = cairo_surface_create_similar (source_pixmap, - CAIRO_CONTENT_COLOR, - width, height); - - cr = cairo_create (surface); - cairo_set_source_surface (cr, source_pixmap, 0, 0); - cairo_paint (cr); - - if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy (surface); - surface = NULL; - } - - cairo_destroy (cr); - } - - if (surface == NULL) { - surface = gdk_window_create_similar_surface (gdk_screen_get_root_window (screen), - CAIRO_CONTENT_COLOR, - width, height); - } - - if (source_pixmap != NULL) - cairo_surface_destroy (source_pixmap); - - if (data != NULL) - XFree (data); - - return surface; -} - -static void -gnome_bg_set_root_pixmap_id (GdkScreen *screen, - cairo_surface_t *surface) -{ - int result; - gint format; - gulong nitems; - gulong bytes_after; - guchar *data_esetroot; - Pixmap pixmap_id; - Atom type; - Display *display; - int screen_num; - GdkRGBA *average; - - screen_num = gdk_screen_get_number (screen); - data_esetroot = NULL; - - display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); - - result = XGetWindowProperty (display, - RootWindow (display, screen_num), - gdk_x11_get_xatom_by_name ("ESETROOT_PMAP_ID"), - 0L, 1L, False, XA_PIXMAP, - &type, &format, &nitems, - &bytes_after, - &data_esetroot); - - if (data_esetroot != NULL) { - if (result == Success && type == XA_PIXMAP && - format == 32 && - nitems == 1) { - gdk_error_trap_push (); - XKillClient (display, *(Pixmap *)data_esetroot); - gdk_error_trap_pop_ignored (); - } - XFree (data_esetroot); - } - - pixmap_id = cairo_xlib_surface_get_drawable (surface); - - XChangeProperty (display, RootWindow (display, screen_num), - gdk_x11_get_xatom_by_name ("ESETROOT_PMAP_ID"), - XA_PIXMAP, 32, PropModeReplace, - (guchar *) &pixmap_id, 1); - XChangeProperty (display, RootWindow (display, screen_num), - gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"), XA_PIXMAP, - 32, PropModeReplace, - (guchar *) &pixmap_id, 1); - - average = cairo_surface_get_user_data (surface, &average_color_key); - if (average != NULL) { - gchar *string; - - string = gdk_rgba_to_string (average); - - /* X encodes string lists as one big string with a nul - * terminator after each item in the list. That's why - * the strlen has to be given; scanning for nul would - * only find the first item. - * - * For now, we only want to set a single string. - * Fortunately, since this is C, it comes with its own - * nul and we can just give strlen + 1 for the size of - * our "list". - */ - XChangeProperty (display, RootWindow (display, screen_num), - gdk_x11_get_xatom_by_name ("_GNOME_BACKGROUND_REPRESENTATIVE_COLORS"), - XA_STRING, 8, PropModeReplace, - (guchar *) string, strlen (string) + 1); - g_free (string); - } else { - /* Could happen if we didn't create the surface... */ - XDeleteProperty (display, RootWindow (display, screen_num), - gdk_x11_get_xatom_by_name ("_GNOME_BACKGROUND_REPRESENTATIVE_COLORS")); - } -} - -/** - * gnome_bg_set_surface_as_root: - * @screen: the #GdkScreen to change root background on - * @surface: the #cairo_surface_t to set root background from. - * Must be an xlib surface backing a pixmap. - * - * Set the root pixmap, and properties pointing to it. We - * do this atomically with a server grab to make sure that - * we won't leak the pixmap if somebody else it setting - * it at the same time. (This assumes that they follow the - * same conventions we do). @surface should come from a call - * to gnome_bg_create_surface(). - **/ -void -gnome_bg_set_surface_as_root (GdkScreen *screen, cairo_surface_t *surface) -{ - Display *display; - int screen_num; - - g_return_if_fail (screen != NULL); - g_return_if_fail (surface != NULL); - g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB); - - screen_num = gdk_screen_get_number (screen); - - display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); - - gdk_x11_display_grab (gdk_screen_get_display (screen)); - - gnome_bg_set_root_pixmap_id (screen, surface); - - XSetWindowBackgroundPixmap (display, RootWindow (display, screen_num), - cairo_xlib_surface_get_drawable (surface)); - XClearWindow (display, RootWindow (display, screen_num)); - - gdk_display_flush (gdk_screen_get_display (screen)); - gdk_x11_display_ungrab (gdk_screen_get_display (screen)); -} - -/** - * gnome_bg_set_surface_as_root_with_crossfade: - * @screen: the #GdkScreen to change root background on - * @surface: the cairo xlib surface to set root background from - * - * Set the root pixmap, and properties pointing to it. - * This function differs from gnome_bg_set_surface_as_root() - * in that it adds a subtle crossfade animation from the - * current root pixmap to the new one. - * - * Return value: (transfer full): a #GnomeBGCrossfade object - **/ -GnomeBGCrossfade * -gnome_bg_set_surface_as_root_with_crossfade (GdkScreen *screen, - cairo_surface_t *surface) -{ - GdkDisplay *display; - GdkWindow *root_window; - cairo_surface_t *old_surface; - int width, height; - GnomeBGCrossfade *fade; - - g_return_val_if_fail (screen != NULL, NULL); - g_return_val_if_fail (surface != NULL, NULL); - - root_window = gdk_screen_get_root_window (screen); - - width = gdk_screen_get_width (screen); - height = gdk_screen_get_height (screen); - - fade = gnome_bg_crossfade_new (width, height); - - display = gdk_screen_get_display (screen); - gdk_x11_display_grab (display); - old_surface = gnome_bg_get_surface_from_root (screen); - gnome_bg_set_root_pixmap_id (screen, surface); - gnome_bg_crossfade_set_start_surface (fade, old_surface); - cairo_surface_destroy (old_surface); - gnome_bg_crossfade_set_end_surface (fade, surface); - gdk_display_flush (display); - gdk_x11_display_ungrab (display); - - gnome_bg_crossfade_start (fade, root_window); - - return fade; -} - -/* Implementation of the pixbuf cache */ -struct _SlideShow -{ - gint ref_count; - double start_time; - double total_duration; - - GQueue *slides; - - gboolean has_multiple_sizes; - - /* used during parsing */ - struct tm start_tm; - GQueue *stack; -}; - - -static GdkPixbuf * -blend (GdkPixbuf *p1, - GdkPixbuf *p2, - double alpha) -{ - GdkPixbuf *result = gdk_pixbuf_copy (p1); - GdkPixbuf *tmp; - - if (gdk_pixbuf_get_width (p2) != gdk_pixbuf_get_width (p1) || - gdk_pixbuf_get_height (p2) != gdk_pixbuf_get_height (p1)) { - tmp = gdk_pixbuf_scale_simple (p2, - gdk_pixbuf_get_width (p1), - gdk_pixbuf_get_height (p1), - GDK_INTERP_BILINEAR); - } - else { - tmp = g_object_ref (p2); - } - - pixbuf_blend (tmp, result, 0, 0, -1, -1, 0, 0, alpha); - - g_object_unref (tmp); - - return result; -} - -typedef enum { - PIXBUF, - SLIDESHOW, - THUMBNAIL -} FileType; - -struct FileCacheEntry -{ - FileType type; - char *filename; - union { - GdkPixbuf *pixbuf; - GnomeBGSlideShow *slideshow; - GdkPixbuf *thumbnail; - } u; -}; - -static void -file_cache_entry_delete (FileCacheEntry *ent) -{ - g_free (ent->filename); - - switch (ent->type) { - case PIXBUF: - g_object_unref (ent->u.pixbuf); - break; - case SLIDESHOW: - g_object_unref (ent->u.slideshow); - break; - case THUMBNAIL: - g_object_unref (ent->u.thumbnail); - break; - } - - g_free (ent); -} - -static void -bound_cache (GnomeBG *bg) -{ - while (g_list_length (bg->file_cache) >= CACHE_SIZE) { - GList *last_link = g_list_last (bg->file_cache); - FileCacheEntry *ent = last_link->data; - - file_cache_entry_delete (ent); - - bg->file_cache = g_list_delete_link (bg->file_cache, last_link); - } -} - -static const FileCacheEntry * -file_cache_lookup (GnomeBG *bg, FileType type, const char *filename) -{ - GList *list; - - for (list = bg->file_cache; list != NULL; list = list->next) { - FileCacheEntry *ent = list->data; - - if (ent && ent->type == type && - strcmp (ent->filename, filename) == 0) { - return ent; - } - } - - return NULL; -} - -static FileCacheEntry * -file_cache_entry_new (GnomeBG *bg, - FileType type, - const char *filename) -{ - FileCacheEntry *ent = g_new0 (FileCacheEntry, 1); - - g_assert (!file_cache_lookup (bg, type, filename)); - - ent->type = type; - ent->filename = g_strdup (filename); - - bg->file_cache = g_list_prepend (bg->file_cache, ent); - - bound_cache (bg); - - return ent; -} - -static void -file_cache_add_pixbuf (GnomeBG *bg, - const char *filename, - GdkPixbuf *pixbuf) -{ - FileCacheEntry *ent = file_cache_entry_new (bg, PIXBUF, filename); - ent->u.pixbuf = g_object_ref (pixbuf); -} - -static void -file_cache_add_thumbnail (GnomeBG *bg, - const char *filename, - GdkPixbuf *pixbuf) -{ - FileCacheEntry *ent = file_cache_entry_new (bg, THUMBNAIL, filename); - ent->u.thumbnail = g_object_ref (pixbuf); -} - -static void -file_cache_add_slide_show (GnomeBG *bg, - const char *filename, - GnomeBGSlideShow *show) -{ - FileCacheEntry *ent = file_cache_entry_new (bg, SLIDESHOW, filename); - ent->u.slideshow = g_object_ref (show); -} - -static GdkPixbuf * -load_from_cache_file (GnomeBG *bg, - const char *filename, - gint num_monitor, - gint best_width, - gint best_height) -{ - GdkPixbuf *pixbuf = NULL; - gchar *cache_filename; - - cache_filename = get_wallpaper_cache_filename (filename, num_monitor, bg->placement, best_width, best_height); - if (cache_file_is_valid (filename, cache_filename)) - pixbuf = gdk_pixbuf_new_from_file (cache_filename, NULL); - g_free (cache_filename); - - return pixbuf; -} - -static GdkPixbuf * -get_as_pixbuf_for_size (GnomeBG *bg, - const char *filename, - gint num_monitor, - gint best_width, - gint best_height) -{ - const FileCacheEntry *ent; - if ((ent = file_cache_lookup (bg, PIXBUF, filename))) { - return g_object_ref (ent->u.pixbuf); - } - else { - GdkPixbufFormat *format; - GdkPixbuf *pixbuf; - gchar *tmp; - pixbuf = NULL; - - /* Try to hit local cache first if relevant */ - if (num_monitor != -1) - pixbuf = load_from_cache_file (bg, filename, num_monitor, best_width, best_height); - - if (!pixbuf) { - /* If scalable choose maximum size */ - format = gdk_pixbuf_get_file_info (filename, NULL, NULL); - - if (format != NULL) { - tmp = gdk_pixbuf_format_get_name (format); - } else { - tmp = NULL; - } - - if (tmp != NULL && - strcmp (tmp, "svg") == 0 && - (best_width > 0 && best_height > 0) && - (bg->placement == G_DESKTOP_BACKGROUND_STYLE_STRETCHED || - bg->placement == G_DESKTOP_BACKGROUND_STYLE_SCALED || - bg->placement == G_DESKTOP_BACKGROUND_STYLE_ZOOM)) - pixbuf = gdk_pixbuf_new_from_file_at_size (filename, best_width, best_height, NULL); - else - pixbuf = gdk_pixbuf_new_from_file (filename, NULL); - g_free (tmp); - } - - if (pixbuf) - file_cache_add_pixbuf (bg, filename, pixbuf); - - return pixbuf; - } -} - -static GnomeBGSlideShow * -get_as_slideshow (GnomeBG *bg, const char *filename) -{ - const FileCacheEntry *ent; - if ((ent = file_cache_lookup (bg, SLIDESHOW, filename))) { - return g_object_ref (ent->u.slideshow); - } - else { - GnomeBGSlideShow *show = read_slideshow_file (filename, NULL); - - if (show) - file_cache_add_slide_show (bg, filename, show); - - return show; - } -} - -static GdkPixbuf * -get_as_thumbnail (GnomeBG *bg, GnomeDesktopThumbnailFactory *factory, const char *filename) -{ - const FileCacheEntry *ent; - if ((ent = file_cache_lookup (bg, THUMBNAIL, filename))) { - return g_object_ref (ent->u.thumbnail); - } - else { - GdkPixbuf *thumb = create_thumbnail_for_filename (factory, filename); - - if (thumb) - file_cache_add_thumbnail (bg, filename, thumb); - - return thumb; - } -} - -static gboolean -blow_expensive_caches (gpointer data) -{ - GnomeBG *bg = data; - GList *list, *next; - - bg->blow_caches_id = 0; - - for (list = bg->file_cache; list != NULL; list = next) { - FileCacheEntry *ent = list->data; - next = list->next; - - if (ent->type == PIXBUF) { - file_cache_entry_delete (ent); - bg->file_cache = g_list_delete_link (bg->file_cache, - list); - } - } - - if (bg->pixbuf_cache) { - g_object_unref (bg->pixbuf_cache); - bg->pixbuf_cache = NULL; - } - - return FALSE; -} - -static void -blow_expensive_caches_in_idle (GnomeBG *bg) -{ - if (bg->blow_caches_id == 0) { - bg->blow_caches_id = - g_idle_add (blow_expensive_caches, - bg); - } -} - - -static gboolean -on_timeout (gpointer data) -{ - GnomeBG *bg = data; - - bg->timeout_id = 0; - - queue_transitioned (bg); - - return FALSE; -} - -static double -get_slide_timeout (gboolean is_fixed, - gdouble duration) -{ - double timeout; - if (is_fixed) { - timeout = duration; - } else { - /* Maybe the number of steps should be configurable? */ - - /* In the worst case we will do a fade from 0 to 256, which mean - * we will never use more than 255 steps, however in most cases - * the first and last value are similar and users can't percieve - * changes in pixel values as small as 1/255th. So, lets not waste - * CPU cycles on transitioning to often. - * - * 64 steps is enough for each step to be just detectable in a 16bit - * color mode in the worst case, so we'll use this as an approximation - * of whats detectable. - */ - timeout = duration / 64.0; - } - return timeout; -} - -static void -ensure_timeout (GnomeBG *bg, - gdouble timeout) -{ - if (!bg->timeout_id) { - /* G_MAXUINT means "only one slide" */ - if (timeout < G_MAXUINT) { - bg->timeout_id = g_timeout_add_full ( - G_PRIORITY_LOW, - timeout * 1000, on_timeout, bg, NULL); - } - } -} - -static time_t -get_mtime (const char *filename) -{ - GFile *file; - GFileInfo *info; - time_t mtime; - - mtime = (time_t)-1; - - if (filename) { - file = g_file_new_for_path (filename); - info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, - G_FILE_QUERY_INFO_NONE, NULL, NULL); - if (info) { - mtime = g_file_info_get_attribute_uint64 (info, - G_FILE_ATTRIBUTE_TIME_MODIFIED); - g_object_unref (info); - } - g_object_unref (file); - } - - return mtime; -} - -static GdkPixbuf * -scale_thumbnail (GDesktopBackgroundStyle placement, - const char *filename, - GdkPixbuf *thumb, - GdkScreen *screen, - int dest_width, - int dest_height) -{ - int o_width; - int o_height; - - if (placement != G_DESKTOP_BACKGROUND_STYLE_WALLPAPER && - placement != G_DESKTOP_BACKGROUND_STYLE_CENTERED) { - - /* In this case, the pixbuf will be scaled to fit the screen anyway, - * so just return the pixbuf here - */ - return g_object_ref (thumb); - } - - if (get_thumb_annotations (thumb, &o_width, &o_height) || - (filename && get_original_size (filename, &o_width, &o_height))) { - - int scr_height = gdk_screen_get_height (screen); - int scr_width = gdk_screen_get_width (screen); - int thumb_width = gdk_pixbuf_get_width (thumb); - int thumb_height = gdk_pixbuf_get_height (thumb); - double screen_to_dest = fit_factor (scr_width, scr_height, - dest_width, dest_height); - double thumb_to_orig = fit_factor (thumb_width, thumb_height, - o_width, o_height); - double f = thumb_to_orig * screen_to_dest; - int new_width, new_height; - - new_width = floor (thumb_width * f + 0.5); - new_height = floor (thumb_height * f + 0.5); - - if (placement == G_DESKTOP_BACKGROUND_STYLE_WALLPAPER) { - /* Heuristic to make sure tiles don't become so small that - * they turn into a blur. - * - * This is strictly speaking incorrect, but the resulting - * thumbnail gives a much better idea what the background - * will actually look like. - */ - - if ((new_width < 32 || new_height < 32) && - (new_width < o_width / 4 || new_height < o_height / 4)) { - new_width = o_width / 4; - new_height = o_height / 4; - } - } - - thumb = gdk_pixbuf_scale_simple (thumb, new_width, new_height, - GDK_INTERP_BILINEAR); - } - else - g_object_ref (thumb); - - return thumb; -} - -/* frame_num determines which slide to thumbnail. - * -1 means 'current slide'. - */ -static GdkPixbuf * -create_img_thumbnail (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - GdkScreen *screen, - int dest_width, - int dest_height, - int frame_num) -{ - if (bg->filename) { - GdkPixbuf *thumb; - - thumb = get_as_thumbnail (bg, factory, bg->filename); - - if (thumb) { - GdkPixbuf *result; - result = scale_thumbnail (bg->placement, - bg->filename, - thumb, - screen, - dest_width, - dest_height); - g_object_unref (thumb); - return result; - } - else { - GnomeBGSlideShow *show = get_as_slideshow (bg, bg->filename); - - if (show) { - double alpha; - double duration; - gboolean is_fixed; - const char *file1; - const char *file2; - GdkPixbuf *tmp; - - if (frame_num == -1) - gnome_bg_slide_show_get_current_slide (show, - dest_width, - dest_height, - &alpha, - &duration, - &is_fixed, - &file1, - &file2); - else - gnome_bg_slide_show_get_slide (show, - frame_num, - dest_width, - dest_height, - &alpha, - &duration, - &is_fixed, - &file1, - &file2); - - if (is_fixed) { - tmp = get_as_thumbnail (bg, factory, file1); - if (tmp) { - thumb = scale_thumbnail (bg->placement, - file1, - tmp, - screen, - dest_width, - dest_height); - g_object_unref (tmp); - } - } - else { - GdkPixbuf *p1, *p2; - p1 = get_as_thumbnail (bg, factory, file1); - p2 = get_as_thumbnail (bg, factory, file2); - - if (p1 && p2) { - GdkPixbuf *thumb1, *thumb2; - - thumb1 = scale_thumbnail (bg->placement, - file1, - p1, - screen, - dest_width, - dest_height); - - thumb2 = scale_thumbnail (bg->placement, - file2, - p2, - screen, - dest_width, - dest_height); - - thumb = blend (thumb1, thumb2, alpha); - - g_object_unref (thumb1); - g_object_unref (thumb2); - } - if (p1) - g_object_unref (p1); - if (p2) - g_object_unref (p2); - } - - ensure_timeout (bg, (guint)get_slide_timeout (is_fixed, duration)); - - g_object_unref (show); - } - } - - return thumb; - } - - return NULL; -} - -static GdkPixbuf * -get_pixbuf_for_size (GnomeBG *bg, - gint num_monitor, - gint best_width, - gint best_height) -{ - guint time_until_next_change; - gboolean hit_cache = FALSE; - - /* only hit the cache if the aspect ratio matches */ - if (bg->pixbuf_cache) { - int width, height; - width = gdk_pixbuf_get_width (bg->pixbuf_cache); - height = gdk_pixbuf_get_height (bg->pixbuf_cache); - hit_cache = 0.2 > fabs ((best_width / (double)best_height) - (width / (double)height)); - if (!hit_cache) { - g_object_unref (bg->pixbuf_cache); - bg->pixbuf_cache = NULL; - } - } - - if (!hit_cache && bg->filename) { - bg->file_mtime = get_mtime (bg->filename); - - bg->pixbuf_cache = get_as_pixbuf_for_size (bg, bg->filename, num_monitor, best_width, best_height); - time_until_next_change = G_MAXUINT; - if (!bg->pixbuf_cache) { - GnomeBGSlideShow *show = get_as_slideshow (bg, bg->filename); - - if (show) { - double alpha; - double duration; - gboolean is_fixed; - const char *file1; - const char *file2; - - g_object_ref (show); - - gnome_bg_slide_show_get_current_slide (show, - best_width, - best_height, - &alpha, - &duration, - &is_fixed, - &file1, - &file2); - time_until_next_change = (guint)get_slide_timeout (is_fixed, duration); - if (is_fixed) { - bg->pixbuf_cache = get_as_pixbuf_for_size (bg, file1, num_monitor, best_width, best_height); - } - else { - GdkPixbuf *p1, *p2; - p1 = get_as_pixbuf_for_size (bg, file1, num_monitor, best_width, best_height); - p2 = get_as_pixbuf_for_size (bg, file2, num_monitor, best_width, best_height); - - if (p1 && p2) { - bg->pixbuf_cache = blend (p1, p2, alpha); - } - if (p1) - g_object_unref (p1); - if (p2) - g_object_unref (p2); - } - - ensure_timeout (bg, time_until_next_change); - - g_object_unref (show); - } - } - - /* If the next slideshow step is a long time away then - we blow away the expensive stuff (large pixbufs) from - the cache */ - if (time_until_next_change > KEEP_EXPENSIVE_CACHE_SECS) - blow_expensive_caches_in_idle (bg); - } - - if (bg->pixbuf_cache) - g_object_ref (bg->pixbuf_cache); - - return bg->pixbuf_cache; -} - -static gboolean -is_different (GnomeBG *bg, - const char *filename) -{ - if (!filename && bg->filename) { - return TRUE; - } - else if (filename && !bg->filename) { - return TRUE; - } - else if (!filename && !bg->filename) { - return FALSE; - } - else { - time_t mtime = get_mtime (filename); - - if (mtime != bg->file_mtime) - return TRUE; - - if (strcmp (filename, bg->filename) != 0) - return TRUE; - - return FALSE; - } -} - -static void -clear_cache (GnomeBG *bg) -{ - GList *list; - - if (bg->file_cache) { - for (list = bg->file_cache; list != NULL; list = list->next) { - FileCacheEntry *ent = list->data; - - file_cache_entry_delete (ent); - } - g_list_free (bg->file_cache); - bg->file_cache = NULL; - } - - if (bg->pixbuf_cache) { - g_object_unref (bg->pixbuf_cache); - - bg->pixbuf_cache = NULL; - } - - if (bg->timeout_id) { - g_source_remove (bg->timeout_id); - - bg->timeout_id = 0; - } -} - -/* Pixbuf utilities */ -static void -pixbuf_average_value (GdkPixbuf *pixbuf, - GdkRGBA *result) -{ - guint64 a_total, r_total, g_total, b_total; - guint row, column; - int row_stride; - const guchar *pixels, *p; - int r, g, b, a; - guint64 dividend; - guint width, height; - gdouble dd; - - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - row_stride = gdk_pixbuf_get_rowstride (pixbuf); - pixels = gdk_pixbuf_get_pixels (pixbuf); - - /* iterate through the pixbuf, counting up each component */ - a_total = 0; - r_total = 0; - g_total = 0; - b_total = 0; - - if (gdk_pixbuf_get_has_alpha (pixbuf)) { - for (row = 0; row < height; row++) { - p = pixels + (row * row_stride); - for (column = 0; column < width; column++) { - r = *p++; - g = *p++; - b = *p++; - a = *p++; - - a_total += a; - r_total += r * a; - g_total += g * a; - b_total += b * a; - } - } - dividend = height * width * 0xFF; - a_total *= 0xFF; - } else { - for (row = 0; row < height; row++) { - p = pixels + (row * row_stride); - for (column = 0; column < width; column++) { - r = *p++; - g = *p++; - b = *p++; - - r_total += r; - g_total += g; - b_total += b; - } - } - dividend = height * width; - a_total = dividend * 0xFF; - } - - dd = dividend * 0xFF; - result->alpha = a_total / dd; - result->red = r_total / dd; - result->green = g_total / dd; - result->blue = b_total / dd; -} - -static GdkPixbuf * -pixbuf_scale_to_fit (GdkPixbuf *src, int max_width, int max_height) -{ - double factor; - int src_width, src_height; - int new_width, new_height; - - src_width = gdk_pixbuf_get_width (src); - src_height = gdk_pixbuf_get_height (src); - - factor = MIN (max_width / (double) src_width, max_height / (double) src_height); - - new_width = floor (src_width * factor + 0.5); - new_height = floor (src_height * factor + 0.5); - - return gdk_pixbuf_scale_simple (src, new_width, new_height, GDK_INTERP_BILINEAR); -} - -static GdkPixbuf * -pixbuf_scale_to_min (GdkPixbuf *src, int min_width, int min_height) -{ - double factor; - int src_width, src_height; - int new_width, new_height; - GdkPixbuf *dest; - - src_width = gdk_pixbuf_get_width (src); - src_height = gdk_pixbuf_get_height (src); - - factor = MAX (min_width / (double) src_width, min_height / (double) src_height); - - new_width = floor (src_width * factor + 0.5); - new_height = floor (src_height * factor + 0.5); - - dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, - gdk_pixbuf_get_has_alpha (src), - 8, min_width, min_height); - if (!dest) - return NULL; - - /* crop the result */ - gdk_pixbuf_scale (src, dest, - 0, 0, - min_width, min_height, - (new_width - min_width) / -2, - (new_height - min_height) / -2, - factor, - factor, - GDK_INTERP_BILINEAR); - return dest; -} - -static guchar * -create_gradient (const GdkColor *primary, - const GdkColor *secondary, - int n_pixels) -{ - guchar *result = g_malloc (n_pixels * 3); - int i; - - for (i = 0; i < n_pixels; ++i) { - double ratio = (i + 0.5) / n_pixels; - - result[3 * i + 0] = ((guint16) (primary->red * (1 - ratio) + secondary->red * ratio)) >> 8; - result[3 * i + 1] = ((guint16) (primary->green * (1 - ratio) + secondary->green * ratio)) >> 8; - result[3 * i + 2] = ((guint16) (primary->blue * (1 - ratio) + secondary->blue * ratio)) >> 8; - } - - return result; -} - -static void -pixbuf_draw_gradient (GdkPixbuf *pixbuf, - gboolean horizontal, - GdkColor *primary, - GdkColor *secondary, - GdkRectangle *rect) -{ - int width; - int height; - int rowstride; - guchar *dst; - int n_channels = 3; - - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - width = rect->width; - height = rect->height; - dst = gdk_pixbuf_get_pixels (pixbuf) + rect->x * n_channels + rowstride * rect->y; - - if (horizontal) { - guchar *gradient = create_gradient (primary, secondary, width); - int copy_bytes_per_row = width * n_channels; - int i; - - for (i = 0; i < height; i++) { - guchar *d; - d = dst + rowstride * i; - memcpy (d, gradient, copy_bytes_per_row); - } - g_free (gradient); - } else { - guchar *gb, *gradient; - int i; - - gradient = create_gradient (primary, secondary, height); - for (i = 0; i < height; i++) { - int j; - guchar *d; - - d = dst + rowstride * i; - gb = gradient + n_channels * i; - for (j = width; j > 0; j--) { - int k; - - for (k = 0; k < n_channels; k++) { - *(d++) = gb[k]; - } - } - } - - g_free (gradient); - } -} - -static void -pixbuf_blend (GdkPixbuf *src, - GdkPixbuf *dest, - int src_x, - int src_y, - int src_width, - int src_height, - int dest_x, - int dest_y, - double alpha) -{ - int dest_width = gdk_pixbuf_get_width (dest); - int dest_height = gdk_pixbuf_get_height (dest); - int offset_x = dest_x - src_x; - int offset_y = dest_y - src_y; - - if (src_width < 0) - src_width = gdk_pixbuf_get_width (src); - - if (src_height < 0) - src_height = gdk_pixbuf_get_height (src); - - if (dest_x < 0) - dest_x = 0; - - if (dest_y < 0) - dest_y = 0; - - if (dest_x + src_width > dest_width) { - src_width = dest_width - dest_x; - } - - if (dest_y + src_height > dest_height) { - src_height = dest_height - dest_y; - } - - gdk_pixbuf_composite (src, dest, - dest_x, dest_y, - src_width, src_height, - offset_x, offset_y, - 1, 1, GDK_INTERP_NEAREST, - alpha * 0xFF + 0.5); -} - -static void -pixbuf_tile (GdkPixbuf *src, GdkPixbuf *dest) -{ - int x, y; - int tile_width, tile_height; - int dest_width = gdk_pixbuf_get_width (dest); - int dest_height = gdk_pixbuf_get_height (dest); - tile_width = gdk_pixbuf_get_width (src); - tile_height = gdk_pixbuf_get_height (src); - - for (y = 0; y < dest_height; y += tile_height) { - for (x = 0; x < dest_width; x += tile_width) { - pixbuf_blend (src, dest, 0, 0, - tile_width, tile_height, x, y, 1.0); - } - } -} - -static GnomeBGSlideShow * -read_slideshow_file (const char *filename, - GError **err) -{ - GnomeBGSlideShow *show; - - show = gnome_bg_slide_show_new (filename); - - if (!gnome_bg_slide_show_load (show, err)) { - g_object_unref (show); - return NULL; - } - - return show; -} - -/* Thumbnail utilities */ -static GdkPixbuf * -create_thumbnail_for_filename (GnomeDesktopThumbnailFactory *factory, - const char *filename) -{ - char *thumb; - time_t mtime; - GdkPixbuf *orig, *result = NULL; - char *uri; - - mtime = get_mtime (filename); - - if (mtime == (time_t)-1) - return NULL; - - uri = g_filename_to_uri (filename, NULL, NULL); - - if (uri == NULL) - return NULL; - - thumb = gnome_desktop_thumbnail_factory_lookup (factory, uri, mtime); - - if (thumb) { - result = gdk_pixbuf_new_from_file (thumb, NULL); - g_free (thumb); - } - else { - orig = gdk_pixbuf_new_from_file (filename, NULL); - if (orig) { - int orig_width = gdk_pixbuf_get_width (orig); - int orig_height = gdk_pixbuf_get_height (orig); - - result = pixbuf_scale_to_fit (orig, THUMBNAIL_SIZE, THUMBNAIL_SIZE); - - g_object_set_data_full (G_OBJECT (result), "gnome-thumbnail-height", - g_strdup_printf ("%d", orig_height), g_free); - g_object_set_data_full (G_OBJECT (result), "gnome-thumbnail-width", - g_strdup_printf ("%d", orig_width), g_free); - - g_object_unref (orig); - - gnome_desktop_thumbnail_factory_save_thumbnail (factory, result, uri, mtime); - } - else { - gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, mtime); - } - } - - g_free (uri); - - return result; -} - -static gboolean -get_thumb_annotations (GdkPixbuf *thumb, - int *orig_width, - int *orig_height) -{ - char *end; - const char *wstr, *hstr; - - wstr = gdk_pixbuf_get_option (thumb, "tEXt::Thumb::Image::Width"); - hstr = gdk_pixbuf_get_option (thumb, "tEXt::Thumb::Image::Height"); - - if (hstr && wstr) { - *orig_width = strtol (wstr, &end, 10); - if (*end != 0) - return FALSE; - - *orig_height = strtol (hstr, &end, 10); - if (*end != 0) - return FALSE; - - return TRUE; - } - - return FALSE; -} - -/* - * Returns whether the background is a slideshow. - */ -gboolean -gnome_bg_changes_with_time (GnomeBG *bg) -{ - GnomeBGSlideShow *show; - gboolean ret = FALSE; - - g_return_val_if_fail (bg != NULL, FALSE); - - if (!bg->filename) - return FALSE; - - show = get_as_slideshow (bg, bg->filename); - if (show) { - ret = gnome_bg_slide_show_get_num_slides (show) > 1; - g_object_unref (show); - } - - return ret; -} - -/** - * gnome_bg_create_frame_thumbnail: - * - * Creates a thumbnail for a certain frame, where 'frame' is somewhat - * vaguely defined as 'suitable point to show while single-stepping - * through the slideshow'. - * - * Returns: (transfer full): the newly created thumbnail or - * or NULL if frame_num is out of bounds. - */ -GdkPixbuf * -gnome_bg_create_frame_thumbnail (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - GdkScreen *screen, - int dest_width, - int dest_height, - int frame_num) -{ - GnomeBGSlideShow *show; - GdkPixbuf *result; - GdkPixbuf *thumb; - int skipped; - gboolean is_fixed; - - g_return_val_if_fail (bg != NULL, FALSE); - - show = get_as_slideshow (bg, bg->filename); - - if (!show) - return NULL; - - - if (frame_num < 0 || frame_num >= gnome_bg_slide_show_get_num_slides (show)) - return NULL; - - - gnome_bg_slide_show_get_slide (show, frame_num, dest_width, dest_height, NULL, NULL, &is_fixed, NULL, NULL); - - skipped = 0; - while (!is_fixed) { - skipped++; - gnome_bg_slide_show_get_slide (show, frame_num, dest_width, dest_height, NULL, NULL, &is_fixed, NULL, NULL); - } - - result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, dest_width, dest_height); - - draw_color (bg, result); - - if (bg->placement != G_DESKTOP_BACKGROUND_STYLE_NONE) { - thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, frame_num + skipped); - - if (thumb) { - draw_image_for_thumb (bg, thumb, result); - g_object_unref (thumb); - } - } - - return result; -} - diff --git a/libgnome-desktop/gnome-bg.h b/libgnome-desktop/gnome-bg.h deleted file mode 100644 index 69d1befd..00000000 --- a/libgnome-desktop/gnome-bg.h +++ /dev/null @@ -1,121 +0,0 @@ -/* gnome-bg.h - - - Copyright 2007, Red Hat, Inc. - - This file is part of the Gnome Library. - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - Author: Soren Sandmann <sandmann@redhat.com> -*/ - -#ifndef __GNOME_BG_H__ -#define __GNOME_BG_H__ - -#ifndef GNOME_DESKTOP_USE_UNSTABLE_API -#error GnomeBG is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-bg.h -#endif - -#include <gdk/gdk.h> -#include <gio/gio.h> -#include <gdesktop-enums.h> -#include <libgnome-desktop/gnome-desktop-thumbnail.h> -#include <libgnome-desktop/gnome-bg-crossfade.h> -#include <gdesktop-enums.h> - -G_BEGIN_DECLS - -#define GNOME_TYPE_BG (gnome_bg_get_type ()) -#define GNOME_BG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_BG, GnomeBG)) -#define GNOME_BG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_BG, GnomeBGClass)) -#define GNOME_IS_BG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_BG)) -#define GNOME_IS_BG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_BG)) -#define GNOME_BG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_BG, GnomeBGClass)) - -typedef struct _GnomeBG GnomeBG; -typedef struct _GnomeBGClass GnomeBGClass; - -GType gnome_bg_get_type (void); -GnomeBG * gnome_bg_new (void); -void gnome_bg_load_from_preferences (GnomeBG *bg, - GSettings *settings); -void gnome_bg_save_to_preferences (GnomeBG *bg, - GSettings *settings); -/* Setters */ -void gnome_bg_set_filename (GnomeBG *bg, - const char *filename); -void gnome_bg_set_placement (GnomeBG *bg, - GDesktopBackgroundStyle placement); -void gnome_bg_set_color (GnomeBG *bg, - GDesktopBackgroundShading type, - GdkColor *primary, - GdkColor *secondary); - -/* Getters */ -GDesktopBackgroundStyle gnome_bg_get_placement (GnomeBG *bg); -void gnome_bg_get_color (GnomeBG *bg, - GDesktopBackgroundShading *type, - GdkColor *primary, - GdkColor *secondary); -const gchar * gnome_bg_get_filename (GnomeBG *bg); - -/* Drawing and thumbnailing */ -void gnome_bg_draw (GnomeBG *bg, - GdkPixbuf *dest, - GdkScreen *screen, - gboolean is_root); -cairo_surface_t *gnome_bg_create_surface (GnomeBG *bg, - GdkWindow *window, - int width, - int height, - gboolean root); -gboolean gnome_bg_get_image_size (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - int best_width, - int best_height, - int *width, - int *height); -GdkPixbuf * gnome_bg_create_thumbnail (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - GdkScreen *screen, - int dest_width, - int dest_height); -gboolean gnome_bg_is_dark (GnomeBG *bg, - int dest_width, - int dest_height); -gboolean gnome_bg_has_multiple_sizes (GnomeBG *bg); -gboolean gnome_bg_changes_with_time (GnomeBG *bg); -GdkPixbuf * gnome_bg_create_frame_thumbnail (GnomeBG *bg, - GnomeDesktopThumbnailFactory *factory, - GdkScreen *screen, - int dest_width, - int dest_height, - int frame_num); - -/* Set a surface as root - not a GnomeBG method. At some point - * if we decide to stabilize the API then we may want to make - * these object methods, drop gnome_bg_create_surface, etc. - */ -void gnome_bg_set_surface_as_root (GdkScreen *screen, - cairo_surface_t *surface); - -GnomeBGCrossfade *gnome_bg_set_surface_as_root_with_crossfade (GdkScreen *screen, - cairo_surface_t *surface); -cairo_surface_t *gnome_bg_get_surface_from_root (GdkScreen *screen); - -G_END_DECLS - -#endif |