changeset 2074:b56062760fc2

implemented clutter-based renderer
author Vladimir Nadvornik <nadvornik@suse.cz>
date Sat, 11 Aug 2012 23:46:42 +0200
parents d6e8bbeea325
children ccd29555c02b
files src/Makefile.am src/pixbuf-renderer.c src/pixbuf-renderer.h src/renderer-clutter.c src/renderer-clutter.h src/renderer-tiles.c
diffstat 6 files changed, 548 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Thu Aug 16 23:33:24 2012 +0200
+++ b/src/Makefile.am	Sat Aug 11 23:46:42 2012 +0200
@@ -209,6 +209,8 @@
 	pixbuf-renderer.h	\
 	renderer-tiles.c	\
 	renderer-tiles.h	\
+	renderer-clutter.c	\
+	renderer-clutter.h	\
 	pixbuf_util.c	\
 	pixbuf_util.h	\
 	preferences.c	\
--- a/src/pixbuf-renderer.c	Thu Aug 16 23:33:24 2012 +0200
+++ b/src/pixbuf-renderer.c	Sat Aug 11 23:46:42 2012 +0200
@@ -18,12 +18,14 @@
 #include "main.h"
 #include "pixbuf-renderer.h"
 #include "renderer-tiles.h"
+#include "renderer-clutter.h"
 
 #include "intl.h"
 #include "layout.h"
 
 #include <gtk/gtk.h>
 
+#define RENDERER_NEW(pr) renderer_clutter_new(pr)
 
 /* comment this out if not using this from within Geeqie
  * defining GQ_BUILD does these things:
@@ -426,7 +428,7 @@
 	
 	pr->stereo_mode = PR_STEREO_NONE;
 	
-	pr->renderer = (void *)renderer_tiles_new(pr);
+	pr->renderer = RENDERER_NEW(pr);
 	
 	pr->renderer2 = NULL;
 
@@ -942,12 +944,6 @@
  *-------------------------------------------------------------------
  */
 
-static void pr_border_clear(PixbufRenderer *pr)
-{
-	pr->renderer->border_clear(pr->renderer);
-	if (pr->renderer2) pr->renderer2->border_clear(pr->renderer2);
-}
-
 void pixbuf_renderer_set_color(PixbufRenderer *pr, GdkColor *color)
 {
 	GtkStyle *style;
@@ -973,21 +969,8 @@
 
 	gtk_widget_set_style(widget, style);
 
-#if GTK_CHECK_VERSION(2,20,0)
-	if (gtk_widget_get_visible(widget)) pr_border_clear(pr);
-#else
-	if (GTK_WIDGET_VISIBLE(widget)) pr_border_clear(pr);
-#endif
-}
-
-static void pr_redraw(PixbufRenderer *pr, gboolean new_data)
-{
-	pr->renderer->queue_clear(pr->renderer);
-	pr->renderer->redraw(pr->renderer, 0, 0, pr->width, pr->height, TRUE, TILE_RENDER_ALL, new_data, FALSE);
-	if (pr->renderer2) {
-		pr->renderer2->queue_clear(pr->renderer2);
-		pr->renderer2->redraw(pr->renderer2, 0, 0, pr->width, pr->height, TRUE, TILE_RENDER_ALL, new_data, FALSE);
-	}
+	pr->renderer->update_sizes(pr->renderer);
+	if (pr->renderer2) pr->renderer2->update_sizes(pr->renderer2);
 }
 
 /*
@@ -1257,7 +1240,6 @@
 	pr->func_tile_data = user_data;
 
 	pr_zoom_sync(pr, zoom, PR_ZOOM_FORCE | PR_ZOOM_NEW, 0, 0);
-	pr_redraw(pr, TRUE);
 }
 
 void pixbuf_renderer_set_tiles_size(PixbufRenderer *pr, gint width, gint height)
@@ -1766,9 +1748,9 @@
 
 	if (invalidate || invalid)
 		{
-		pr->renderer->invalidate_all(pr->renderer);
-		if (pr->renderer2) pr->renderer2->invalidate_all(pr->renderer2);
-		if (!lazy) pr_redraw(pr, TRUE);
+		pr->renderer->update_zoom(pr->renderer, lazy);
+		if (pr->renderer2) pr->renderer2->update_zoom(pr->renderer2, lazy);
+//		if (!lazy) pr_redraw(pr, TRUE);
 		}
 	if (redrawn) *redrawn = (invalidate || invalid);
 
@@ -1854,12 +1836,7 @@
 
 	pr_scroll_clamp(pr);
 
-	/* If the window was not sized, redraw the image - we know there will be no size/expose signal.
-	 * But even if a size is claimed, there is no guarantee that the window manager will allow it,
-	 * so redraw the window anyway :/
-	 */
-	if (sized || clamped) pr_border_clear(pr);
-	
+#if 0	
 	if (lazy)
 		{
 		pr->renderer->queue_clear(pr->renderer);
@@ -1869,6 +1846,9 @@
 		{
 		pr_redraw(pr, redrawn);
 		}
+#endif
+	pr->renderer->update_zoom(pr->renderer, lazy);
+	if (pr->renderer2) pr->renderer2->update_zoom(pr->renderer2, lazy);
 
 	pr_scroll_notify_signal(pr);
 	pr_zoom_signal(pr);
@@ -1954,8 +1934,6 @@
 			}
 		}
 
