[gnome-desktop] gnome-bg: split slide show stuff off into separate api



commit 33d793c5e3996046f165499f941b5256d8a51850
Author: Ray Strode <rstrode redhat com>
Date:   Mon Feb 18 14:36:27 2013 -0500

    gnome-bg: split slide show stuff off into separate api
    
    We need to be able to parse slide shows directly from within gnome-shell.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=694121

 libgnome-desktop/Makefile.am           |    2 +
 libgnome-desktop/gnome-bg-slide-show.c |  766 ++++++++++++++++++++++++++++++++
 libgnome-desktop/gnome-bg-slide-show.h |   89 ++++
 libgnome-desktop/gnome-bg.c            |  662 +++++-----------------------
 4 files changed, 959 insertions(+), 560 deletions(-)
---
diff --git a/libgnome-desktop/Makefile.am b/libgnome-desktop/Makefile.am
index 3f04191..00ba47b 100644
--- a/libgnome-desktop/Makefile.am
+++ b/libgnome-desktop/Makefile.am
@@ -27,6 +27,7 @@ introspection_sources =               \
        gnome-desktop-thumbnail.c       \
        gnome-thumbnail-pixbuf-utils.c  \
        gnome-bg.c                      \
+       gnome-bg-slide-show.c           \
        gnome-bg-crossfade.c            \
        display-name.c                  \
        gnome-rr.c                      \
@@ -66,6 +67,7 @@ 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                      \
         gnome-rr-config.h               \
