summaryrefslogtreecommitdiff
path: root/libmate-desktop/mate-bg.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmate-desktop/mate-bg.c')
-rw-r--r--libmate-desktop/mate-bg.c383
1 files changed, 289 insertions, 94 deletions
diff --git a/libmate-desktop/mate-bg.c b/libmate-desktop/mate-bg.c
index 2c29528..7877b9c 100644
--- a/libmate-desktop/mate-bg.c
+++ b/libmate-desktop/mate-bg.c
@@ -34,6 +34,7 @@ Authors: Soren Sandmann <[email protected]>
#include <stdarg.h>
#include <stdlib.h>
+#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gdk/gdkx.h>
@@ -59,6 +60,8 @@ Authors: Soren Sandmann <[email protected]>
#define mate_bg_crossfade_set_end_surface mate_bg_crossfade_set_end_pixmap
#endif
+#define MATE_BG_CACHE_DIR "mate/background"
+
/* 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
@@ -175,8 +178,9 @@ static gboolean get_thumb_annotations (GdkPixbuf *thumb,
/* Cache */
static GdkPixbuf *get_pixbuf_for_size (MateBG *bg,
- int width,
- int height);
+ gint num_monitor,
+ int width,
+ int height);
static void clear_cache (MateBG *bg);
static gboolean is_different (MateBG *bg,
const char *filename);
@@ -621,12 +625,147 @@ mate_bg_get_filename (MateBG *bg)
return bg->filename;
}
+static inline gchar *
+get_wallpaper_cache_dir ()
+{
+ return g_build_filename (g_get_user_cache_dir(), MATE_BG_CACHE_DIR, NULL);
+}
+
+static inline gchar *
+get_wallpaper_cache_prefix_name (gint num_monitor,
+ MateBGPlacement 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,
+ MateBGPlacement 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 = 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 (MateBG *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,
+file_changed (GFileMonitor *file_monitor,
+ GFile *child,
+ GFile *other_file,
GFileMonitorEvent event_type,
- gpointer user_data)
+ gpointer user_data)
{
MateBG *bg = MATE_BG (user_data);
@@ -668,8 +807,8 @@ mate_bg_set_filename (MateBG *bg,
}
static void
-draw_color_area (MateBG *bg,
- GdkPixbuf *dest,
+draw_color_area (MateBG *bg,
+ GdkPixbuf *dest,
GdkRectangle *rect)
{
guint32 pixel;
@@ -707,7 +846,7 @@ draw_color_area (MateBG *bg,
}
static void
-draw_color (MateBG *bg,
+draw_color (MateBG *bg,
GdkPixbuf *dest,
GdkScreen *screen)
{
@@ -721,7 +860,7 @@ draw_color (MateBG *bg,
}
static void
-draw_color_each_monitor (MateBG *bg,
+draw_color_each_monitor (MateBG *bg,
GdkPixbuf *dest,
GdkScreen *screen)
{
@@ -770,8 +909,8 @@ pixbuf_clip_to_fit (GdkPixbuf *src,
}
static GdkPixbuf *
-get_scaled_pixbuf (MateBGPlacement placement,
- GdkPixbuf *pixbuf,
+get_scaled_pixbuf (MateBGPlacement placement,
+ GdkPixbuf *pixbuf,
int width, int height,
int *x, int *y,
int *w, int *h)
@@ -818,10 +957,11 @@ get_scaled_pixbuf (MateBGPlacement placement,
static void
-draw_image_area (MateBGPlacement placement,
- GdkPixbuf *pixbuf,
- GdkPixbuf *dest,
- GdkRectangle *area)
+draw_image_area (MateBG *bg,
+ gint num_monitor,
+ GdkPixbuf *pixbuf,
+ GdkPixbuf *dest,
+ GdkRectangle *area)
{
int dest_width = area->width;
int dest_height = area->height;
@@ -831,9 +971,9 @@ draw_image_area (MateBGPlacement placement,
if (!pixbuf)
return;
- scaled = get_scaled_pixbuf (placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
+ scaled = get_scaled_pixbuf (bg->placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
- switch (placement) {
+ switch (bg->placement) {
case MATE_BG_PLACEMENT_TILED:
pixbuf_tile (scaled, dest);
break;
@@ -851,13 +991,15 @@ draw_image_area (MateBGPlacement placement,
break;
}
+ refresh_cache_file (bg, scaled, num_monitor, dest_width, dest_height);
+
g_object_unref (scaled);
}
static void
-draw_image (MateBGPlacement placement,
- GdkPixbuf *pixbuf,
- GdkPixbuf *dest)
+draw_image_for_thumb (MateBG *bg,
+ GdkPixbuf *pixbuf,
+ GdkPixbuf *dest)
{
GdkRectangle rect;
@@ -866,60 +1008,63 @@ draw_image (MateBGPlacement placement,
rect.width = gdk_pixbuf_get_width (dest);
rect.height = gdk_pixbuf_get_height (dest);
- draw_image_area (placement, pixbuf, dest, &rect);
+ draw_image_area (bg, -1, pixbuf, dest, &rect);
}
static void
-draw_once (MateBG *bg,
+draw_once (MateBG *bg,
GdkPixbuf *dest,
- GdkScreen *screen)
+ GdkScreen *screen,
+ gboolean is_root)
{
GdkRectangle rect;
GdkPixbuf *pixbuf;
+ gint monitor;
+
+ /* whether we're drawing on root window or normal (Caja) window */
+ monitor = (is_root) ? 0 : -1;
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, gdk_pixbuf_get_width (dest), gdk_pixbuf_get_height (dest));
+ pixbuf = get_pixbuf_for_size (bg, monitor, rect.width, rect.height);
if (pixbuf) {
- draw_image_area (bg->placement,
- pixbuf,
- dest,
- &rect);
+ draw_image_area (bg, monitor, pixbuf, dest, &rect);
+
g_object_unref (pixbuf);
}
}
static void
-draw_each_monitor (MateBG *bg,
+draw_each_monitor (MateBG *bg,
GdkPixbuf *dest,
GdkScreen *screen)
{
- GdkRectangle rect;
- gint num_monitors;
- int monitor;
+ gint num_monitors = gdk_screen_get_n_monitors (screen);
+ gint monitor = 0;
- num_monitors = gdk_screen_get_n_monitors (screen);
- for (monitor = 0; monitor < num_monitors; monitor++) {
+ for (; monitor < num_monitors; monitor++) {
+ GdkRectangle rect;
GdkPixbuf *pixbuf;
+
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
- pixbuf = get_pixbuf_for_size (bg, rect.width, rect.height);
+
+ pixbuf = get_pixbuf_for_size (bg, monitor, rect.width, rect.height);
if (pixbuf) {
- draw_image_area (bg->placement,
- pixbuf,
- dest, &rect);
+ draw_image_area (bg, monitor, pixbuf, dest, &rect);
+
g_object_unref (pixbuf);
}
}
}
void
-mate_bg_draw (MateBG *bg,
+mate_bg_draw (MateBG *bg,
GdkPixbuf *dest,
GdkScreen *screen,
- gboolean is_root)
+ gboolean is_root)
{
if (!bg)
return;
@@ -932,7 +1077,7 @@ mate_bg_draw (MateBG *bg,
} else {
draw_color (bg, dest, screen);
if (bg->filename) {
- draw_once (bg, dest, screen);
+ draw_once (bg, dest, screen, is_root);
}
}
}
@@ -1023,14 +1168,13 @@ mate_bg_create_pixmap (MateBG *bg,
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)
+ (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 */
mate_bg_get_pixmap_size (bg, width, height, &pm_width, &pm_height);
@@ -1092,7 +1236,7 @@ mate_bg_is_dark (MateBG *bg,
color.green = (bg->primary.green + bg->secondary.green) / 2;
color.blue = (bg->primary.blue + bg->secondary.blue) / 2;
}
- pixbuf = get_pixbuf_for_size (bg, width, height);
+ pixbuf = get_pixbuf_for_size (bg, -1, width, height);
if (pixbuf) {
guint32 argb = pixbuf_average_value (pixbuf);
guchar a = (argb >> 24) & 0xff;
@@ -1259,7 +1403,7 @@ mate_bg_create_thumbnail (MateBG *bg,
thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, -1);
if (thumb) {
- draw_image (bg->placement, thumb, result);
+ draw_image_for_thumb (bg, thumb, result);
g_object_unref (thumb);
}
}
@@ -1770,38 +1914,68 @@ file_cache_add_slide_show (MateBG *bg,
}
static GdkPixbuf *
+load_from_cache_file (MateBG *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 (MateBG *bg,
const char *filename,
- int best_width,
- int best_height)
+ gint 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 {
+ } else {
GdkPixbufFormat *format;
- GdkPixbuf *pixbuf;
+ GdkPixbuf *pixbuf = NULL;
gchar *tmp = NULL;
- /* 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;
+ /* Try to hit local cache first if relevant */
+ if (monitor != -1)
+ pixbuf = load_from_cache_file (bg, filename, 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);
+
+ if (g_strcmp0 (tmp, "svg") == 0 &&
+ (best_width > 0 && best_height > 0) &&
+ (bg->placement == MATE_BG_PLACEMENT_FILL_SCREEN ||
+ bg->placement == MATE_BG_PLACEMENT_SCALED ||
+ bg->placement == MATE_BG_PLACEMENT_ZOOMED))
+ {
+ pixbuf = gdk_pixbuf_new_from_file_at_size (filename,
+ best_width,
+ best_height, NULL);
+ } else {
+ pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+ }
+
+ if (tmp != NULL)
+ g_free (tmp);
}
- if (tmp != NULL &&
- g_strcmp0 (tmp, "svg") == 0 &&
- (best_width > 0 && best_height > 0) &&
- (bg->placement == MATE_BG_PLACEMENT_FILL_SCREEN ||
- bg->placement == MATE_BG_PLACEMENT_SCALED ||
- bg->placement == MATE_BG_PLACEMENT_ZOOMED))
- pixbuf = gdk_pixbuf_new_from_file_at_size (filename, best_width, best_height, NULL);
- else
- pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
- if (tmp != NULL)
- g_free (tmp);
if (pixbuf)
file_cache_add_pixbuf (bg, filename, pixbuf);
@@ -1848,18 +2022,19 @@ static gboolean
blow_expensive_caches (gpointer data)
{
MateBG *bg = data;
- GList *list, *next;
+ GList *list;
bg->blow_caches_id = 0;
- for (list = bg->file_cache; list != NULL; list = next) {
- FileCacheEntry *ent = list->data;
- next = list->next;
+ if (bg->file_cache) {
+ for (list = bg->file_cache; list != NULL; list = list->next) {
+ FileCacheEntry *ent = list->data;
- if (ent->type == PIXBUF) {
- file_cache_entry_delete (ent);
- bg->file_cache = g_list_delete_link (bg->file_cache,
- list);
+ if (ent->type == PIXBUF) {
+ file_cache_entry_delete (ent);
+ bg->file_cache = g_list_delete_link (bg->file_cache,
+ list);
+ }
}
}
@@ -1924,9 +2099,13 @@ ensure_timeout (MateBG *bg,
{
if (!bg->timeout_id) {
double timeout = get_slide_timeout (slide);
- bg->timeout_id = g_timeout_add_full (
- G_PRIORITY_LOW,
- timeout * 1000, on_timeout, bg, NULL);
+
+ /* 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);
+ }
}
}
@@ -2167,6 +2346,7 @@ find_best_size (GSList *sizes, gint width, gint height)
static GdkPixbuf *
get_pixbuf_for_size (MateBG *bg,
+ gint monitor,
gint best_width,
gint best_height)
{
@@ -2188,7 +2368,8 @@ get_pixbuf_for_size (MateBG *bg,
if (!hit_cache && bg->filename) {
bg->file_mtime = get_mtime (bg->filename);
- bg->pixbuf_cache = get_as_pixbuf_for_size (bg, bg->filename, best_width, best_height);
+ bg->pixbuf_cache = get_as_pixbuf_for_size (bg, bg->filename, monitor,
+ best_width, best_height);
time_until_next_change = G_MAXUINT;
if (!bg->pixbuf_cache) {
SlideShow *show = get_as_slideshow (bg, bg->filename);
@@ -2202,21 +2383,27 @@ get_pixbuf_for_size (MateBG *bg,
slide = get_current_slide (show, &alpha);
time_until_next_change = (guint)get_slide_timeout (slide);
if (slide->fixed) {
- FileSize *size;
- size = find_best_size (slide->file1, best_width, best_height);
- bg->pixbuf_cache = get_as_pixbuf_for_size (bg, size->file, best_width, best_height);
- }
- else {
+ FileSize *size = find_best_size (slide->file1,
+ best_width, best_height);
+ bg->pixbuf_cache =
+ get_as_pixbuf_for_size (bg, size->file, monitor,
+ best_width, best_height);
+ } else {
FileSize *size;
GdkPixbuf *p1, *p2;
- size = find_best_size (slide->file1, best_width, best_height);
- p1 = get_as_pixbuf_for_size (bg, size->file, best_width, best_height);
- size = find_best_size (slide->file2, best_width, best_height);
- p2 = get_as_pixbuf_for_size (bg, size->file, best_width, best_height);
- if (p1 && p2) {
+ size = find_best_size (slide->file1,
+ best_width, best_height);
+ p1 = get_as_pixbuf_for_size (bg, size->file, monitor,
+ best_width, best_height);
+
+ size = find_best_size (slide->file2,
+ best_width, best_height);
+ p2 = get_as_pixbuf_for_size (bg, size->file, monitor,
+ best_width, best_height);
+
+ if (p1 && p2)
bg->pixbuf_cache = blend (p1, p2, alpha);
- }
if (p1)
g_object_unref (p1);
if (p2)
@@ -2873,16 +3060,24 @@ read_slideshow_file (const char *filename,
g_markup_parse_context_free (context);
if (show) {
+ int len;
+
t = mktime (&show->start_tm);
show->start_time = (double)t;
dump_bg (show);
+ len = g_queue_get_length (show->slides);
+
/* no slides, that's not a slideshow */
- if (g_queue_get_length (show->slides) == 0) {
+ if (len == 0) {
slideshow_unref (show);
show = NULL;
+ /* one slide, there's no transition */
+ } else if (len == 1) {
+ Slide *slide = show->slides->head->data;
+ slide->duration = G_MAXUINT;
}
}
@@ -3052,7 +3247,7 @@ mate_bg_create_frame_thumbnail (MateBG *bg,
frame_num + skipped);
if (thumb) {
- draw_image (bg->placement, thumb, result);
+ draw_image_for_thumb (bg, thumb, result);
g_object_unref (thumb);
}
}