-	pr_border_clear(pr);
-
 	pr_scroll_notify_signal(pr);
 	if (zoom_changed) pr_zoom_signal(pr);
 	pr_update_signal(pr);
@@ -2482,6 +2460,8 @@
 		}
 
 	pr_pixbuf_size_sync(pr);
+	pr->renderer->update_pixbuf(pr->renderer, flags & PR_ZOOM_LAZY);
+	if (pr->renderer2) pr->renderer2->update_pixbuf(pr->renderer2, flags & PR_ZOOM_LAZY);
 	pr_zoom_sync(pr, zoom, flags | PR_ZOOM_FORCE | PR_ZOOM_NEW, 0, 0);
 }
 
@@ -2523,7 +2503,15 @@
 	pr->orientation = orientation;
 
 	pr_pixbuf_size_sync(pr);
+	if (0)
+		{
+		pr->renderer->update_pixbuf(pr->renderer, FALSE);
+		if (pr->renderer2) pr->renderer2->update_pixbuf(pr->renderer2, FALSE);
+		}
 	pr_zoom_sync(pr, pr->zoom, PR_ZOOM_FORCE, 0, 0);
+
+	pr->renderer->update_sizes(pr->renderer);
+	if (pr->renderer2) pr->renderer2->update_sizes(pr->renderer2);
 }
 
 gint pixbuf_renderer_get_orientation(PixbufRenderer *pr)
@@ -2544,6 +2532,8 @@
 		pr_stereo_temp_disable(pr, disable);
 		}
 	pr_pixbuf_size_sync(pr);
+	pr->renderer->update_pixbuf(pr->renderer, FALSE);
+	if (pr->renderer2) pr->renderer2->update_pixbuf(pr->renderer2, FALSE);
 	pr_zoom_sync(pr, pr->zoom, PR_ZOOM_FORCE, 0, 0);
 }
 
@@ -2609,7 +2599,6 @@
 		source->source_tiles = NULL;
 
 		pr_zoom_sync(pr, source->zoom, PR_ZOOM_FORCE | PR_ZOOM_NEW, 0, 0);