diff --git a/libgnome-desktop/gnome-bg-slide-show.c b/libgnome-desktop/gnome-bg-slide-show.c
new file mode 100644
index 0000000..cbdbf7b
--- /dev/null
+++ b/libgnome-desktop/gnome-bg-slide-show.c
@@ -0,0 +1,766 @@
+/* gnome-bg-slide-show.h
+ *
+ * Copyright (C) 2008, 2013 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.
+ *
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <gio/gio.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include "gnome-bg-slide-show.h"
+
+struct _GnomeBGSlideShowPrivate
+{
+        char *filename;
+
+        double start_time;
+        double total_duration;
+
+        GQueue *slides;
+
+        gboolean has_multiple_sizes;
+
+        /* used during parsing */
+        struct tm start_tm;
+        GQueue *stack;
+};
+
+typedef struct _Slide Slide;
+
+struct _Slide
+{
+       double   duration;              /* in seconds */
+       gboolean fixed;
+
+       GSList  *file1;
+       GSList  *file2;         /* NULL if fixed is TRUE */
+};
+
+typedef struct _FileSize FileSize;
+struct _FileSize
+{
+       gint width;
+       gint height;
+
+       char *file;
+};
+
+enum {
+        PROP_0,
+        PROP_FILENAME,
+        PROP_START_TIME,
+        PROP_TOTAL_DURATION,
+        PROP_HAS_MULTIPLE_SIZES,
+};
+
+G_DEFINE_TYPE (GnomeBGSlideShow, gnome_bg_slide_show, G_TYPE_OBJECT)
+#define GNOME_BG_SLIDE_SHOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),\
+                                            GNOME_BG_TYPE_SLIDE_SHOW,\
+                                            GnomeBGSlideShowPrivate))
+
+static void
+gnome_bg_slide_show_set_property (GObject       *object,
+                                  guint          property_id,
+                                  const GValue  *value,
+                                  GParamSpec    *pspec)
+{
+        GnomeBGSlideShow *self;
+
+        g_assert (GNOME_BG_IS_SLIDE_SHOW (object));
+
+        self = GNOME_BG_SLIDE_SHOW (object);
+
+        switch (property_id)
+        {
+        case PROP_FILENAME:
+                self->priv->filename = g_value_dup_string (value);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gnome_bg_slide_show_get_property (GObject     *object,
+                                  guint        property_id,
+                                  GValue      *value,
+                                  GParamSpec  *pspec)
+{
+        GnomeBGSlideShow *self;
+
+        g_assert (GNOME_BG_IS_SLIDE_SHOW (object));
+
+        self = GNOME_BG_SLIDE_SHOW (object);
+
+        switch (property_id)
+        {
+        case PROP_START_TIME:
+                g_value_set_int (value, self->priv->start_time);
+                break;
+        case PROP_TOTAL_DURATION:
+                g_value_set_int (value, self->priv->total_duration);
+                break;
+        case PROP_HAS_MULTIPLE_SIZES:
+                g_value_set_boolean (value, self->priv->has_multiple_sizes);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gnome_bg_slide_show_finalize (GObject *object)
+{
+        GnomeBGSlideShow *self;
+
+        GList *list;
+        GSList *slist;
+        FileSize *size;
+
+        self = GNOME_BG_SLIDE_SHOW (object);
+
+        for (list = self->priv->slides->head; list != NULL; list = list->next) {
+                Slide *slide = list->data;
+
+                for (slist = slide->file1; slist != NULL; slist = slist->next) {
+                        size = slist->data;
+                        g_free (size->file);
+                        g_free (size);
+                }
+                g_slist_free (slide->file1);
+
+                for (slist = slide->file2; slist != NULL; slist = slist->next) {
+                        size = slist->data;
+                        g_free (size->file);
+                        g_free (size);
+                }
+                g_slist_free (slide->file2);
+
+                g_free (slide);
+        }
+
+        g_queue_free (self->priv->slides);
+
+        g_list_foreach (self->priv->stack->head, (GFunc) g_free, NULL);
+        g_queue_free (self->priv->stack);
+}
+
+static void
+gnome_bg_slide_show_class_init (GnomeBGSlideShowClass *self_class)
+{
+        GObjectClass *gobject_class;
+
+        gobject_class = G_OBJECT_CLASS (self_class);
+
+        gobject_class->get_property = gnome_bg_slide_show_get_property;
+        gobject_class->set_property = gnome_bg_slide_show_set_property;
+        gobject_class->finalize = gnome_bg_slide_show_finalize;
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_FILENAME,
+                                         g_param_spec_string ("filename",
+                                                              "Filename",
+                                                              "Filename",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_START_TIME,
+                                         g_param_spec_double ("start-time",
+                                                              "Start time",
+                                                              "start time",
+                                                              0.0, G_MAXDOUBLE, 0.0,
+                                                              G_PARAM_READABLE));
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_TOTAL_DURATION,
+                                         g_param_spec_double ("total-duration",
+                                                              "Start duration",
+                                                              "total duration",
+                                                              0.0, G_MAXDOUBLE, 0.0,
+                                                              G_PARAM_READABLE));
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_HAS_MULTIPLE_SIZES,
+                                         g_param_spec_boolean ("has-multiple-sizes",
+                                                               "Has multiple sizes",
+                                                               "Has multiple sizes",
+                                                               FALSE,
+                                                               G_PARAM_READABLE));
+
+        g_type_class_add_private (gobject_class, sizeof (GnomeBGSlideShowPrivate));
+}
+
+static void
+gnome_bg_slide_show_init (GnomeBGSlideShow *self)
+{
+        self->priv = GNOME_BG_SLIDE_SHOW_GET_PRIVATE (self);
+
+        self->priv->stack = g_queue_new ();
+        self->priv->slides = g_queue_new ();
+}
+
+/**
+ * gnome_bg_slide_show_new:
+ * @filename: The name of the slide show file
+ *
+ * Creates a new object to manage a slide show.
+ * window background between two #cairo_surface_ts.
+ *
+ * Return value: the new #GnomeBGSlideShow
+ **/
+GnomeBGSlideShow *
+gnome_bg_slide_show_new (const char *filename)
+{
+        return GNOME_BG_SLIDE_SHOW (g_object_new (GNOME_BG_TYPE_SLIDE_SHOW,
+                                                  "filename", filename,
+                                                  NULL));
+}
+
+static void
+threadsafe_localtime (time_t time, struct tm *tm)
+{
+       struct tm *res;
+
+       G_LOCK_DEFINE_STATIC (localtime_mutex);
+
+       G_LOCK (localtime_mutex);
+
+       res = localtime (&time);
+       if (tm) {
+               *tm = *res;
+       }
+
+       G_UNLOCK (localtime_mutex);
+}
+static gboolean stack_is (GnomeBGSlideShow *self, const char *s1, ...);
+
+/* Parser for fading background */
+static void
+handle_start_element (GMarkupParseContext *context,
+                      const gchar         *name,
+                      const gchar        **attr_names,
+                      const gchar        **attr_values,
+                      gpointer             user_data,
+                      GError             **err)
+{
+        GnomeBGSlideShow *self = user_data;
+        gint i;
+
+        if (strcmp (name, "static") == 0 || strcmp (name, "transition") == 0) {
+                Slide *slide = g_new0 (Slide, 1);
+
+                if (strcmp (name, "static") == 0)
+                        slide->fixed = TRUE;
+
+                g_queue_push_tail (self->priv->slides, slide);
+        }
+        else if (strcmp (name, "size") == 0) {
+                Slide *slide = self->priv->slides->tail->data;
+                FileSize *size = g_new0 (FileSize, 1);
+                for (i = 0; attr_names[i]; i++) {
+                        if (strcmp (attr_names[i], "width") == 0)
+                                size->width = atoi (attr_values[i]);
+                        else if (strcmp (attr_names[i], "height") == 0)
+                                size->height = atoi (attr_values[i]);
+                }
+                if (self->priv->stack->tail &&
+                    (strcmp (self->priv->stack->tail->data, "file") == 0 ||
+                     strcmp (self->priv->stack->tail->data, "from") == 0)) {
+                        slide->file1 = g_slist_prepend (slide->file1, size);
+                }
+                else if (self->priv->stack->tail &&
+                         strcmp (self->priv->stack->tail->data, "to") == 0) {
+                        slide->file2 = g_slist_prepend (slide->file2, size);
+                }
+        }
+        g_queue_push_tail (self->priv->stack, g_strdup (name));
+}
+
+static void
+handle_end_element (GMarkupParseContext *context,
+                    const gchar         *name,
+                    gpointer             user_data,
+                    GError             **err)
+{
+        GnomeBGSlideShow *self = user_data;
+
+        g_free (g_queue_pop_tail (self->priv->stack));
+}
+
+static gboolean
+stack_is (GnomeBGSlideShow *self,
+          const char *s1,
+          ...)
+{
+        GList *stack = NULL;
+        const char *s;
+        GList *l1, *l2;
+        va_list args;
+
+        stack = g_list_prepend (stack, (gpointer)s1);
+
+        va_start (args, s1);
+
+        s = va_arg (args, const char *);
+        while (s) {
+                stack = g_list_prepend (stack, (gpointer)s);
+                s = va_arg (args, const char *);
+        }
+
+        l1 = stack;
+        l2 = self->priv->stack->head;
+
+        while (l1 && l2) {
+                if (strcmp (l1->data, l2->data) != 0) {
+                        g_list_free (stack);
+                        return FALSE;
+                }
+
+                l1 = l1->next;
+                l2 = l2->next;
+        }
+
+        g_list_free (stack);
+
+        return (!l1 && !l2);
+}
+
+static int
+parse_int (const char *text)
+{
+        return strtol (text, NULL, 0);
+}
+
+static void
+handle_text (GMarkupParseContext *context,
+             const gchar         *text,
+             gsize                text_len,
+             gpointer             user_data,
+             GError             **err)
+{
+        GnomeBGSlideShow *self = user_data;
+        Slide *slide = self->priv->slides->tail? self->priv->slides->tail->data : NULL;
+        FileSize *fs;
+        gint i;
+
+        if (stack_is (self, "year", "starttime", "background", NULL)) {
+                self->priv->start_tm.tm_year = parse_int (text) - 1900;
+        }
+        else if (stack_is (self, "month", "starttime", "background", NULL)) {
+                self->priv->start_tm.tm_mon = parse_int (text) - 1;
+        }
+        else if (stack_is (self, "day", "starttime", "background", NULL)) {
+                self->priv->start_tm.tm_mday = parse_int (text);
+        }
+        else if (stack_is (self, "hour", "starttime", "background", NULL)) {
+                self->priv->start_tm.tm_hour = parse_int (text) - 1;
+        }
+        else if (stack_is (self, "minute", "starttime", "background", NULL)) {
+                self->priv->start_tm.tm_min = parse_int (text);
+        }
+        else if (stack_is (self, "second", "starttime", "background", NULL)) {
+                self->priv->start_tm.tm_sec = parse_int (text);
+        }
+        else if (stack_is (self, "duration", "static", "background", NULL) ||
+                 stack_is (self, "duration", "transition", "background", NULL)) {
+                slide->duration = g_strtod (text, NULL);
+                self->priv->total_duration += slide->duration;
+        }
+        else if (stack_is (self, "file", "static", "background", NULL) ||
+                 stack_is (self, "from", "transition", "background", NULL)) {
+                for (i = 0; text[i]; i++) {
+                        if (!g_ascii_isspace (text[i]))
+                                break;
+                }
+                if (text[i] == 0)
+                        return;
+                fs = g_new (FileSize, 1);
+                fs->width = -1;
+                fs->height = -1;
+                fs->file = g_strdup (text);
+                slide->file1 = g_slist_prepend (slide->file1, fs);
+                if (slide->file1->next != NULL)
+                        self->priv->has_multiple_sizes = TRUE;
+        }
+        else if (stack_is (self, "size", "file", "static", "background", NULL) ||
+                 stack_is (self, "size", "from", "transition", "background", NULL)) {
+                fs = slide->file1->data;
+                fs->file = g_strdup (text);
+                if (slide->file1->next != NULL)
+                        self->priv->has_multiple_sizes = TRUE;
+        }
+        else if (stack_is (self, "to", "transition", "background", NULL)) {
+                for (i = 0; text[i]; i++) {
+                        if (!g_ascii_isspace (text[i]))
+                                break;
+                }
+                if (text[i] == 0)
+                        return;
+                fs = g_new (FileSize, 1);
+                fs->width = -1;
+                fs->height = -1;
+                fs->file = g_strdup (text);
+                slide->file2 = g_slist_prepend (slide->file2, fs);
+                if (slide->file2->next != NULL)
+                        self->priv->has_multiple_sizes = TRUE;
+        }
+        else if (stack_is (self, "size", "to", "transition", "background", NULL)) {
+                fs = slide->file2->data;
+                fs->file = g_strdup (text);
+                if (slide->file2->next != NULL)
+                        self->priv->has_multiple_sizes = TRUE;
+        }
+}
+
+/*
+ * Find the FileSize that best matches the given size.
+ * Do two passes; the first pass only considers FileSizes
+ * that are larger than the given size.
+ * We are looking for the image that best matches the aspect ratio.
+ * When two images have the same aspect ratio, prefer the one whose
+ * width is closer to the given width.
+ */
+static const char *
+find_best_size (GSList *sizes, gint width, gint height)
+{
+       GSList *s;
+       gdouble a, d, distance;
+       FileSize *best = NULL;
+       gint pass;
+
+       a = width/(gdouble)height;
+       distance = 10000.0;
+
+       for (pass = 0; pass < 2; pass++) {
+               for (s = sizes; s; s = s->next) {
+                       FileSize *size = s->data;
+
+                       if (pass == 0 && (size->width < width || size->height < height))
+                               continue;
+
+                       d = fabs (a - size->width/(gdouble)size->height);
+                       if (d < distance) {
+                               distance = d;
+                               best = size;
+                        }
+                       else if (d == distance) {
+                               if (abs (size->width - width) < abs (best->width - width)) {
+                                       best = size;
+                               }
+                       }
+               }
+
+               if (best)
+                       break;
+       }
+
+       return best->file;
+}
+
+static double
+now (void)
+{
+       GTimeVal tv;
+
+       g_get_current_time (&tv);
+
+       return (double)tv.tv_sec + (tv.tv_usec / 1000000.0);
+}
+
+/**
+ * gnome_bg_slide_show_get_current_slide:
+ * @self: a #GnomeBGSlideShow
+ * @width: monitor width
+ * @height: monitor height
+ * @progress: slide progress
+ * @duration: slide duration
+ * @is_fixed: if slide is fixed
+ * @file1: (transfer none): first file in slide
+ * @file2: (transfer none): second file in slide
+ *
+ * Returns the current slides progress
+ *
+ * Return value: %TRUE if successful
+ **/
+void
+gnome_bg_slide_show_get_current_slide (GnomeBGSlideShow  *self,
+                                       int                width,
+                                       int                height,
+                                       gdouble           *progress,
+                                       double            *duration,
+                                       gboolean          *is_fixed,
+                                       const char       **file1,
+                                       const char       **file2)
+{
+       double delta = fmod (now() - self->priv->start_time, self->priv->total_duration);
+       GList *list;
+       double elapsed;
+       int i;
+
+       if (delta < 0)
+               delta += self->priv->total_duration;
+
+       elapsed = 0;
+       i = 0;
+       for (list = self->priv->slides->head; list != NULL; list = list->next) {
+               Slide *slide = list->data;
+
+               if (elapsed + slide->duration > delta) {
+                        if (progress)
+                            *progress = (delta - elapsed) / (double)slide->duration;
+                        if (duration)
+                            *duration = slide->duration;
+
+                        if (is_fixed)
+                            *is_fixed = slide->fixed;
+
+                        if (file1)
+                            *file1 = find_best_size (slide->file1, width, height);
+
+                        if (file2 && slide->file2)
+                            *file2 = find_best_size (slide->file2, width, height);
+
+                        return;
+               }
+
+               i++;
+               elapsed += slide->duration;
+       }
+
+       /* this should never happen since we have slides and we should always
+        * find a current slide for the elapsed time since beginning -- we're
+        * looping with fmod() */
+       g_assert_not_reached ();
+}
+
+/**
+ * gnome_bg_slide_show_get_slide:
+ * @self: a #GnomeBGSlideShow
+ * @frame_number: frame number
+ * @width: monitor width
+ * @height: monitor height
+ * @duration: slide duration
+ * @is_fixed: if slide is fixed
+ * @file1: (transfer none): first file in slide
+ * @file2: (transfer none): second file in slide
+ *
+ * Retrieves slide by frame number
+ *
+ * Return value: %TRUE if successful
+ **/
+gboolean
+gnome_bg_slide_show_get_slide (GnomeBGSlideShow  *self,
+                               int                frame_number,
+                               int                width,
+                               int                height,
+                               double            *progress,
+                               double            *duration,
+                               gboolean          *is_fixed,
+                               const char       **file1,
+                               const char       **file2)
+{
+       double delta = fmod (now() - self->priv->start_time, self->priv->total_duration);
+        GList *l;
+        int i, skipped;
+        gboolean found;
+        double elapsed;
+        Slide *slide;
+
+       if (delta < 0)
+               delta += self->priv->total_duration;
+
+        elapsed = 0;
+       i = 0;
+       skipped = 0;
+       found = FALSE;
+       for (l = self->priv->slides->head; l; l = l->next) {
+               slide = l->data;
+
+               if (!slide->fixed) {
+                        elapsed += slide->duration;
+
+                       skipped++;
+                       continue;
+               }
+               if (i == frame_number) {
+                       found = TRUE;
+                       break;
+               }
+               i++;
+                elapsed += slide->duration;
+       }
+       if (!found)
+               return FALSE;
+
+        if (progress) {
+            if (elapsed + slide->duration > delta) {
+                    *progress = (delta - elapsed) / (double)slide->duration;
+            } else {
+                    *progress = 0.0;
+            }
+        }
+
+        if (duration)
+                *duration = slide->duration;
+
+        if (is_fixed)
+                *is_fixed = slide->fixed;
+
+        if (file1)
+                *file1 = find_best_size (slide->file1, width, height);
+
+        if (file2 && slide->file2)
+                *file2 = find_best_size (slide->file2, width, height);
+
+        return TRUE;
+}
+
+/**
+ * gnome_bg_slide_show_load:
+ * @self: a #GnomeBGSlideShow
+ * @error: a #GError
+ *
+ * Tries to load the slide show.
+ *
+ * Return value: %TRUE if successful
+ **/
+gboolean
+gnome_bg_slide_show_load (GnomeBGSlideShow  *self,
+                          GError           **error)
+{
+        GMarkupParser parser = {
+                handle_start_element,
+                handle_end_element,
+                handle_text,
+                NULL, /* passthrough */
+                NULL, /* error */
+        };
+
+        GFile *file;
+        char *contents = NULL;
+        gsize len;
+        GMarkupParseContext *context = NULL;
+        time_t t;
+        gboolean failed = FALSE;
+
+        file = g_file_new_for_path (self->priv->filename);
+        if (!g_file_load_contents (file, NULL, &contents, &len, NULL, NULL)) {
+                return FALSE;
+        }
+        g_object_unref (file);
+
+        threadsafe_localtime ((time_t)0, &self->priv->start_tm);
+
+        context = g_markup_parse_context_new (&parser, 0, self, NULL);
+
+        if (!g_markup_parse_context_parse (context, contents, len, error)) {
+                failed = TRUE;
+        }
+
+        if (!failed && !g_markup_parse_context_end_parse (context, error)) {
+                failed = TRUE;
+        }
+
+        g_markup_parse_context_free (context);
+
+        if (!failed) {
+                int len;
+
+                t = mktime (&self->priv->start_tm);
+
+                self->priv->start_time = (double)t;
+
+                len = g_queue_get_length (self->priv->slides);
+
+                /* no slides, that's not a slideshow */
+                if (len == 0) {
+                        failed = TRUE;
+                /* one slide, there's no transition */
+                } else if (len == 1) {
+                        Slide *slide = self->priv->slides->head->data;
+                        slide->duration = self->priv->total_duration = G_MAXUINT;
+                }
+        }
+
+        g_free (contents);
+
+        return !failed;
+}
+
+/**
+ * gnome_bg_slide_show_get_start_time:
+ * @self: a #GnomeBGSlideShow
+ *
+ * gets the start time of the slide show
+ *
+ * Return value: a timestamp
+ **/
+double
+gnome_bg_slide_show_get_start_time (GnomeBGSlideShow *self)
+{
+        return self->priv->start_time;
+}
+
+/**
+ * gnome_bg_slide_show_get_total_duration:
+ * @self: a #GnomeBGSlideShow
+ *
+ * gets the total duration of the slide show
+ *
+ * Return value: a timestamp
+ **/
+double
+gnome_bg_slide_show_get_total_duration (GnomeBGSlideShow *self)
+{
+        return self->priv->total_duration;
+}
+
+/**
+ * gnome_bg_slide_show_get_has_multiple_sizes:
+ * @self: a #GnomeBGSlideShow
+ *
+ * gets whether or not the slide show has multiple sizes for different monitors
+ *
+ * Return value: %TRUE if multiple sizes
+ **/
+gboolean
+gnome_bg_slide_show_get_has_multiple_sizes (GnomeBGSlideShow *self)
+{
+        return self->priv->has_multiple_sizes;
+}
+
+/**
+ * gnome_bg_slide_show_get_num_slides:
+ * @self: a #GnomeBGSlideShow
+ *
+ * Returns number of slides in slide show
+ **/
+int
+gnome_bg_slide_show_get_num_slides (GnomeBGSlideShow *self)
+{
+        return g_queue_get_length (self->priv->slides);
+}
diff --git a/libgnome-desktop/gnome-bg-slide-show.h b/libgnome-desktop/gnome-bg-slide-show.h
new file mode 100644
index 0000000..5776f7c
--- /dev/null
+++ b/libgnome-desktop/gnome-bg-slide-show.h
@@ -0,0 +1,89 @@
+/* gnome-bg-slide_show.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_SLIDE_SHOW_H__
+#define __GNOME_BG_SLIDE_SHOW_H__
+
+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
+#error    GnomeBGSlideShow is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including 
gnome-bg-slide_show.h
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GNOME_BG_TYPE_SLIDE_SHOW            (gnome_bg_slide_show_get_type ())
+#define GNOME_BG_SLIDE_SHOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_BG_TYPE_SLIDE_SHOW, 
GnomeBGSlideShow))
+#define GNOME_BG_SLIDE_SHOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GNOME_BG_TYPE_SLIDE_SHOW, 
GnomeBGSlideShowClass))
+#define GNOME_BG_IS_SLIDE_SHOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_BG_TYPE_SLIDE_SHOW))
+#define GNOME_BG_IS_SLIDE_SHOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GNOME_BG_TYPE_SLIDE_SHOW))
+#define GNOME_BG_SLIDE_SHOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GNOME_BG_TYPE_SLIDE_SHOW, 
GnomeBGSlideShowClass))
+
+typedef struct _GnomeBGSlideShowPrivate GnomeBGSlideShowPrivate;
+typedef struct _GnomeBGSlideShow GnomeBGSlideShow;
+typedef struct _GnomeBGSlideShowClass GnomeBGSlideShowClass;
+
+struct _GnomeBGSlideShow
+{
+       GObject parent_object;
+
+       GnomeBGSlideShowPrivate *priv;
+};
+
+struct _GnomeBGSlideShowClass
+{
+       GObjectClass parent_class;
+};
+
+GType             gnome_bg_slide_show_get_type (void);
+GnomeBGSlideShow *gnome_bg_slide_show_new (const char *filename);
+gboolean          gnome_bg_slide_show_load (GnomeBGSlideShow  *self,
+                                            GError           **error);
+gboolean          gnome_bg_slide_show_get_slide (GnomeBGSlideShow *self,
+                                                 int               frame_number,
+                                                 int               width,
+                                                 int               height,
+                                                 gdouble          *progress,
+                                                 double           *duration,
+                                                 gboolean         *is_fixed,
+                                                 const char      **file1,
+                                                 const char      **file2);
+
+void              gnome_bg_slide_show_get_current_slide (GnomeBGSlideShow  *self,
+                                                         int                width,
+                                                         int                height,
+                                                         gdouble           *progress,
+                                                         double            *duration,
+                                                         gboolean          *is_fixed,
+                                                         const char       **file1,
+                                                         const char       **file2);
+
+
+double gnome_bg_slide_show_get_start_time (GnomeBGSlideShow *self);
+double gnome_bg_slide_show_get_total_duration (GnomeBGSlideShow *self);
+gboolean gnome_bg_slide_show_get_has_multiple_sizes (GnomeBGSlideShow *self);
+int  gnome_bg_slide_show_get_num_slides (GnomeBGSlideShow *self);
+G_END_DECLS
+
+#endif
diff --git a/libgnome-desktop/gnome-bg.c b/libgnome-desktop/gnome-bg.c
index 0073d68..36e4a5f 100644
--- a/libgnome-desktop/gnome-bg.c
+++ b/libgnome-desktop/gnome-bg.c
@@ -44,6 +44,7 @@ Author: Soren Sandmann <sandmann redhat com>
 
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include "gnome-bg.h"
+#include "gnome-bg-slide-show.h"
 #include "gnome-bg-crossfade.h"
 
 #define BG_KEY_DRAW_BACKGROUND    "draw-background"
@@ -58,27 +59,6 @@ Author: Soren Sandmann <sandmann redhat com>
    in the slideshow is less than 60 seconds away */
 #define KEEP_EXPENSIVE_CACHE_SECS 60
 
-typedef struct _SlideShow SlideShow;
-typedef struct _Slide Slide;
-
-struct _Slide
-{
-       double   duration;              /* in seconds */
-       gboolean fixed;
-
-       GSList  *file1;
-       GSList  *file2;         /* NULL if fixed is TRUE */
-};
-
-typedef struct _FileSize FileSize;
-struct _FileSize
-{
-       gint width;
-       gint height;
-
-       char *file;
-};
-
 /* This is the size of the GdkRGB dither matrix, in order to avoid
  * bad dithering when tiling the gradient
  */
@@ -108,7 +88,7 @@ struct _GnomeBG
        guint                   blow_caches_id;
 
        /* Cached information, only access through cache accessor functions */
-        SlideShow *            slideshow;
+        GnomeBGSlideShow *     slideshow;
        time_t                  file_mtime;
        GdkPixbuf *             pixbuf_cache;
        int                     timeout_id;
@@ -185,20 +165,10 @@ static GdkPixbuf *create_img_thumbnail (GnomeBG               *bg,
                                        int                    dest_width,
                                        int                    dest_height,
                                        int                    frame_num);
-static SlideShow * get_as_slideshow    (GnomeBG               *bg,
-                                       const char            *filename);
-static Slide *     get_current_slide   (SlideShow            *show,
-                                       double                *alpha);
-static gboolean    slideshow_has_multiple_sizes (SlideShow *show);
-
-static SlideShow *read_slideshow_file (const char *filename,
+static GnomeBGSlideShow * get_as_slideshow    (GnomeBG               *bg,
+                                               const char            *filename);
+static GnomeBGSlideShow *read_slideshow_file (const char *filename,
                                       GError     **err);
-static SlideShow *slideshow_ref       (SlideShow  *show);
-static void       slideshow_unref     (SlideShow  *show);
-
-static FileSize   *find_best_size      (GSList                *sizes,
-                                       gint                   width,
-                                       gint                   height);
 
 static void
 color_from_string (const char *string,
@@ -1025,7 +995,7 @@ gnome_bg_draw (GnomeBG *bg,
 gboolean
 gnome_bg_has_multiple_sizes (GnomeBG *bg)
 {
-       SlideShow *show;
+       GnomeBGSlideShow *show;
        gboolean ret;
 
        g_return_val_if_fail (bg != NULL, FALSE);
@@ -1034,8 +1004,8 @@ gnome_bg_has_multiple_sizes (GnomeBG *bg)
 
        show = get_as_slideshow (bg, bg->filename);
        if (show) {
-               ret = slideshow_has_multiple_sizes (show);
-               slideshow_unref (show);
+               ret = gnome_bg_slide_show_get_has_multiple_sizes (show);
+               g_object_unref (show);
        }
 
        return ret;
@@ -1272,9 +1242,8 @@ get_original_size (const char *filename,
 static const char *
 get_filename_for_size (GnomeBG *bg, gint best_width, gint best_height)
 {
-       SlideShow *show;
-       Slide *slide;
-       FileSize *size;
+       GnomeBGSlideShow *show;
+        const char *file = NULL;
 
        if (!bg->filename)
                return NULL;
@@ -1284,10 +1253,8 @@ get_filename_for_size (GnomeBG *bg, gint best_width, gint best_height)
                return bg->filename;
        }
 
-       slide = get_current_slide (show, NULL);
-       slideshow_unref (show);
-       size = find_best_size (slide->file1, best_width, best_height);
-       return size->file;
+        gnome_bg_slide_show_get_current_slide (show, best_width, best_height, NULL, NULL, NULL, &file, NULL);
+        return file;
 }
 
 gboolean
@@ -1647,51 +1614,6 @@ struct _SlideShow
 };
 
 
-static double
-now (void)
-{
-       GTimeVal tv;
-
-       g_get_current_time (&tv);
-
-       return (double)tv.tv_sec + (tv.tv_usec / 1000000.0);
-}
-
-static Slide *
-get_current_slide (SlideShow *show,
-                  double    *alpha)
-{
-       double delta = fmod (now() - show->start_time, show->total_duration);
-       GList *list;
-       double elapsed;
-       int i;
-
-       if (delta < 0)
-               delta += show->total_duration;
-
-       elapsed = 0;
-       i = 0;
-       for (list = show->slides->head; list != NULL; list = list->next) {
-               Slide *slide = list->data;
-
-               if (elapsed + slide->duration > delta) {
-                       if (alpha)
-                               *alpha = (delta - elapsed) / (double)slide->duration;
-                       return slide;
-               }
-
-               i++;
-               elapsed += slide->duration;
-       }
-
-       /* this should never happen since we have slides and we should always
-        * find a current slide for the elapsed time since beginning -- we're
-        * looping with fmod() */
-       g_assert_not_reached ();
-
-       return NULL;
-}
-
 static GdkPixbuf *
 blend (GdkPixbuf *p1,
        GdkPixbuf *p2,
@@ -1730,7 +1652,7 @@ struct FileCacheEntry
        char *filename;
        union {
                GdkPixbuf *pixbuf;
-               SlideShow *slideshow;
+               GnomeBGSlideShow *slideshow;
                GdkPixbuf *thumbnail;
        } u;
 };
@@ -1745,7 +1667,7 @@ file_cache_entry_delete (FileCacheEntry *ent)
                g_object_unref (ent->u.pixbuf);
                break;
        case SLIDESHOW:
-               slideshow_unref (ent->u.slideshow);
+               g_object_unref (ent->u.slideshow);
                break;
        case THUMBNAIL:
                g_object_unref (ent->u.thumbnail);
@@ -1825,10 +1747,10 @@ file_cache_add_thumbnail (GnomeBG *bg,
 static void
 file_cache_add_slide_show (GnomeBG *bg,
                           const char *filename,
-                          SlideShow *show)
+                          GnomeBGSlideShow *show)
 {
        FileCacheEntry *ent = file_cache_entry_new (bg, SLIDESHOW, filename);
-       ent->u.slideshow = slideshow_ref (show);
+       ent->u.slideshow = g_object_ref (show);
 }
 
 static GdkPixbuf *
@@ -1899,15 +1821,15 @@ get_as_pixbuf_for_size (GnomeBG    *bg,
        }
 }
 
-static SlideShow *
+static GnomeBGSlideShow *
 get_as_slideshow (GnomeBG *bg, const char *filename)
 {
        const FileCacheEntry *ent;
        if ((ent = file_cache_lookup (bg, SLIDESHOW, filename))) {
-               return slideshow_ref (ent->u.slideshow);
+               return g_object_ref (ent->u.slideshow);
        }
        else {
-               SlideShow *show = read_slideshow_file (filename, NULL);
+               GnomeBGSlideShow *show = read_slideshow_file (filename, NULL);
 
                if (show)
                        file_cache_add_slide_show (bg, filename, show);
@@ -1984,11 +1906,12 @@ on_timeout (gpointer data)
 }
 
 static double
-get_slide_timeout (Slide   *slide)
+get_slide_timeout (gboolean is_fixed,
+                   gdouble  duration)
 {
        double timeout;
-       if (slide->fixed) {
-               timeout = slide->duration;
+       if (is_fixed) {
+               timeout = duration;
        } else {
                /* Maybe the number of steps should be configurable? */
                
@@ -2002,18 +1925,16 @@ get_slide_timeout (Slide   *slide)
                 * color mode in the worst case, so we'll use this as an approximation
                 * of whats detectable.
                 */
-               timeout = slide->duration / 64.0;
+               timeout = duration / 64.0;
        }
        return timeout;
 }
 
 static void
 ensure_timeout (GnomeBG *bg,
-               Slide   *slide)
+                gdouble  timeout)
 {
        if (!bg->timeout_id) {
-               double timeout = get_slide_timeout (slide);
-
                /* G_MAXUINT means "only one slide" */
                if (timeout < G_MAXUINT) {
                        bg->timeout_id = g_timeout_add_full (
@@ -2137,25 +2058,41 @@ create_img_thumbnail (GnomeBG                      *bg,
                        return result;
                }
                else {
-                       SlideShow *show = get_as_slideshow (bg, bg->filename);
+                       GnomeBGSlideShow *show = get_as_slideshow (bg, bg->filename);
 
                        if (show) {
                                double alpha;
-                               Slide *slide;
+                               double duration;
+                                gboolean is_fixed;
+                                const char *file1;
+                                const char *file2;
+                                GdkPixbuf *tmp;
 
                                if (frame_num == -1)
-                                       slide = get_current_slide (show, &alpha);
+                                       gnome_bg_slide_show_get_current_slide (show,
+                                                                               dest_width,
+                                                                               dest_height,
+                                                                               &alpha,
+                                                                               &duration,
+                                                                               &is_fixed,
+                                                                               &file1,
+                                                                               &file2);
                                else
-                                       slide = g_queue_peek_nth (show->slides, frame_num);
-
-                               if (slide->fixed) {
-                                       GdkPixbuf *tmp;
-                                       FileSize *fs;
-                                       fs = find_best_size (slide->file1, dest_width, dest_height);
-                                       tmp = get_as_thumbnail (bg, factory, fs->file);
+                                       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,
-                                                                        fs->file,
+                                                                        file1,
                                                                         tmp,
                                                                         screen,
                                                                         dest_width,
@@ -2164,26 +2101,22 @@ create_img_thumbnail (GnomeBG                      *bg,
                                        }
                                }
                                else {
-                                       FileSize *fs1, *fs2;
                                        GdkPixbuf *p1, *p2;
-                                       fs1 = find_best_size (slide->file1, dest_width, dest_height);
-                                       p1 = get_as_thumbnail (bg, factory, fs1->file);
-
-                                       fs2 = find_best_size (slide->file2, dest_width, dest_height);
-                                       p2 = get_as_thumbnail (bg, factory, fs2->file);
+                                       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,
-                                                                         fs1->file,
+                                                                         file1,
                                                                          p1,
                                                                          screen,
                                                                          dest_width,
                                                                          dest_height);
 
                                                thumb2 = scale_thumbnail (bg->placement,
-                                                                         fs2->file,
+                                                                         file2,
                                                                          p2,
                                                                          screen,
                                                                          dest_width,
@@ -2200,9 +2133,9 @@ create_img_thumbnail (GnomeBG                      *bg,
                                                g_object_unref (p2);
                                }
 
-                               ensure_timeout (bg, slide);
+                               ensure_timeout (bg, (guint)get_slide_timeout (is_fixed, duration));
 
-                               slideshow_unref (show);
+                               g_object_unref (show);
                        }
                }
 
@@ -2212,51 +2145,6 @@ create_img_thumbnail (GnomeBG                      *bg,
        return NULL;
 }
 
-/*
- * Find the FileSize that best matches the given size.
- * Do two passes; the first pass only considers FileSizes
- * that are larger than the given size.
- * We are looking for the image that best matches the aspect ratio.
- * When two images have the same aspect ratio, prefer the one whose
- * width is closer to the given width.
- */
-static FileSize *
-find_best_size (GSList *sizes, gint width, gint height)
-{
-       GSList *s;
-       gdouble a, d, distance;
-       FileSize *best = NULL;
-       gint pass;
-
-       a = width/(gdouble)height;
-       distance = 10000.0;
-
-       for (pass = 0; pass < 2; pass++) {
-               for (s = sizes; s; s = s->next) {
-                       FileSize *size = s->data;
-
-                       if (pass == 0 && (size->width < width || size->height < height))
-                               continue;       
-
-                       d = fabs (a - size->width/(gdouble)size->height);
-                       if (d < distance) {
-                               distance = d;
-                               best = size;
-                       } 
-                       else if (d == distance) {
-                               if (abs (size->width - width) < abs (best->width - width)) {
-                                       best = size;
-                               }
-                       }
-               }
-
-               if (best)
-                       break;
-       }
-
-       return best;
-}
-
 static GdkPixbuf *
 get_pixbuf_for_size (GnomeBG *bg,
                     gint num_monitor,
@@ -2284,28 +2172,33 @@ get_pixbuf_for_size (GnomeBG *bg,
                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) {
-                       SlideShow *show = get_as_slideshow (bg, bg->filename);
+                       GnomeBGSlideShow *show = get_as_slideshow (bg, bg->filename);
 
                        if (show) {
                                double alpha;
-                               Slide *slide;
-
-                               slideshow_ref (show);
-
-                               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, 
num_monitor, best_width, best_height);
+                                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 {
-                                       FileSize *size;
                                        GdkPixbuf *p1, *p2;
-                                       size = find_best_size (slide->file1, best_width, best_height);
-                                       p1 = get_as_pixbuf_for_size (bg, size->file, num_monitor, best_width, 
best_height);
-                                       size = find_best_size (slide->file2, best_width, best_height);
-                                       p2 = get_as_pixbuf_for_size (bg, size->file, num_monitor, best_width, 
best_height);
+                                       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);
@@ -2316,9 +2209,9 @@ get_pixbuf_for_size (GnomeBG *bg,
                                                g_object_unref (p2);
                                }
 
-                               ensure_timeout (bg, slide);
+                               ensure_timeout (bg, time_until_next_change);
 
-                               slideshow_unref (show);
+                               g_object_unref (show);
                        }
                }
 
@@ -2641,355 +2534,20 @@ pixbuf_tile (GdkPixbuf *src, GdkPixbuf *dest)
        }
 }
 
-static gboolean stack_is (SlideShow *parser, const char *s1, ...);
-
-/* Parser for fading background */
-static void
-handle_start_element (GMarkupParseContext *context,
-                     const gchar         *name,
-                     const gchar        **attr_names,
-                     const gchar        **attr_values,
-                     gpointer             user_data,
-                     GError             **err)
-{
-       SlideShow *parser = user_data;
-       gint i;
-       
-       if (strcmp (name, "static") == 0 || strcmp (name, "transition") == 0) {
-               Slide *slide = g_new0 (Slide, 1);
-               
-               if (strcmp (name, "static") == 0)
-                       slide->fixed = TRUE;
-               
-               g_queue_push_tail (parser->slides, slide);
-       }
-       else if (strcmp (name, "size") == 0) {
-               Slide *slide = parser->slides->tail->data;
-               FileSize *size = g_new0 (FileSize, 1);
-               for (i = 0; attr_names[i]; i++) {
-                       if (strcmp (attr_names[i], "width") == 0)
-                               size->width = atoi (attr_values[i]);
-                       else if (strcmp (attr_names[i], "height") == 0)
-                               size->height = atoi (attr_values[i]);
-               }
-               if (parser->stack->tail &&
-                   (strcmp (parser->stack->tail->data, "file") == 0 ||
-                    strcmp (parser->stack->tail->data, "from") == 0)) {
-                       slide->file1 = g_slist_prepend (slide->file1, size);
-               }
-               else if (parser->stack->tail &&
-                        strcmp (parser->stack->tail->data, "to") == 0) { 
-                       slide->file2 = g_slist_prepend (slide->file2, size);
-               }
-       }
-       g_queue_push_tail (parser->stack, g_strdup (name));
-}
-
-static void
-handle_end_element (GMarkupParseContext *context,
-                   const gchar         *name,
-                   gpointer             user_data,
-                   GError             **err)
-{
-       SlideShow *parser = user_data;
-       
-       g_free (g_queue_pop_tail (parser->stack));
-}
-
-static gboolean
-stack_is (SlideShow *parser,
-         const char *s1,
-         ...)
-{
-       GList *stack = NULL;
-       const char *s;
-       GList *l1, *l2;
-       va_list args;
-       
-       stack = g_list_prepend (stack, (gpointer)s1);
-       
-       va_start (args, s1);
-       
-       s = va_arg (args, const char *);
-       while (s) {
-               stack = g_list_prepend (stack, (gpointer)s);
-               s = va_arg (args, const char *);
-       }
-       
-       l1 = stack;
-       l2 = parser->stack->head;
-       
-       while (l1 && l2) {
-               if (strcmp (l1->data, l2->data) != 0) {
-                       g_list_free (stack);
-                       return FALSE;
-               }
-               
-               l1 = l1->next;
-               l2 = l2->next;
-       }
-
-       g_list_free (stack);
-
-       return (!l1 && !l2);
-}
-
-static int
-parse_int (const char *text)
-{
-       return strtol (text, NULL, 0);
-}
-
-static void
-handle_text (GMarkupParseContext *context,
-            const gchar         *text,
-            gsize                text_len,
-            gpointer             user_data,
-            GError             **err)
-{
-       SlideShow *parser = user_data;
-       Slide *slide = parser->slides->tail? parser->slides->tail->data : NULL;
-       FileSize *fs;
-       gint i;
-
-       if (stack_is (parser, "year", "starttime", "background", NULL)) {
-               parser->start_tm.tm_year = parse_int (text) - 1900;
-       }
-       else if (stack_is (parser, "month", "starttime", "background", NULL)) {
-               parser->start_tm.tm_mon = parse_int (text) - 1;
-       }
-       else if (stack_is (parser, "day", "starttime", "background", NULL)) {
-               parser->start_tm.tm_mday = parse_int (text);
-       }
-       else if (stack_is (parser, "hour", "starttime", "background", NULL)) {
-               parser->start_tm.tm_hour = parse_int (text) - 1;
-       }
-       else if (stack_is (parser, "minute", "starttime", "background", NULL)) {
-               parser->start_tm.tm_min = parse_int (text);
-       }
-       else if (stack_is (parser, "second", "starttime", "background", NULL)) {
-               parser->start_tm.tm_sec = parse_int (text);
-       }
-       else if (stack_is (parser, "duration", "static", "background", NULL) ||
-                stack_is (parser, "duration", "transition", "background", NULL)) {
-               slide->duration = g_strtod (text, NULL);
-               parser->total_duration += slide->duration;
-       }
-       else if (stack_is (parser, "file", "static", "background", NULL) ||
-                stack_is (parser, "from", "transition", "background", NULL)) {
-               for (i = 0; text[i]; i++) {
-                       if (!g_ascii_isspace (text[i]))
-                               break;
-               }
-               if (text[i] == 0)
-                       return;
-               fs = g_new (FileSize, 1);
-               fs->width = -1;
-               fs->height = -1;
-               fs->file = g_strdup (text);
-               slide->file1 = g_slist_prepend (slide->file1, fs);
-               if (slide->file1->next != NULL)
-                       parser->has_multiple_sizes = TRUE;                       
-       }
-       else if (stack_is (parser, "size", "file", "static", "background", NULL) ||
-                stack_is (parser, "size", "from", "transition", "background", NULL)) {
-               fs = slide->file1->data;
-               fs->file = g_strdup (text);
-               if (slide->file1->next != NULL)
-                       parser->has_multiple_sizes = TRUE; 
-       }
-       else if (stack_is (parser, "to", "transition", "background", NULL)) {
-               for (i = 0; text[i]; i++) {
-                       if (!g_ascii_isspace (text[i]))
-                               break;
-               }
-               if (text[i] == 0)
-                       return;
-               fs = g_new (FileSize, 1);
-               fs->width = -1;
-               fs->height = -1;
-               fs->file = g_strdup (text);
-               slide->file2 = g_slist_prepend (slide->file2, fs);
-               if (slide->file2->next != NULL)
-                       parser->has_multiple_sizes = TRUE;                       
-       }
-       else if (stack_is (parser, "size", "to", "transition", "background", NULL)) {
-               fs = slide->file2->data;
-               fs->file = g_strdup (text);
-               if (slide->file2->next != NULL)
-                       parser->has_multiple_sizes = TRUE;
-       }
-}
-
-static SlideShow *
-slideshow_ref (SlideShow *show)
-{
-       show->ref_count++;
-       return show;
-}
-
-static void
-slideshow_unref (SlideShow *show)
-{
-       GList *list;
-       GSList *slist;
-       FileSize *size;
-
-       show->ref_count--;
-       if (show->ref_count > 0)
-               return;
-
-       for (list = show->slides->head; list != NULL; list = list->next) {
-               Slide *slide = list->data;
-
-               for (slist = slide->file1; slist != NULL; slist = slist->next) {
-                       size = slist->data;
-                       g_free (size->file);
-                       g_free (size);
-               }
-               g_slist_free (slide->file1);
-
-               for (slist = slide->file2; slist != NULL; slist = slist->next) {
-                       size = slist->data;
-                       g_free (size->file);
-                       g_free (size);
-               }
-               g_slist_free (slide->file2);
-
-               g_free (slide);
-       }
-
-       g_queue_free (show->slides);
-       
-       g_list_foreach (show->stack->head, (GFunc) g_free, NULL);
-       g_queue_free (show->stack);
-       
-       g_free (show);
-}
-
-static void
-dump_bg (SlideShow *show)
-{
-#if 0
-       GList *list;
-       GSList *slist;
-       
-       for (list = show->slides->head; list != NULL; list = list->next)
-       {
-               Slide *slide = list->data;
-               
-               g_print ("\nSlide: %s\n", slide->fixed? "fixed" : "transition");
-               g_print ("duration: %f\n", slide->duration);
-               g_print ("File1:\n");
-               for (slist = slide->file1; slist != NULL; slist = slist->next) {
-                       FileSize *size = slist->data;
-                       g_print ("\t%s (%dx%d)\n", 
-                                size->file, size->width, size->height);
-               }
-               g_print ("File2:\n");
-               for (slist = slide->file2; slist != NULL; slist = slist->next) {
-                       FileSize *size = slist->data;
-                       g_print ("\t%s (%dx%d)\n", 
-                                size->file, size->width, size->height);
-               }
-       }
-#endif
-}
-
-static void
-threadsafe_localtime (time_t time, struct tm *tm)
-{
-       struct tm *res;
-       
-       G_LOCK_DEFINE_STATIC (localtime_mutex);
-
-       G_LOCK (localtime_mutex);
-
-       res = localtime (&time);
-       if (tm) {
-               *tm = *res;
-       }
-       
-       G_UNLOCK (localtime_mutex);
-}
-
-static SlideShow *
+static GnomeBGSlideShow *
 read_slideshow_file (const char *filename,
                     GError     **err)
 {
-       GMarkupParser parser = {
-               handle_start_element,
-               handle_end_element,
-               handle_text,
-               NULL, /* passthrough */
-               NULL, /* error */
-       };
-       
-       GFile *file;
-       char *contents = NULL;
-       gsize len;
-       SlideShow *show = NULL;
-       GMarkupParseContext *context = NULL;
-       time_t t;
-
-       if (!filename)
-               return NULL;
-
-       file = g_file_new_for_path (filename);
-       if (!g_file_load_contents (file, NULL, &contents, &len, NULL, NULL)) {
-               g_object_unref (file);
-               return NULL;
-       }
-       g_object_unref (file);
-       
-       show = g_new0 (SlideShow, 1);
-       show->ref_count = 1;
-       threadsafe_localtime ((time_t)0, &show->start_tm);
-       show->stack = g_queue_new ();
-       show->slides = g_queue_new ();
-       
-       context = g_markup_parse_context_new (&parser, 0, show, NULL);
-       
-       if (!g_markup_parse_context_parse (context, contents, len, err)) {
-               slideshow_unref (show);
-               show = NULL;
-       }
-       
+        GnomeBGSlideShow *show;
 
-       if (show) {
-               if (!g_markup_parse_context_end_parse (context, err)) {
-                       slideshow_unref (show);
-                       show = NULL;
-               }
-       }
-       
-       g_markup_parse_context_free (context);
+        show = gnome_bg_slide_show_new (filename);
 
-       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 (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 = show->total_duration = G_MAXUINT;
-               }
-       }
+        if (!gnome_bg_slide_show_load (show, err)) {
+            g_object_unref (show);
+            return NULL;
+        }
 
-       g_free (contents);
-       
-       return show;
+        return show;
 }
 
 /* Thumbnail utilities */
@@ -3071,25 +2629,19 @@ get_thumb_annotations (GdkPixbuf *thumb,
        return FALSE;
 }
 
-static gboolean
-slideshow_has_multiple_sizes (SlideShow *show)
-{
-       return show->has_multiple_sizes;
-}
-
 /*
  * Returns whether the background is a slideshow.
  */
 gboolean
 gnome_bg_changes_with_time (GnomeBG *bg)
 {
-       SlideShow *show;
+       GnomeBGSlideShow *show;
 
        g_return_val_if_fail (bg != NULL, FALSE);
 
        show = get_as_slideshow (bg, bg->filename);
        if (show)
-               return g_queue_get_length (show->slides) > 1;
+               return gnome_bg_slide_show_get_num_slides (show) > 1;
 
        return FALSE;
 }
@@ -3112,12 +2664,12 @@ gnome_bg_create_frame_thumbnail (GnomeBG                        *bg,
                                 int                             dest_height,
                                 int                             frame_num)
 {
-       SlideShow *show;
+       GnomeBGSlideShow *show;
        GdkPixbuf *result;
        GdkPixbuf *thumb;
         GList *l;
-        int i, skipped;
-        gboolean found;
+        int skipped;
+        gboolean is_fixed;
 
        g_return_val_if_fail (bg != NULL, FALSE);
 
@@ -3127,27 +2679,17 @@ gnome_bg_create_frame_thumbnail (GnomeBG                        *bg,
                return NULL;
 
 
-       if (frame_num < 0 || frame_num >= g_queue_get_length (show->slides))
+       if (frame_num < 0 || frame_num >= gnome_bg_slide_show_get_num_slides (show))
                return NULL;
 
-       i = 0;
-       skipped = 0;
-       found = FALSE;
-       for (l = show->slides->head; l; l = l->next) {
-               Slide *slide = l->data;
-               if (!slide->fixed) {
-                       skipped++;
-                       continue;
-               }
-               if (i == frame_num) {
-                       found = TRUE;
-                       break;
-               }
-               i++;
-       }
-       if (!found)
-               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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]