[gthumb] [slideshow] use a simple slideshow if clutter is not available



commit 6814927c486268f0129e42f00c930db2c29d3ce6
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sat Apr 24 23:35:30 2010 +0200

    [slideshow] use a simple slideshow if clutter is not available
    
    If clutter is not available or the clutter initialization fails
    use a simple slideshow with no transitions based on gth_image_viewer,
    instead of disabling the slideshow feature altogether.

 extensions/slideshow/Makefile.am      |    4 -
 extensions/slideshow/actions.c        |   25 +-
 extensions/slideshow/callbacks.c      |    4 +
 extensions/slideshow/gth-slideshow.c  |  868 +++++++++++++++++++++------------
 extensions/slideshow/gth-slideshow.h  |   45 ++-
 extensions/slideshow/gth-transition.c |    6 +-
 extensions/slideshow/gth-transition.h |    6 +-
 extensions/slideshow/main.c           |   10 +-
 extensions/slideshow/preferences.c    |    4 +
 9 files changed, 617 insertions(+), 355 deletions(-)
---
diff --git a/extensions/slideshow/Makefile.am b/extensions/slideshow/Makefile.am
index 26329c7..e40a44c 100644
--- a/extensions/slideshow/Makefile.am
+++ b/extensions/slideshow/Makefile.am
@@ -1,5 +1,3 @@
-if ENABLE_CLUTTER
-
 SUBDIRS = data
 
 extensiondir = $(pkglibdir)/extensions
@@ -32,8 +30,6 @@ extensioninidir = $(extensiondir)
 extensionini_DATA = $(extensionini_in_files:.extension.in.in=.extension)
 DISTCLEANFILES = $(extensionini_DATA)
 
-endif
-
 extensionini_in_files = slideshow.extension.in.in
 
 %.extension.in: %.extension.in.in $(extension_LTLIBRARIES)