-		pr_redraw(pr, TRUE);
 		}
 	else
 		{
@@ -2693,13 +2682,13 @@
 
 static void pr_stereo_set(PixbufRenderer *pr)
 {
-	if (!pr->renderer) pr->renderer = (void *)renderer_tiles_new(pr);
+	if (!pr->renderer) pr->renderer = RENDERER_NEW(pr);
 	
 	pr->renderer->stereo_set(pr->renderer, pr->stereo_mode & ~PR_STEREO_MIRROR_RIGHT & ~PR_STEREO_FLIP_RIGHT);
 	
 	if (pr->stereo_mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED))
 		{
-		if (!pr->renderer2) pr->renderer2 = (void *)renderer_tiles_new(pr);
+		if (!pr->renderer2) pr->renderer2 = RENDERER_NEW(pr);
 		pr->renderer2->stereo_set(pr->renderer2, (pr->stereo_mode & ~PR_STEREO_MIRROR_LEFT & ~PR_STEREO_FLIP_LEFT) | PR_STEREO_RIGHT);
 		}
 	else
@@ -2757,7 +2746,7 @@
 	pr->stereo_temp_disable = disable;
 	if (disable)
 		{
-		if (!pr->renderer) pr->renderer = (void *)renderer_tiles_new(pr);
+		if (!pr->renderer) pr->renderer = RENDERER_NEW(pr);
 		pr->renderer->stereo_set(pr->renderer, PR_STEREO_NONE);
 		if (pr->renderer2) pr->renderer2->free(pr->renderer2);
 		pr->renderer2 = NULL;
--- a/src/pixbuf-renderer.h	Thu Aug 16 23:33:24 2012 +0200
+++ b/src/pixbuf-renderer.h	Sat Aug 11 23:46:42 2012 +0200
@@ -74,20 +74,19 @@
 {
 	void (*redraw)(void *renderer, gint x, gint y, gint w, gint h,
                      gint clamp, ImageRenderType render, gboolean new_data, gboolean only_existing);
-        void (*area_changed)(void *renderer, gint src_x, gint src_y, gint src_w, gint src_h);
-	void (*queue_clear)(void *renderer);
-	void (*border_clear)(void *renderer);
-	void (*invalidate_all)(void *renderer);
+        void (*area_changed)(void *renderer, gint src_x, gint src_y, gint src_w, gint src_h); /* pixbuf area changed */
 	void (*invalidate_region)(void *renderer, gint x, gint y, gint w, gint h);
-	void (*scroll)(void *renderer, gint x_off, gint y_off);
-	void (*update_sizes)(void *renderer);
+	void (*scroll)(void *renderer, gint x_off, gint y_off); /* scroll */
+	void (*update_sizes)(void *renderer); /* window / wiewport / borders / border color has changed */
+	void (*update_pixbuf)(void *renderer, gboolean lazy); /* pixbuf has changed */
+	void (*update_zoom)(void *renderer, gboolean lazy); /* zoom has changed */
 
 	gint (*overlay_add)(void *renderer, GdkPixbuf *pixbuf, gint x, gint y, OverlayRendererFlags flags);
 	void (*overlay_set)(void *renderer, gint id, GdkPixbuf *pixbuf, gint x, gint y);
 	gboolean (*overlay_get)(void *renderer, gint id, GdkPixbuf **pixbuf, gint *x, gint *y);
 	void (*overlay_draw)(void *renderer, gint x, gint y, gint w, gint h);
 
-	void (*stereo_set)(void *renderer, gint stereo_mode);
+	void (*stereo_set)(void *renderer, gint stereo_mode); /* set stereo mode */
 
 	void (*free)(void *renderer);
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/renderer-clutter.c	Sat Aug 11 23:46:42 2012 +0200
@@ -0,0 +1,480 @@
+/*
+ * Geeqie
+ * (C) 2006 John Ellis
+ * Copyright (C) 2008 - 2012 The Geeqie Team
+ *
+ * Author: John Ellis
+ * Author: Vladimir Nadvornik
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "main.h"
+#include "pixbuf-renderer.h"
+#include "renderer-clutter.h"
+
+#include "intl.h"
+#include "layout.h"
+
+#include <gtk/gtk.h>
+#include <clutter/clutter.h>
+
+#include <clutter-gtk/clutter-gtk.h>
+
+
+
+#define GQ_BUILD 1
+
+#ifdef GQ_BUILD
+#include "main.h"
+#include "pixbuf_util.h"
+#include "exif.h"
+#else
+typedef enum {
+	EXIF_ORIENTATION_UNKNOWN	= 0,
+	EXIF_ORIENTATION_TOP_LEFT	= 1,
+	EXIF_ORIENTATION_TOP_RIGHT	= 2,
+	EXIF_ORIENTATION_BOTTOM_RIGHT	= 3,
+	EXIF_ORIENTATION_BOTTOM_LEFT	= 4,
+	EXIF_ORIENTATION_LEFT_TOP	= 5,
+	EXIF_ORIENTATION_RIGHT_TOP	= 6,
+	EXIF_ORIENTATION_RIGHT_BOTTOM	= 7,
+	EXIF_ORIENTATION_LEFT_BOTTOM	= 8
+} ExifOrientationType;
+#endif
+
+
+typedef struct _OverlayData OverlayData;
+struct _OverlayData
+{
+	gint id;
+
+	GdkPixbuf *pixbuf;
+	GdkWindow *window;
+
+	gint x;
+	gint y;
+
+	OverlayRendererFlags flags;
+};
+
+typedef struct _RendererClutter RendererClutter;
+
+struct _RendererClutter
+{
+	RendererFuncs f;
+	PixbufRenderer *pr;
+
+	
+	gint stereo_mode;
+	gint stereo_off_x;
+	gint stereo_off_y;
+	
+	gint x_scroll;  /* allow local adjustment and mirroring */
+	gint y_scroll;
+	
+	GtkWidget *widget; /* widget and stage may be shared with other renderers */
+	ClutterActor *stage;
+	ClutterActor *texture;
+	ClutterActor *group;
+};
+
+static void rc_sync_scroll(RendererClutter *rc)
+{
+	PixbufRenderer *pr = rc->pr;
+	
+	rc->x_scroll = (rc->stereo_mode & PR_STEREO_MIRROR) ? 
+	               pr->width - pr->vis_width - pr->x_scroll 
+	               : pr->x_scroll;
+	
+	rc->y_scroll = (rc->stereo_mode & PR_STEREO_FLIP) ? 
+	               pr->height - pr->vis_height - pr->y_scroll 
+	               : pr->y_scroll;
+}
+
+static gint rc_get_orientation(RendererClutter *rc)
+{
+	PixbufRenderer *pr = rc->pr;
+
+	gint orientation = pr->orientation;
+	static const gint mirror[]       = {1,   2, 1, 4, 3, 6, 5, 8, 7};
+	static const gint flip[]         = {1,   4, 3, 2, 1, 8, 7, 6, 5};
+
+	if (rc->stereo_mode & PR_STEREO_MIRROR) orientation = mirror[orientation];
+	if (rc->stereo_mode & PR_STEREO_FLIP) orientation = flip[orientation];
+        return orientation;
+}
+
+
+static void rc_sync_actor(RendererClutter *rc)
+{
+	PixbufRenderer *pr = rc->pr;
+	gint anchor_x = 0;
+	gint anchor_y = 0;
+	
+	rc_sync_scroll(rc);
+	
+	clutter_actor_set_anchor_point(CLUTTER_ACTOR(rc->texture), 0, 0);
+
+	printf("scale %d %d\n", rc->pr->width, rc->pr->height);
+	printf("pos   %d %d        %d %d\n", rc->pr->x_offset, rc->pr->y_offset, rc->x_scroll, rc->y_scroll);
+	
+	switch (rc_get_orientation(rc))
+		{
+		case EXIF_ORIENTATION_TOP_LEFT:
+			/* normal  */
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						0, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						0, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
+			anchor_x = 0;
+			anchor_y = 0;
+			break;
+		case EXIF_ORIENTATION_TOP_RIGHT:
+			/* mirrored */
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						0, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						180, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
+			anchor_x = pr->width;
+			anchor_y = 0;
+			break;
+		case EXIF_ORIENTATION_BOTTOM_RIGHT:
+			/* upside down */
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						180, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						0, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
+			anchor_x = pr->width;
+			anchor_y = pr->height;
+			break;
+		case EXIF_ORIENTATION_BOTTOM_LEFT:
+			/* flipped */
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						180, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						180, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
+			anchor_x = 0;
+			anchor_y = pr->height;
+			break;
+		case EXIF_ORIENTATION_LEFT_TOP:
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						-90, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						180, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
+			anchor_x = 0;
+			anchor_y = 0;
+			break;
+		case EXIF_ORIENTATION_RIGHT_TOP:
+			/* rotated -90 (270) */
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						-90, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						0, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
+			anchor_x = 0;
+			anchor_y = pr->height;
+			break;
+		case EXIF_ORIENTATION_RIGHT_BOTTOM:
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						90, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						180, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
+			anchor_x = pr->width;
+			anchor_y = pr->height;
+			break;
+		case EXIF_ORIENTATION_LEFT_BOTTOM:
+			/* rotated 90 */
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Z_AXIS,
+						90, 0, 0, 0);
+			clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
+						CLUTTER_Y_AXIS,
+						0, 0, 0, 0);
+			clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
+			anchor_x = pr->width;
+			anchor_y = 0;
+			break;
+		default:
+			/* The other values are out of range */
+			break;
+		}
+	
+	clutter_actor_set_position(CLUTTER_ACTOR(rc->texture), 
+				pr->x_offset - rc->x_scroll + anchor_x, 
+				pr->y_offset - rc->y_scroll + anchor_y);
+
+}
+
+
+static void renderer_area_changed(void *renderer, gint src_x, gint src_y, gint src_w, gint src_h)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+	PixbufRenderer *pr = rc->pr;
+	
+	
+	
+	printf("renderer_area_changed %d %d %d %d\n", src_x, src_y, src_w, src_h);
+	if (pr->pixbuf)
+		{
+		CoglHandle texture = clutter_texture_get_cogl_texture(CLUTTER_TEXTURE(rc->texture));
+		
+		cogl_texture_set_region(texture,
+					src_x,
+					src_y,
+					src_x,
+					src_y,
+					src_w,
+					src_h,
+					src_w,
+					src_h,
+					gdk_pixbuf_get_has_alpha(pr->pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
+					gdk_pixbuf_get_rowstride(pr->pixbuf),
+					gdk_pixbuf_get_pixels(pr->pixbuf));
+		clutter_actor_queue_redraw(CLUTTER_ACTOR(rc->texture));
+		}
+
+}
+
+static void renderer_redraw(void *renderer, gint x, gint y, gint w, gint h,
+                     gint clamp, ImageRenderType render, gboolean new_data, gboolean only_existing)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+	PixbufRenderer *pr = rc->pr;
+}
+
+static void renderer_update_pixbuf(void *renderer, gboolean lazy)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+	PixbufRenderer *pr = rc->pr;
+	
+	if (pr->pixbuf)
+		{
+		printf("renderer_update_pixbuf\n");
+		
+		/* FIXME use CoglMaterial with multiple textures for background, color management, anaglyph, ... */
+		CoglHandle texture = cogl_texture_new_with_size(gdk_pixbuf_get_width(pr->pixbuf),
+								gdk_pixbuf_get_height(pr->pixbuf),
+								COGL_TEXTURE_NONE,
+								gdk_pixbuf_get_has_alpha(pr->pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888);
+
+		if (texture != COGL_INVALID_HANDLE)
+			{
+			clutter_texture_set_cogl_texture(CLUTTER_TEXTURE(rc->texture), texture);
+			cogl_handle_unref(texture);
+			}
+		if (!lazy)
+			{
+			renderer_area_changed(renderer, 0, 0, gdk_pixbuf_get_width(pr->pixbuf), gdk_pixbuf_get_height(pr->pixbuf));
+			}
+		}
+
+
+	printf("renderer_update_pixbuf\n");
+	rc_sync_actor(rc);
+}
+
+
+
+static void renderer_update_zoom(void *renderer, gboolean lazy)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+	PixbufRenderer *pr = rc->pr;
+
+	printf("renderer_update_zoom\n");
+	rc_sync_actor(rc);
+}
+
+static void renderer_invalidate_region(void *renderer, gint x, gint y, gint w, gint h)
+{
+}
+
+static void renderer_overlay_draw(void *renderer, gint x, gint y, gint w, gint h)
+{
+}
+
+static void renderer_overlay_add(void *renderer, gint x, gint y, gint w, gint h)
+{
+}
+
+static void renderer_overlay_set(void *renderer, gint x, gint y, gint w, gint h)
+{
+}
+
+static void renderer_overlay_get(void *renderer, gint x, gint y, gint w, gint h)
+{
+}
+
+static void renderer_update_sizes(void *renderer)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+	ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; 
+
+	rc->stereo_off_x = 0;
+	rc->stereo_off_y = 0;
+	
+	if (rc->stereo_mode & PR_STEREO_RIGHT) 
+		{
+		if (rc->stereo_mode & PR_STEREO_HORIZ) 
+			{
+			rc->stereo_off_x = rc->pr->viewport_width;
+			}
+		else if (rc->stereo_mode & PR_STEREO_VERT) 
+			{
+			rc->stereo_off_y = rc->pr->viewport_height;
+			}
+		else if (rc->stereo_mode & PR_STEREO_FIXED) 
+			{
+			rc->stereo_off_x = rc->pr->stereo_fixed_x_right;
+			rc->stereo_off_y = rc->pr->stereo_fixed_y_right;
+			}
+		}
+	else
+		{
+		if (rc->stereo_mode & PR_STEREO_FIXED) 
+			{
+			rc->stereo_off_x = rc->pr->stereo_fixed_x_left;
+			rc->stereo_off_y = rc->pr->stereo_fixed_y_left;
+			}
+		}
+        DEBUG_1("update size: %p  %d %d   %d %d", rc, rc->stereo_off_x, rc->stereo_off_y, rc->pr->viewport_width, rc->pr->viewport_height);
+
+	printf("renderer_update_sizes  scale %d %d\n", rc->pr->width, rc->pr->height);
+
+        clutter_stage_set_color(CLUTTER_STAGE(rc->stage), &stage_color);
+
+
+	clutter_actor_set_size(rc->group, rc->pr->viewport_width, rc->pr->viewport_height);
+	clutter_actor_set_position(rc->group, rc->stereo_off_x, rc->stereo_off_y);
+	rc_sync_actor(rc);
+}
+
+static void renderer_scroll(void *renderer, gint x_off, gint y_off)
+{
+	printf("renderer_scroll\n");
+	RendererClutter *rc = (RendererClutter *)renderer;
+	PixbufRenderer *pr = rc->pr;
+
+	rc_sync_actor(rc);
+}
+
+static void renderer_stereo_set(void *renderer, gint stereo_mode)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+
+	rc->stereo_mode = stereo_mode;
+}
+
+static void renderer_free(void *renderer)
+{
+	RendererClutter *rc = (RendererClutter *)renderer;
+	GtkWidget *widget = gtk_bin_get_child(GTK_BIN(rc->pr));
+	if (widget)
+		{
+		/* widget still exists */
+		clutter_actor_destroy(rc->group);
+		if (clutter_group_get_n_children(CLUTTER_GROUP(rc->stage)) == 0)
+			{
+			printf("destroy %p\n", rc->widget);
+			/* this was the last user */
+			gtk_widget_destroy(rc->widget);
+			}
+		else
+			{
+			printf("keep %p\n", rc->widget);
+			g_object_unref(G_OBJECT(rc->widget));
+			}
+		}
+	g_free(rc);
+}
+
+RendererFuncs *renderer_clutter_new(PixbufRenderer *pr)
+{
+	RendererClutter *rc = g_new0(RendererClutter, 1);
+	
+	rc->pr = pr;
+	
+	rc->f.redraw = renderer_redraw;
+	rc->f.area_changed = renderer_area_changed;
+	rc->f.update_pixbuf = renderer_update_pixbuf;
+	rc->f.free = renderer_free;
+	rc->f.update_zoom = renderer_update_zoom;
+	rc->f.invalidate_region = renderer_invalidate_region;
+	rc->f.scroll = renderer_scroll;
+	rc->f.update_sizes = renderer_update_sizes;
+
+
+	rc->f.overlay_add = renderer_overlay_add;
+	rc->f.overlay_set = renderer_overlay_set;
+	rc->f.overlay_get = renderer_overlay_get;
+	rc->f.overlay_draw = renderer_overlay_draw;
+
+	rc->f.stereo_set = renderer_stereo_set;
+	
+	
+	rc->stereo_mode = 0;
+	rc->stereo_off_x = 0;
+	rc->stereo_off_y = 0;
+
+
+  	rc->widget = gtk_bin_get_child(GTK_BIN(rc->pr));
+  	
+  	if (rc->widget)
+  		{
+  		if (!GTK_CLUTTER_IS_EMBED(rc->widget))
+  			{
+  			g_free(rc);
+  			DEBUG_0("pixbuf renderer has a child of other type than gtk_clutter_embed");
+  			return NULL;
+  			}
+  		}
+  	else 
+  		{
+  		rc->widget = gtk_clutter_embed_new();
+		gtk_container_add(GTK_CONTAINER(rc->pr), rc->widget);
+  		}
+  		
+	gtk_event_box_set_above_child (GTK_EVENT_BOX(rc->pr), TRUE);
+        rc->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (rc->widget));
+        
+        rc->group = clutter_group_new();
+  	clutter_container_add_actor(CLUTTER_CONTAINER(rc->stage), rc->group);
+  	clutter_actor_set_clip_to_allocation(CLUTTER_ACTOR(rc->group), TRUE);
+  
+  	rc->texture = gtk_clutter_texture_new ();
+  	clutter_container_add_actor(CLUTTER_CONTAINER(rc->group), rc->texture);
+  	g_object_ref(G_OBJECT(rc->widget));
+  
+	gtk_widget_show(rc->widget);
+	return (RendererFuncs *) rc;
+}
+
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/renderer-clutter.h	Sat Aug 11 23:46:42 2012 +0200
@@ -0,0 +1,22 @@
+/*
+ * Geeqie
+ * (C) 2006 John Ellis
+ * Copyright (C) 2008 - 2012 The Geeqie Team
+ *
+ * Author: John Ellis
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+#ifndef RENDERER_CLUTTER_H
+#define RENDERER_CLUTTER_H
+
+#include <pixbuf-renderer.h>
+
+
+RendererFuncs *renderer_clutter_new(PixbufRenderer *pr);
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/renderer-tiles.c	Thu Aug 16 23:33:24 2012 +0200
+++ b/src/renderer-tiles.c	Sat Aug 11 23:46:42 2012 +0200
@@ -2052,20 +2052,21 @@
 		 clamp, render, new_data, only_existing);
 }
 
-static void renderer_queue_clear(void *renderer)
+static void renderer_update_pixbuf(void *renderer, gboolean lazy)
 {
 	rt_queue_clear((RendererTiles *)renderer);
 }
 
-static void renderer_border_clear(void *renderer)
+static void renderer_update_zoom(void *renderer, gboolean lazy)
 {
-	rt_border_clear((RendererTiles *)renderer);
-}
+	RendererTiles *rt = (RendererTiles *)renderer;
+	PixbufRenderer *pr = rt->pr;
 
-
-static void renderer_invalidate_all(void *renderer)
-{
 	rt_tile_invalidate_all((RendererTiles *)renderer);
+	if (!lazy)
+		{
+		renderer_redraw(renderer, 0, 0, pr->width, pr->height, TRUE, TILE_RENDER_ALL, TRUE, FALSE);
+		}
 }
 
 static void renderer_invalidate_region(void *renderer, gint x, gint y, gint w, gint h)
@@ -2112,6 +2113,7 @@
         DEBUG_1("update size: %p  %d %d   %d %d", rt, rt->stereo_off_x, rt->stereo_off_y, rt->pr->viewport_width, rt->pr->viewport_height);
 	rt_sync_scroll(rt);
 	rt_overlay_update_sizes(rt);
+	rt_border_clear(rt);
 }
 
 static void renderer_stereo_set(void *renderer, gint stereo_mode)
@@ -2143,10 +2145,9 @@
 	
 	rt->f.redraw = renderer_redraw;
 	rt->f.area_changed = renderer_area_changed;
-	rt->f.queue_clear = renderer_queue_clear;
-	rt->f.border_clear = renderer_border_clear;
+	rt->f.update_pixbuf = renderer_update_pixbuf;
 	rt->f.free = renderer_free;
-	rt->f.invalidate_all = renderer_invalidate_all;
+	rt->f.update_zoom = renderer_update_zoom;
 	rt->f.invalidate_region = renderer_invalidate_region;
 	rt->f.scroll = rt_scroll;
 	rt->f.update_sizes = renderer_update_sizes;