diff --git a/extensions/slideshow/actions.c b/extensions/slideshow/actions.c
index 6ac470c..5af174d 100644
--- a/extensions/slideshow/actions.c
+++ b/extensions/slideshow/actions.c
@@ -33,12 +33,13 @@ void
 gth_browser_activate_action_view_slideshow (GtkAction  *action,
 					    GthBrowser *browser)
 {
-	GList       *items;
-	GList       *file_list;
-	GtkWidget   *slideshow;
-	GthFileData *location;
-	char        *transition_id;
-	GList       *transitions = NULL;
+	GList        *items;
+	GList        *file_list;
+	GthProjector *projector;
+	GtkWidget    *slideshow;
+	GthFileData  *location;
+	char         *transition_id;
+	GList        *transitions = NULL;
 
 	items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
 	if ((items == NULL) || (items->next == NULL))
@@ -46,10 +47,18 @@ gth_browser_activate_action_view_slideshow (GtkAction  *action,
 	else
 		file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
 
-	slideshow = gth_slideshow_new (browser, file_list);
+	projector = NULL;
+#ifdef HAVE_CLUTTER
+	if (ClutterInitResult == CLUTTER_INIT_SUCCESS)
+		projector = &clutter_projector;
+#endif /* HAVE_CLUTTER */
+	if (projector == NULL)
+		projector = &default_projector;
+
+	slideshow = gth_slideshow_new (projector, browser, file_list);
 
 	location = gth_browser_get_location_data (browser);
-	if (g_file_info_get_attribute_status (location->info, "slideshow::personalize") == G_FILE_ATTRIBUTE_STATUS_SET) {
+	if (g_file_info_get_attribute_boolean (location->info, "slideshow::personalize")) {
 		gth_slideshow_set_delay (GTH_SLIDESHOW (slideshow), g_file_info_get_attribute_int32 (location->info, "slideshow::delay"));
 		gth_slideshow_set_automatic (GTH_SLIDESHOW (slideshow), g_file_info_get_attribute_boolean (location->info, "slideshow::automatic"));
 		gth_slideshow_set_wrap_around (GTH_SLIDESHOW (slideshow), g_file_info_get_attribute_boolean (location->info, "slideshow::wrap-around"));
diff --git a/extensions/slideshow/callbacks.c b/extensions/slideshow/callbacks.c
index b968827..ea94b5d 100644
--- a/extensions/slideshow/callbacks.c
+++ b/extensions/slideshow/callbacks.c
@@ -382,6 +382,10 @@ ss__dlg_catalog_properties (GtkBuilder  *builder,
 	gtk_widget_show (gth_slideshow_preferences_get_widget (GTH_SLIDESHOW_PREFERENCES (slideshow_preferences), "playlist_box"));
 	gtk_widget_show (slideshow_preferences);
 
+#ifndef HAVE_CLUTTER
+	gtk_widget_hide (gth_slideshow_preferences_get_widget (GTH_SLIDESHOW_PREFERENCES (slideshow_preferences), "transition_box"));
+#endif /* ! HAVE_CLUTTER */
+
 	label = gtk_label_new (_("Slideshow"));
 	gtk_widget_show (label);
 
diff --git a/extensions/slideshow/gth-slideshow.c b/extensions/slideshow/gth-slideshow.c
index 4bf22ff..76bbbee 100644
--- a/extensions/slideshow/gth-slideshow.c
+++ b/extensions/slideshow/gth-slideshow.c
@@ -22,12 +22,15 @@
 
 #include <config.h>
 #include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#ifdef HAVE_CLUTTER
 #include <clutter/clutter.h>
 #include <clutter-gtk/clutter-gtk.h>
+#endif /* HAVE_CLUTTER */
 #if HAVE_GSTREAMER
 #include <gst/gst.h>
 #include <extensions/gstreamer_utils/gstreamer-utils.h>
-#endif
+#endif /* HAVE_GSTREAMER */
 #include "gth-slideshow.h"
 #include "gth-transition.h"
 
@@ -35,33 +38,44 @@
 #define DEFAULT_DELAY 2000
 
 
+typedef enum {
+	GTH_SLIDESHOW_DIRECTION_FORWARD,
+	GTH_SLIDESHOW_DIRECTION_BACKWARD
+} GthSlideshowDirection;
+
+
 struct _GthSlideshowPrivate {
-	GthBrowser        *browser;
-	GList             *file_list; /* GthFileData */
-	gboolean           automatic;
-	gboolean           wrap_around;
-	GList             *current;
-	GthImagePreloader *preloader;
-	GList             *transitions; /* GthTransition */
-	int                n_transitions;
-	GthTransition     *transition;
-	ClutterTimeline   *timeline;
-	ClutterActor      *image1;
-	ClutterActor      *image2;
-	guint              next_event;
-	guint              delay;
-	guint              hide_cursor_event;
-	GRand             *rand;
-	gboolean           first_show;
-	gboolean           one_loaded;
-	char             **audio_files;
-	gboolean           audio_loop;
+	GthProjector          *projector;
+	GthBrowser            *browser;
+	GList                 *file_list; /* GthFileData */
+	gboolean               automatic;
+	gboolean               wrap_around;
+	GList                 *current;
+	GthImagePreloader     *preloader;
+	GList                 *transitions; /* GthTransition */
+	int                    n_transitions;
+	GthTransition         *transition;
+	GthSlideshowDirection  direction;
+#if HAVE_CLUTTER
+	ClutterTimeline       *timeline;
+	ClutterActor          *image1;
+	ClutterActor          *image2;
+#endif
+	GtkWidget             *viewer;
+	guint                  next_event;
+	guint                  delay;
+	guint                  hide_cursor_event;
+	GRand                 *rand;
+	gboolean               first_show;
+	gboolean               one_loaded;
+	char                 **audio_files;
+	gboolean               audio_loop;
 #if HAVE_GSTREAMER
-	int                current_audio_file;
-	GstElement        *playbin;
+	int                    current_audio_file;
+	GstElement            *playbin;
 #endif
-	gboolean           paused;
-	gboolean           animating;
+	gboolean               paused;
+	gboolean               animating;
 };
 
 
@@ -101,7 +115,7 @@ _gth_slideshow_load_current_image (GthSlideshow *self)
 			return;
 		}
 
-		if (clutter_timeline_get_direction (self->priv->timeline) == CLUTTER_TIMELINE_FORWARD)
+		if (self->priv->direction == GTH_SLIDESHOW_DIRECTION_FORWARD)
 			self->priv->current = g_list_first (self->priv->file_list);
 		else
 			self->priv->current = g_list_last (self->priv->file_list);
@@ -124,6 +138,486 @@ _gth_slideshow_load_current_image (GthSlideshow *self)
 
 
 static void
+_gth_slideshow_load_next_image (GthSlideshow *self)
+{
+	self->priv->projector->load_next_image (self); /* FIXME */
+	self->priv->direction = GTH_SLIDESHOW_DIRECTION_FORWARD;
+
+	if (self->priv->paused)
+		return;
+
+	self->priv->current = self->priv->current->next;
+	_gth_slideshow_load_current_image (self);
+}
+
+
+static void
+_gth_slideshow_load_prev_image (GthSlideshow *self)
+{
+	self->priv->projector->load_prev_image (self); /* FIXME */
+	self->priv->direction = GTH_SLIDESHOW_DIRECTION_BACKWARD;
+
+	if (self->priv->paused)
+		return;
+
+	self->priv->current = self->priv->current->prev;
+	_gth_slideshow_load_current_image (self);
+}
+
+
+static gboolean
+next_image_cb (gpointer user_data)
+{
+	GthSlideshow *self = user_data;
+
+	if (self->priv->next_event != 0) {
+		g_source_remove (self->priv->next_event);
+		self->priv->next_event = 0;
+	}
+	_gth_slideshow_load_next_image (self);
+
+	return FALSE;
+}
+
+
+static void
+view_next_image_automatically (GthSlideshow *self)
+{
+	if (self->priv->automatic) {
+		if (self->priv->next_event != 0)
+			g_source_remove (self->priv->next_event);
+		self->priv->next_event = g_timeout_add (self->priv->delay, next_image_cb, self);
+	}
+}
+
+
+static void
+image_preloader_requested_ready_cb (GthImagePreloader *preloader,
+				    GError            *error,
+				    gpointer           user_data)
+{
+	GthSlideshow   *self = user_data;
+	GthImageLoader *image_loader;
+	GdkPixbuf      *pixbuf;
+
+	if (error != NULL) {
+		g_clear_error (&error);
+		_gth_slideshow_load_next_image (self);
+		return;
+	}
+
+	image_loader = gth_image_preloader_get_loader (self->priv->preloader, (GthFileData *) self->priv->current->data);
+	if (image_loader == NULL) {
+		_gth_slideshow_load_next_image (self);
+		return;
+	}
+
+	pixbuf = gth_image_loader_get_pixbuf (image_loader);
+	if (pixbuf == NULL) {
+		_gth_slideshow_load_next_image (self);
+		return;
+	}
+
+	self->priv->one_loaded = TRUE;
+	self->priv->projector->image_ready (self, pixbuf); /* FIXME */
+}
+
+
+static void
+gth_slideshow_init (GthSlideshow *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_SLIDESHOW, GthSlideshowPrivate);
+	self->priv->file_list = NULL;
+	self->priv->next_event = 0;
+	self->priv->delay = DEFAULT_DELAY;
+	self->priv->automatic = FALSE;
+	self->priv->wrap_around = FALSE;
+	self->priv->transitions = NULL;
+	self->priv->n_transitions = 0;
+	self->priv->rand = g_rand_new ();
+	self->priv->first_show = TRUE;
+	self->priv->audio_files = NULL;
+	self->priv->paused = FALSE;
+	self->priv->animating = FALSE;
+	self->priv->direction = GTH_SLIDESHOW_DIRECTION_FORWARD;
+
+	self->priv->preloader = gth_image_preloader_new ();
+	g_signal_connect (self->priv->preloader,
+			  "requested_ready",
+			  G_CALLBACK (image_preloader_requested_ready_cb),
+			  self);
+}
+
+
+static void
+gth_slideshow_finalize (GObject *object)
+{
+	GthSlideshow *self = GTH_SLIDESHOW (object);
+
+	if (self->priv->next_event != 0)
+		g_source_remove (self->priv->next_event);
+	if (self->priv->hide_cursor_event != 0)
+		g_source_remove (self->priv->hide_cursor_event);
+
+	_g_object_list_unref (self->priv->file_list);
+	_g_object_unref (self->priv->browser);
+	_g_object_unref (self->priv->preloader);
+	_g_object_list_unref (self->priv->transitions);
+	g_rand_free (self->priv->rand);
+	g_strfreev (self->priv->audio_files);
+	self->priv->projector->finalize (self); /* FIXME */
+
+#if HAVE_GSTREAMER
+	if (self->priv->playbin != NULL) {
+		gst_element_set_state (self->priv->playbin, GST_STATE_NULL);
+		gst_object_unref (GST_OBJECT (self->priv->playbin));
+		self->priv->playbin = NULL;
+	}
+#endif
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_slideshow_class_init (GthSlideshowClass *klass)
+{
+	GObjectClass *gobject_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthSlideshowPrivate));
+
+	gobject_class = G_OBJECT_CLASS (klass);
+	gobject_class->finalize = gth_slideshow_finalize;
+}
+
+
+GType
+gth_slideshow_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthSlideshowClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_slideshow_class_init,
+			NULL,
+			NULL,
+			sizeof (GthSlideshow),
+			0,
+			(GInstanceInitFunc) gth_slideshow_init
+		};
+
+		type = g_type_register_static (GTK_TYPE_WINDOW,
+					       "GthSlideshow",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+static gboolean
+hide_cursor_cb (gpointer data)
+{
+	GthSlideshow *self = data;
+
+	g_source_remove (self->priv->hide_cursor_event);
+	self->priv->hide_cursor_event = 0;
+	self->priv->projector->hide_cursor (self); /* FIXME */
+
+	return FALSE;
+}
+
+
+static void
+_gth_slideshow_toggle_pause (GthSlideshow *self)
+{
+	self->priv->paused = ! self->priv->paused;
+	if (self->priv->paused) {
+		self->priv->projector->paused (self); /* FIXME */
+#if HAVE_GSTREAMER
+		if (self->priv->playbin != NULL)
+			gst_element_set_state (self->priv->playbin, GST_STATE_PAUSED);
+#endif
+	}
+	else { /* resume */
+		_gth_slideshow_load_next_image (self);
+#if HAVE_GSTREAMER
+		if (self->priv->playbin != NULL)
+			gst_element_set_state (self->priv->playbin, GST_STATE_PLAYING);
+#endif
+	}
+}
+
+
+#if HAVE_GSTREAMER
+static void
+bus_message_cb (GstBus     *bus,
+                GstMessage *message,
+                gpointer    user_data)
+{
+	GthSlideshow *self = user_data;
+
+	if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS) {
+		self->priv->current_audio_file++;
+		if ((self->priv->audio_files[self->priv->current_audio_file] == NULL)
+		    && self->priv->audio_loop)
+		{
+			self->priv->current_audio_file = 0;
+		}
+		gst_element_set_state (self->priv->playbin, GST_STATE_NULL);
+		g_object_set (G_OBJECT (self->priv->playbin), "uri", self->priv->audio_files[self->priv->current_audio_file], NULL);
+		gst_element_set_state (self->priv->playbin, GST_STATE_PLAYING);
+	}
+}
+#endif
+
+
+static void
+gth_slideshow_show_cb (GtkWidget    *widget,
+		       GthSlideshow *self)
+{
+	if (! self->priv->first_show)
+		return;
+
+#if HAVE_GSTREAMER
+	if (gstreamer_init ()) {
+		if ((self->priv->audio_files != NULL) && (self->priv->audio_files[0] != NULL)) {
+			self->priv->current_audio_file = 0;
+			if (self->priv->playbin == NULL) {
+				GstBus *bus;
+
+				self->priv->playbin = gst_element_factory_make ("playbin", "playbin");
+				bus = gst_pipeline_get_bus (GST_PIPELINE (self->priv->playbin));
+				gst_bus_add_signal_watch (bus);
+				g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), self);
+			}
+			else
+				gst_element_set_state (self->priv->playbin, GST_STATE_NULL);
+			g_object_set (G_OBJECT (self->priv->playbin), "uri", self->priv->audio_files[self->priv->current_audio_file], NULL);
+			gst_element_set_state (self->priv->playbin, GST_STATE_PLAYING);
+		}
+	}
+#endif
+
+	_gth_slideshow_load_current_image (self);
+	self->priv->first_show = FALSE;
+}
+
+
+static void
+_gth_slideshow_construct (GthSlideshow *self,
+			  GthProjector *projector,
+			  GthBrowser   *browser,
+			  GList        *file_list)
+{
+	self->priv->projector = projector;
+	self->priv->browser = _g_object_ref (browser);
+	self->priv->file_list = _g_object_list_ref (file_list);
+	self->priv->current = self->priv->file_list;
+	self->priv->one_loaded = FALSE;
+
+	self->priv->projector->construct (self); /* FIXME */
+
+	g_signal_connect (self, "show", G_CALLBACK (gth_slideshow_show_cb), self);
+}
+
+
+GtkWidget *
+gth_slideshow_new (GthProjector *projector,
+		   GthBrowser   *browser,
+		   GList        *file_list /* GthFileData */)
+{
+	GthSlideshow *window;
+
+	g_return_val_if_fail (projector != NULL, NULL);
+
+	window = (GthSlideshow *) g_object_new (GTH_TYPE_SLIDESHOW, NULL);
+	_gth_slideshow_construct (window, projector, browser, file_list);
+
+	return (GtkWidget*) window;
+}
+
+
+void
+gth_slideshow_set_delay (GthSlideshow *self,
+			 guint         msecs)
+{
+	self->priv->delay = msecs;
+}
+
+
+void
+gth_slideshow_set_automatic (GthSlideshow *self,
+			     gboolean      automatic)
+{
+	self->priv->automatic = automatic;
+}
+
+
+void
+gth_slideshow_set_wrap_around (GthSlideshow *self,
+			       gboolean      wrap_around)
+{
+	self->priv->wrap_around = wrap_around;
+}
+
+
+void
+gth_slideshow_set_transitions (GthSlideshow *self,
+			       GList        *transitions)
+{
+	_g_object_list_unref (self->priv->transitions);
+	self->priv->transitions = _g_object_list_ref (transitions);
+	self->priv->n_transitions = g_list_length (self->priv->transitions);
+}
+
+
+void
+gth_slideshow_set_playlist (GthSlideshow  *self,
+			    char         **files)
+{
+	self->priv->audio_files = g_strdupv (files);
+	self->priv->audio_loop = TRUE;
+}
+
+
+/* -- default projector -- */
+
+
+static void
+default_projector_load_next_image (GthSlideshow *self)
+{
+	/* void */
+}
+
+
+static void
+default_projector_load_prev_image (GthSlideshow *self)
+{
+	/* void */
+}
+
+
+static void
+default_projector_image_ready (GthSlideshow *self,
+			       GdkPixbuf    *pixbuf)
+{
+	gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (self->priv->viewer), pixbuf);
+	view_next_image_automatically (self);
+}
+
+
+static void
+default_projector_finalize (GthSlideshow *self)
+{
+	/* void */
+}
+
+
+static void
+default_projector_hide_cursor (GthSlideshow *self)
+{
+	gth_image_viewer_hide_cursor (GTH_IMAGE_VIEWER (self->priv->viewer));
+}
+
+
+static void
+default_projector_paused (GthSlideshow *self)
+{
+	/* void */
+}
+
+
+static void
+viewer_event_cb (GtkWidget    *widget,
+	         GdkEvent     *event,
+	         GthSlideshow *self)
+{
+	if (event->type == GDK_MOTION_NOTIFY) {
+		gth_image_viewer_show_cursor (GTH_IMAGE_VIEWER (self->priv->viewer));
+		if (self->priv->hide_cursor_event != 0)
+			g_source_remove (self->priv->hide_cursor_event);
+		self->priv->hide_cursor_event = g_timeout_add (HIDE_CURSOR_DELAY, hide_cursor_cb, self);
+	}
+	else if (event->type == GDK_BUTTON_PRESS) {
+		switch (((GdkEventButton *) event)->button) {
+		case 1:
+			_gth_slideshow_load_next_image (self);
+			break;
+		case 3:
+			_gth_slideshow_load_prev_image (self);
+			break;
+		default:
+			break;
+		}
+	}
+	else if (event->type == GDK_KEY_RELEASE) {
+		switch (((GdkEventKey *) event)->keyval) {
+		case GDK_Escape:
+			_gth_slideshow_close (self);
+			break;
+
+		case GDK_space:
+			_gth_slideshow_toggle_pause (self);
+			break;
+
+		case GDK_Up:
+		case GDK_Right:
+			_gth_slideshow_load_next_image (self);
+			break;
+
+		case GDK_Down:
+		case GDK_Left:
+			_gth_slideshow_load_prev_image (self);
+			break;
+		}
+	}
+}
+
+
+static void
+default_projector_construct (GthSlideshow *self)
+{
+	self->priv->viewer = gth_image_viewer_new ();
+	gth_image_viewer_set_black_background (GTH_IMAGE_VIEWER (self->priv->viewer), TRUE);
+	gth_image_viewer_hide_frame (GTH_IMAGE_VIEWER (self->priv->viewer));
+	gth_image_viewer_set_fit_mode (GTH_IMAGE_VIEWER (self->priv->viewer), GTH_FIT_SIZE_IF_LARGER);
+	gth_image_viewer_set_zoom_change (GTH_IMAGE_VIEWER (self->priv->viewer), GTH_ZOOM_CHANGE_FIT_SIZE_IF_LARGER);
+	gth_image_viewer_set_transp_type (GTH_IMAGE_VIEWER (self->priv->viewer), GTH_TRANSP_TYPE_BLACK);
+	gth_image_viewer_set_zoom_quality (GTH_IMAGE_VIEWER (self->priv->viewer), GTH_ZOOM_QUALITY_LOW);
+
+	g_signal_connect (self->priv->viewer, "button-press-event", G_CALLBACK (viewer_event_cb), self);
+	g_signal_connect (self->priv->viewer, "motion-notify-event", G_CALLBACK (viewer_event_cb), self);
+	g_signal_connect (self->priv->viewer, "key-release-event", G_CALLBACK (viewer_event_cb), self);
+
+	gtk_widget_show (self->priv->viewer);
+	gtk_container_add (GTK_CONTAINER (self), self->priv->viewer);
+}
+
+
+GthProjector default_projector = {
+	default_projector_construct,
+	default_projector_paused,
+	default_projector_hide_cursor,
+	default_projector_finalize,
+	default_projector_image_ready,
+	default_projector_load_prev_image,
+	default_projector_load_next_image
+};
+
+
+#ifdef HAVE_CLUTTER
+
+
+/* -- clutter projector -- */
+
+
+static void
 _gth_slideshow_swap_current_and_next (GthSlideshow *self)
 {
 	ClutterGeometry tmp_geometry;
@@ -212,48 +706,24 @@ _gth_slideshow_animation_completed (GthSlideshow *self)
 
 
 static void
-_gth_slideshow_load_next_image (GthSlideshow *self)
+clutter_projector_load_next_image (GthSlideshow *self)
 {
 	if (clutter_timeline_is_playing (self->priv->timeline)) {
 		clutter_timeline_pause (self->priv->timeline);
 		_gth_slideshow_animation_completed (self);
 	}
-
-	if (self->priv->paused)
-		return;
-
-	self->priv->current = self->priv->current->next;
 	clutter_timeline_set_direction (self->priv->timeline, CLUTTER_TIMELINE_FORWARD);
-	_gth_slideshow_load_current_image (self);
 }
 
 
 static void
-_gth_slideshow_load_prev_image (GthSlideshow *self)
+clutter_projector_load_prev_image (GthSlideshow *self)
 {
 	if (clutter_timeline_is_playing (self->priv->timeline)) {
 		clutter_timeline_pause (self->priv->timeline);
 		_gth_slideshow_animation_completed (self);
 	}
-
-	self->priv->current = self->priv->current->prev;
 	clutter_timeline_set_direction (self->priv->timeline, CLUTTER_TIMELINE_BACKWARD);
-	_gth_slideshow_load_current_image (self);
-}
-
-
-static gboolean
-next_image_cb (gpointer user_data)
-{
-	GthSlideshow *self = user_data;
-
-	if (self->priv->next_event != 0) {
-		g_source_remove (self->priv->next_event);
-		self->priv->next_event = 0;
-	}
-	_gth_slideshow_load_next_image (self);
-
-	return FALSE;
 }
 
 
@@ -262,12 +732,7 @@ animation_completed_cb (ClutterTimeline *timeline,
 			GthSlideshow    *self)
 {
 	_gth_slideshow_animation_completed (self);
-
-	if (self->priv->automatic) {
-		if (self->priv->next_event != 0)
-			g_source_remove (self->priv->next_event);
-		self->priv->next_event = g_timeout_add (self->priv->delay, next_image_cb, self);
-	}
+	view_next_image_automatically (self);
 }
 
 
@@ -306,43 +771,19 @@ _gth_slideshow_get_transition (GthSlideshow *self)
 
 
 static void
-image_preloader_requested_ready_cb (GthImagePreloader *preloader,
-				    GError            *error,
-				    gpointer           user_data)
+clutter_projector_image_ready (GthSlideshow *self,
+			       GdkPixbuf    *pixbuf)
 {
-	GthSlideshow   *self = user_data;
-	GthImageLoader *image_loader;
-	GdkPixbuf      *pixbuf;
-	GdkPixbuf      *image;
-	ClutterActor   *texture;
-	int             pixbuf_w, pixbuf_h;
-	float           stage_w, stage_h;
-	int             pixbuf_x, pixbuf_y;
+	GdkPixbuf    *image;
+	ClutterActor *texture;
+	int           pixbuf_w, pixbuf_h;
+	float         stage_w, stage_h;
+	int           pixbuf_x, pixbuf_y;
 
-	if (error != NULL) {
-		g_clear_error (&error);
-		_gth_slideshow_load_next_image (self);
-		return;
-	}
-
-	self->priv->one_loaded = TRUE;
 	clutter_actor_get_size (self->stage, &stage_w, &stage_h);
-
 	if ((stage_w == 0) || (stage_h == 0))
 		return;
 
-	image_loader = gth_image_preloader_get_loader (self->priv->preloader, (GthFileData *) self->priv->current->data);
-	if (image_loader == NULL) {
-		_gth_slideshow_load_next_image (self);
-		return;
-	}
-
-	pixbuf = gth_image_loader_get_pixbuf (image_loader);
-	if (pixbuf == NULL) {
-		_gth_slideshow_load_next_image (self);
-		return;
-	}
-
 	image = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
 				FALSE,
 				gdk_pixbuf_get_bits_per_sample (pixbuf),
@@ -393,135 +834,25 @@ image_preloader_requested_ready_cb (GthImagePreloader *preloader,
 
 
 static void
-gth_slideshow_init (GthSlideshow *self)
-{
-	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_SLIDESHOW, GthSlideshowPrivate);
-	self->priv->file_list = NULL;
-	self->priv->next_event = 0;
-	self->priv->delay = DEFAULT_DELAY;
-	self->priv->automatic = FALSE;
-	self->priv->wrap_around = FALSE;
-	self->priv->transitions = NULL;
-	self->priv->n_transitions = 0;
-	self->priv->rand = g_rand_new ();
-	self->priv->first_show = TRUE;
-	self->priv->audio_files = NULL;
-	self->priv->paused = FALSE;
-	self->priv->animating = FALSE;
-
-	self->priv->preloader = gth_image_preloader_new ();
-	g_signal_connect (self->priv->preloader,
-			  "requested_ready",
-			  G_CALLBACK (image_preloader_requested_ready_cb),
-			  self);
-}
-
-
-static void
-gth_slideshow_finalize (GObject *object)
+clutter_projector_finalize (GthSlideshow *self)
 {
-	GthSlideshow *self = GTH_SLIDESHOW (object);
-
-	if (self->priv->next_event != 0)
-		g_source_remove (self->priv->next_event);
-	if (self->priv->hide_cursor_event != 0)
-		g_source_remove (self->priv->hide_cursor_event);
-
-	_g_object_list_unref (self->priv->file_list);
-	_g_object_unref (self->priv->browser);
-	_g_object_unref (self->priv->preloader);
 	_g_object_unref (self->priv->timeline);
-	_g_object_list_unref (self->priv->transitions);
-	g_rand_free (self->priv->rand);
-	g_strfreev (self->priv->audio_files);
-
-#if HAVE_GSTREAMER
-	if (self->priv->playbin != NULL) {
-		gst_element_set_state (self->priv->playbin, GST_STATE_NULL);
-		gst_object_unref (GST_OBJECT (self->priv->playbin));
-		self->priv->playbin = NULL;
-	}
-#endif
-
-	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 
 static void
-gth_slideshow_class_init (GthSlideshowClass *klass)
+clutter_projector_hide_cursor (GthSlideshow *self)
 {
-	GObjectClass *gobject_class;
-
-	parent_class = g_type_class_peek_parent (klass);
-	g_type_class_add_private (klass, sizeof (GthSlideshowPrivate));
-
-	gobject_class = G_OBJECT_CLASS (klass);
-	gobject_class->finalize = gth_slideshow_finalize;
-}
-
-
-GType
-gth_slideshow_get_type (void)
-{
-	static GType type = 0;
-
-	if (! type) {
-		GTypeInfo type_info = {
-			sizeof (GthSlideshowClass),
-			NULL,
-			NULL,
-			(GClassInitFunc) gth_slideshow_class_init,
-			NULL,
-			NULL,
-			sizeof (GthSlideshow),
-			0,
-			(GInstanceInitFunc) gth_slideshow_init
-		};
-
-		type = g_type_register_static (GTK_TYPE_WINDOW,
-					       "GthSlideshow",
-					       &type_info,
-					       0);
-	}
-
-	return type;
-}
-
-
-static gboolean
-hide_cursor_cb (gpointer data)
-{
-	GthSlideshow *self = data;
-
-	g_source_remove (self->priv->hide_cursor_event);
-	self->priv->hide_cursor_event = 0;
-
 	clutter_stage_hide_cursor (CLUTTER_STAGE (self->stage));
-
-	return FALSE;
 }
 
 
 static void
-_gth_slideshow_toggle_pause (GthSlideshow *self)
+clutter_projector_paused (GthSlideshow *self)
 {
-	self->priv->paused = ! self->priv->paused;
-	if (self->priv->paused) {
-		if (self->priv->animating) {
-			clutter_timeline_pause (self->priv->timeline);
-			_gth_slideshow_animation_completed (self);
-		}
-#if HAVE_GSTREAMER
-		if (self->priv->playbin != NULL)
-			gst_element_set_state (self->priv->playbin, GST_STATE_PAUSED);
-#endif
-	}
-	else { /* resume */
-		_gth_slideshow_load_next_image (self);
-#if HAVE_GSTREAMER
-		if (self->priv->playbin != NULL)
-			gst_element_set_state (self->priv->playbin, GST_STATE_PLAYING);
-#endif
+	if (self->priv->animating) {
+		clutter_timeline_pause (self->priv->timeline);
+		_gth_slideshow_animation_completed (self);
 	}
 }
 
@@ -573,61 +904,6 @@ stage_input_cb (ClutterStage *stage,
 }
 
 
-#if HAVE_GSTREAMER
-static void
-bus_message_cb (GstBus     *bus,
-                GstMessage *message,
-                gpointer    user_data)
-{
-	GthSlideshow *self = user_data;
-
-	if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS) {
-		self->priv->current_audio_file++;
-		if ((self->priv->audio_files[self->priv->current_audio_file] == NULL)
-		    && self->priv->audio_loop)
-		{
-			self->priv->current_audio_file = 0;
-		}
-		gst_element_set_state (self->priv->playbin, GST_STATE_NULL);
-		g_object_set (G_OBJECT (self->priv->playbin), "uri", self->priv->audio_files[self->priv->current_audio_file], NULL);
-		gst_element_set_state (self->priv->playbin, GST_STATE_PLAYING);
-	}
-}
-#endif
-
-
-static void
-gth_slideshow_show_cb (GtkWidget    *widget,
-		       GthSlideshow *self)
-{
-	if (! self->priv->first_show)
-		return;
-
-#if HAVE_GSTREAMER
-	if (gstreamer_init ()) {
-		if ((self->priv->audio_files != NULL) && (self->priv->audio_files[0] != NULL)) {
-			self->priv->current_audio_file = 0;
-			if (self->priv->playbin == NULL) {
-				GstBus *bus;
-
-				self->priv->playbin = gst_element_factory_make ("playbin", "playbin");
-				bus = gst_pipeline_get_bus (GST_PIPELINE (self->priv->playbin));
-				gst_bus_add_signal_watch (bus);
-				g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), self);
-			}
-			else
-				gst_element_set_state (self->priv->playbin, GST_STATE_NULL);
-			g_object_set (G_OBJECT (self->priv->playbin), "uri", self->priv->audio_files[self->priv->current_audio_file], NULL);
-			gst_element_set_state (self->priv->playbin, GST_STATE_PLAYING);
-		}
-	}
-#endif
-
-	_gth_slideshow_load_current_image (self);
-	self->priv->first_show = FALSE;
-}
-
-
 static void
 gth_slideshow_size_allocate_cb (GtkWidget     *widget,
 				GtkAllocation *allocation,
@@ -698,18 +974,11 @@ gth_slideshow_size_allocate_cb (GtkWidget     *widget,
 
 
 static void
-_gth_slideshow_construct (GthSlideshow *self,
-			  GthBrowser   *browser,
-			  GList        *file_list)
+clutter_projector_construct (GthSlideshow *self)
 {
 	GtkWidget    *embed;
 	ClutterColor  background_color = { 0x0, 0x0, 0x0, 0xff };
 
-	self->priv->browser = _g_object_ref (browser);
-	self->priv->file_list = _g_object_list_ref (file_list);
-	self->priv->current = self->priv->file_list;
-	self->priv->one_loaded = FALSE;
-
 	embed = gtk_clutter_embed_new ();
 	self->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (embed));
 	clutter_stage_hide_cursor (CLUTTER_STAGE (self->stage));
@@ -737,62 +1006,19 @@ _gth_slideshow_construct (GthSlideshow *self,
 	g_signal_connect (self->priv->timeline, "new-frame", G_CALLBACK (animation_frame_cb), self);
 	g_signal_connect (self->priv->timeline, "started", G_CALLBACK (animation_started_cb), self);
 
-	g_signal_connect (self, "show", G_CALLBACK (gth_slideshow_show_cb), self);
 	g_signal_connect (self, "size-allocate", G_CALLBACK (gth_slideshow_size_allocate_cb), self);
 }
 
 
-GtkWidget *
-gth_slideshow_new (GthBrowser *browser,
-		   GList      *file_list /* GthFileData */)
-{
-	GthSlideshow *window;
-
-	window = (GthSlideshow *) g_object_new (GTH_TYPE_SLIDESHOW, NULL);
-	_gth_slideshow_construct (window, browser, file_list);
-
-	return (GtkWidget*) window;
-}
-
-
-void
-gth_slideshow_set_delay (GthSlideshow *self,
-			 guint         msecs)
-{
-	self->priv->delay = msecs;
-}
-
-
-void
-gth_slideshow_set_automatic (GthSlideshow *self,
-			     gboolean      automatic)
-{
-	self->priv->automatic = automatic;
-}
-
-
-void
-gth_slideshow_set_wrap_around (GthSlideshow *self,
-			       gboolean      wrap_around)
-{
-	self->priv->wrap_around = wrap_around;
-}
-
-
-void
-gth_slideshow_set_transitions (GthSlideshow *self,
-			       GList        *transitions)
-{
-	_g_object_list_unref (self->priv->transitions);
-	self->priv->transitions = _g_object_list_ref (transitions);
-	self->priv->n_transitions = g_list_length (self->priv->transitions);
-}
+GthProjector clutter_projector = {
+	clutter_projector_construct,
+	clutter_projector_paused,
+	clutter_projector_hide_cursor,
+	clutter_projector_finalize,
+	clutter_projector_image_ready,
+	clutter_projector_load_prev_image,
+	clutter_projector_load_next_image
+};
 
 
-void
-gth_slideshow_set_playlist (GthSlideshow  *self,
-			    char         **files)
-{
-	self->priv->audio_files = g_strdupv (files);
-	self->priv->audio_loop = TRUE;
-}
+#endif /* HAVE_CLUTTER*/
diff --git a/extensions/slideshow/gth-slideshow.h b/extensions/slideshow/gth-slideshow.h
index 85f6c06..de5cba3 100644
--- a/extensions/slideshow/gth-slideshow.h
+++ b/extensions/slideshow/gth-slideshow.h
@@ -24,8 +24,10 @@
 #define GTH_SLIDESHOW_H
 
 #include <gthumb.h>
+#ifdef HAVE_CLUTTER
 #include <clutter/clutter.h>
 #include <clutter-gtk/clutter-gtk.h>
+#endif /* HAVE_CLUTTER */
 
 G_BEGIN_DECLS
 
@@ -43,12 +45,14 @@ typedef struct _GthSlideshowPrivate  GthSlideshowPrivate;
 struct _GthSlideshow
 {
 	GtkWindow __parent;
+#ifdef HAVE_CLUTTER
 	ClutterActor        *stage;
 	ClutterActor        *current_image;
 	ClutterActor        *next_image;
 	ClutterGeometry      current_geometry;
 	ClutterGeometry      next_geometry;
 	gboolean             first_frame;
+#endif /* HAVE_CLUTTER */
 	GthSlideshowPrivate *priv;
 };
 
@@ -57,19 +61,36 @@ struct _GthSlideshowClass
 	GtkWindowClass __parent_class;
 };
 
+typedef struct {
+	void (* construct)       (GthSlideshow *self);
+	void (* paused)          (GthSlideshow *self);
+	void (* hide_cursor)     (GthSlideshow *self);
+	void (* finalize)        (GthSlideshow *self);
+	void (* image_ready)     (GthSlideshow *self,
+			          GdkPixbuf    *pixbuf);
+	void (* load_prev_image) (GthSlideshow *self);
+	void (* load_next_image) (GthSlideshow *self);
+} GthProjector;
+
+extern GthProjector default_projector;
+#ifdef HAVE_CLUTTER
+extern GthProjector clutter_projector;
+#endif /* HAVE_CLUTTER */
+
 GType            gth_slideshow_get_type        (void);
-GtkWidget *      gth_slideshow_new             (GthBrowser       *browser,
-					        GList            *file_list /* GthFileData */);
-void             gth_slideshow_set_delay       (GthSlideshow     *self,
-					        guint             msecs);
-void             gth_slideshow_set_automatic   (GthSlideshow     *self,
-					        gboolean          automatic);
-void             gth_slideshow_set_wrap_around (GthSlideshow     *self,
-					        gboolean          wrap_around);
-void             gth_slideshow_set_transitions (GthSlideshow     *self,
-					        GList            *transitions);
-void             gth_slideshow_set_playlist    (GthSlideshow     *self,
-						char            **files);
+GtkWidget *      gth_slideshow_new             (GthProjector  *projector,
+						GthBrowser    *browser,
+					        GList         *file_list /* GthFileData */);
+void             gth_slideshow_set_delay       (GthSlideshow  *self,
+					        guint          msecs);
+void             gth_slideshow_set_automatic   (GthSlideshow  *self,
+					        gboolean       automatic);
+void             gth_slideshow_set_wrap_around (GthSlideshow  *self,
+					        gboolean       wrap_around);
+void             gth_slideshow_set_transitions (GthSlideshow  *self,
+					        GList         *transitions);
+void             gth_slideshow_set_playlist    (GthSlideshow  *self,
+						char         **files);
 
 G_END_DECLS
 
diff --git a/extensions/slideshow/gth-transition.c b/extensions/slideshow/gth-transition.c
index ff1d55e..724fb18 100644
--- a/extensions/slideshow/gth-transition.c
+++ b/extensions/slideshow/gth-transition.c
@@ -34,9 +34,9 @@ enum {
 
 
 struct _GthTransitionPrivate {
-	char         *id;
-	char         *display_name;
-	FrameFunc     frame_func;
+	char      *id;
+	char      *display_name;
+	FrameFunc  frame_func;
 };
 
 
diff --git a/extensions/slideshow/gth-transition.h b/extensions/slideshow/gth-transition.h
index 6920c79..133571f 100644
--- a/extensions/slideshow/gth-transition.h
+++ b/extensions/slideshow/gth-transition.h
@@ -24,8 +24,6 @@
 #define GTH_TRANSITION_H
 
 #include <glib-object.h>
-#include <clutter/clutter.h>
-#include <clutter-gtk/clutter-gtk.h>
 #include "gth-slideshow.h"
 
 G_BEGIN_DECLS
@@ -47,13 +45,13 @@ typedef void (*FrameFunc) (GthSlideshow *slideshow, int msecs);
 
 struct _GthTransition
 {
-	GtkWindow __parent;
+	GObject __parent;
 	GthTransitionPrivate *priv;
 };
 
 struct _GthTransitionClass
 {
-	GtkWindowClass __parent_class;
+	GObjectClass __parent_class;
 };
 
 GType             gth_transition_get_type         (void);
diff --git a/extensions/slideshow/main.c b/extensions/slideshow/main.c
index d7ef3a3..48e15a6 100644
--- a/extensions/slideshow/main.c
+++ b/extensions/slideshow/main.c
@@ -29,6 +29,8 @@
 #include "preferences.h"
 
 
+#ifdef HAVE_CLUTTER
+
 #define VALUE_AT_MSECS(v, t)(((double) (v) * ((double) (t) / GTH_TRANSITION_DURATION)))
 
 
@@ -264,12 +266,13 @@ cube_from_bottom_transition (GthSlideshow *self,
 }
 
 
+#endif /* HAVE_CLUTTER */
+
+
 G_MODULE_EXPORT void
 gthumb_extension_activate (void)
 {
-	if (ClutterInitResult != CLUTTER_INIT_SUCCESS)
-		return;
-
+#ifdef HAVE_CLUTTER
 	gth_main_register_object (GTH_TYPE_TRANSITION,
 				  "none",
 				  GTH_TYPE_TRANSITION,
@@ -324,6 +327,7 @@ gthumb_extension_activate (void)
 				  "display-name", _("Cube from bottom"),
 				  "frame-func", cube_from_bottom_transition,
 				  NULL);
+#endif /* HAVE_CLUTTER */
 
 	gth_hook_add_callback ("slideshow", 10, G_CALLBACK (ss__slideshow_cb), NULL);
 	gth_hook_add_callback ("gth-browser-construct", 10, G_CALLBACK (ss__gth_browser_construct_cb), NULL);
diff --git a/extensions/slideshow/preferences.c b/extensions/slideshow/preferences.c
index 24db38e..b33ff7d 100644
--- a/extensions/slideshow/preferences.c
+++ b/extensions/slideshow/preferences.c
@@ -102,6 +102,10 @@ ss__dlg_preferences_construct_cb (GtkWidget  *dialog,
 	gtk_widget_show (data->preferences_page);
 	g_free (current_transition);
 
+#ifndef HAVE_CLUTTER
+	gtk_widget_hide (gth_slideshow_preferences_get_widget (GTH_SLIDESHOW_PREFERENCES (data->preferences_page), "transition_box"));
+#endif /* ! HAVE_CLUTTER */
+
 	g_signal_connect (gth_slideshow_preferences_get_widget (GTH_SLIDESHOW_PREFERENCES (data->preferences_page), "transition_combobox"),
 			  "changed",
 			  G_CALLBACK (transition_combobox_changed_cb),



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