[gnome-photos] Absorb gegl-gtk
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-photos] Absorb gegl-gtk
- Date: Mon, 25 Mar 2013 15:55:02 +0000 (UTC)
commit 79844cfaa7181f3985713b4cccb7e197ecbb2f9e
Author: Debarshi Ray <debarshir gnome org>
Date: Mon Mar 25 02:41:42 2013 +0100
Absorb gegl-gtk
It appears to be unmaintained and not widely distributed. Lets carry
our own copy until the situation changes.
Like other elements of the GEGL stack, gegl-gtk is LGPLv3+.
configure.ac | 9 +-
src/Makefile.am | 50 ++++-
src/gegl-gtk-enums.h | 43 +++
src/gegl-gtk-marshal.list | 1 +
src/gegl-gtk-view-helper.c | 466 ++++++++++++++++++++++++++++++++
src/gegl-gtk-view-helper.h | 90 +++++++
src/gegl-gtk-view.c | 638 ++++++++++++++++++++++++++++++++++++++++++++
src/gegl-gtk-view.h | 79 ++++++
src/photos-preview-view.c | 2 +-
9 files changed, 1373 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 123b2c9..5e13eb1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,10 +73,13 @@ if test x$have_zlib = xno; then
AC_MSG_ERROR([No sufficient zlib library found on your system.])
fi
-PKG_CHECK_MODULES(CAIRO, [cairo])
+PKG_CHECK_MODULES(BABL, [babl])
+
+PKG_CHECK_MODULES(CAIRO, [cairo cairo-gobject])
+AC_DEFINE([HAVE_CAIRO_GOBJECT], [], [We want gegl-gtk to use the cairo-gobject code path])
+
PKG_CHECK_MODULES(EXEMPI, [exempi-2.0 >= $EXEMPI_MIN_VERSION])
PKG_CHECK_MODULES(GEGL, [gegl-0.2])
-PKG_CHECK_MODULES(GEGL_GTK, [gegl-gtk3-0.1])
PKG_CHECK_MODULES(GDK_PIXBUF, [gdk-pixbuf-2.0])
PKG_CHECK_MODULES(GLIB, [glib-2.0 >= $GLIB_MIN_VERSION])
PKG_CHECK_MODULES(GIO, [gio-2.0])
@@ -88,6 +91,8 @@ PKG_CHECK_MODULES(GOA, [goa-1.0])
AC_DEFINE([GOA_API_IS_SUBJECT_TO_CHANGE], [], [We are aware that GOA's API can change])
PKG_CHECK_MODULES(GTK, [gtk+-3.0])
+AC_DEFINE([HAVE_GTK3], [], [We want gegl-gtk to use the GTK+ 3.x code path])
+
PKG_CHECK_MODULES(GTK_UNIX_PRINT, [gtk+-unix-print-3.0])
PKG_CHECK_MODULES(LCMS, [lcms2])
PKG_CHECK_MODULES(LIBEXIF, [libexif >= $LIBEXIF_MIN_VERSION])
diff --git a/src/Makefile.am b/src/Makefile.am
index f9fd269..e0798ab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,9 @@
bin_PROGRAMS = gnome-photos
gnome_photos_built_sources = \
+ gegl-gtk-enums.c \
+ gegl-gtk-marshal.c \
+ gegl-gtk-marshal.h \
photos-about-data.c \
photos-about-data.h \
photos-enums.c \
@@ -50,6 +53,11 @@ gnome_photos_SOURCES = \
eog-uri-converter.h \
eog-util.c \
eog-util.h \
+ gegl-gtk-enums.h \
+ gegl-gtk-view.c \
+ gegl-gtk-view.h \
+ gegl-gtk-view-helper.c \
+ gegl-gtk-view-helper.h \
photos-application.c \
photos-application.h \
photos-base-manager.c \
@@ -148,6 +156,7 @@ BUILT_SOURCES = \
$(NULL)
EXTRA_DIST = \
+ gegl-gtk-marshal.list \
photos-enums.c.template \
photos-enums.h.template \
photos-generate-about \
@@ -161,11 +170,11 @@ EXTRA_DIST = \
AM_CPPFLAGS = \
-DPACKAGE_ICONS_DIR=\""${pkgdatadir}/icons"\" \
-DPACKAGE_LOCALE_DIR=\""${datadir}/locale"\" \
+ $(BABL_CFLAGS) \
$(CAIRO_CFLAGS) \
$(EXEMPI_CFLAGS) \
$(GDK_PIXBUF_CFLAGS) \
$(GEGL_CFLAGS) \
- $(GEGL_GTK_CFLAGS) \
$(GIO_CFLAGS) \
$(GLIB_CFLAGS) \
$(GNOME_DESKTOP_CFLAGS) \
@@ -182,11 +191,11 @@ AM_CPPFLAGS = \
gnome_photos_LDFLAGS =
gnome_photos_LDADD = \
+ $(BABL_LIBS) \
$(CAIRO_LIBS) \
$(EXEMPI_LIBS) \
$(GDK_PIXBUF_LIBS) \
$(GEGL_LIBS) \
- $(GEGL_GTK_LIBS) \
$(GIO_LIBS) \
$(GLIB_LIBS) \
$(GNOME_DESKTOP_LIBS) \
@@ -203,6 +212,7 @@ gnome_photos_LDADD = \
CLEANFILES = \
$(gnome_photos_built_sources) \
+ stamp-gegl-gtk-marshal.h \
stamp-photos-about-data.h \
stamp-photos-enums.h \
stamp-photos-marshalers.h \
@@ -210,10 +220,46 @@ CLEANFILES = \
xgen-ah \
xgen-etbc \
xgen-etbh \
+ xgen-gmc \
+ xgen-gmh \
xgen-tmc \
xgen-tmh \
$(NULL)
+gegl-gtk-enums.c: $(srcdir)/gegl-gtk-enums.h
+ glib-mkenums \
+ --fhead "/* This is a generated file, do not edit directly */\n\n#include \"config.h\"\n#include
<glib-object.h>\n#include \"gegl-gtk-enums.h\"" \
+ --fprod "\n/* enumerations from \"@filename \" */" \
+ --vhead "GType\n enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n
static const G Type@Value values[] = {" \
+ --vprod " { @VALUENAME@, \"@valuenick \", \"@valuenick \" }," \
+ --vtail " { 0, NULL, NULL }\n };\n etype = g_ type@_register_static (\"@EnumName \",
values);\n }\n return etype;\n}\n\n" \
+ $(srcdir)/gegl-gtk-enums.h > gegl-gtk-enums.c
+
+gegl-gtk-marshal.h: stamp-gegl-gtk-marshal.h
+ @true
+
+stamp-gegl-gtk-marshal.h: gegl-gtk-marshal.list Makefile
+ $(AM_V_GEN) ( \
+ ( glib-genmarshal \
+ --prefix=gegl_gtk_marshal \
+ --header $(srcdir)/gegl-gtk-marshal.list \
+ ) >> xgen-gmh \
+ && ( cmp -s xgen-gmh gegl-gtk-marshal.h || cp xgen-gmh gegl-gtk-marshal.h ) \
+ && rm -f xgen-gmh \
+ && echo timestamp > $(@F) \
+ )
+
+gegl-gtk-marshal.c: gegl-gtk-marshal.list gegl-gtk-marshal.h Makefile
+ $(AM_V_GEN) ( \
+ echo "#include \"gegl-gtk-marshal.h\"" > xgen-gmc \
+ && ( glib-genmarshal \
+ --prefix=gegl_gtk_marshal \
+ --body $(srcdir)/gegl-gtk-marshal.list \
+ ) >> xgen-gmc \
+ && cp xgen-gmc gegl-gtk-marshal.c \
+ && rm -f xgen-gmc \
+ )
+
photos-about-data.h: stamp-photos-about-data.h
@true
diff --git a/src/gegl-gtk-enums.h b/src/gegl-gtk-enums.h
new file mode 100644
index 0000000..ba0da5b
--- /dev/null
+++ b/src/gegl-gtk-enums.h
@@ -0,0 +1,43 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#ifndef __GEGL_GTK_ENUMS_H__
+#define __GEGL_GTK_ENUMS_H__
+
+G_BEGIN_DECLS
+
+/**
+ * GeglGtkViewAutoscale:
+ * @GEGL_GTK_VIEW_AUTOSCALE_DISABLED: Do not autoscale
+ * @GEGL_GTK_VIEW_AUTOSCALE_WIDGET: Automatically scale the widget size
+ * @GEGL_GTK_VIEW_AUTOSCALE_CONTENT: Automatically scale content to fit widget
+ *
+ * Specifies the autoscaling behavior of #GeglGtkView.
+ **/
+typedef enum {
+ GEGL_GTK_VIEW_AUTOSCALE_DISABLED = 0,
+ GEGL_GTK_VIEW_AUTOSCALE_WIDGET,
+ GEGL_GTK_VIEW_AUTOSCALE_CONTENT
+} GeglGtkViewAutoscale;
+
+GType gegl_gtk_view_autoscale_get_type(void) G_GNUC_CONST;
+#define GEGL_GTK_TYPE_VIEW_AUTOSCALE (gegl_gtk_view_autoscale_get_type())
+
+G_END_DECLS
+
+#endif /* __GEGL_GTK_ENUMS_H__ */
diff --git a/src/gegl-gtk-marshal.list b/src/gegl-gtk-marshal.list
new file mode 100644
index 0000000..73ccad0
--- /dev/null
+++ b/src/gegl-gtk-marshal.list
@@ -0,0 +1 @@
+VOID:BOXED,BOXED
diff --git a/src/gegl-gtk-view-helper.c b/src/gegl-gtk-view-helper.c
new file mode 100644
index 0000000..2042893
--- /dev/null
+++ b/src/gegl-gtk-view-helper.c
@@ -0,0 +1,466 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2003, 2004, 2006 Øyvind Kolås <pippin gimp org>
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#include "gegl-gtk-view-helper.h"
+
+#include <math.h>
+#include <babl/babl.h>
+
+
+G_DEFINE_TYPE(ViewHelper, view_helper, G_TYPE_OBJECT)
+
+
+enum {
+ SIGNAL_REDRAW_NEEDED,
+ SIGNAL_SIZE_CHANGED,
+ N_SIGNALS
+};
+
+static guint view_helper_signals[N_SIGNALS] = { 0 };
+
+
+static void
+finalize(GObject *gobject);
+void
+trigger_processing(ViewHelper *self, GeglRectangle roi);
+void
+trigger_redraw(ViewHelper *self, GeglRectangle *redraw_rect);
+
+
+static void
+view_helper_class_init(ViewHelperClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->finalize = finalize;
+
+ /* Emitted when a redraw is needed, with the area that needs redrawing. */
+ view_helper_signals[SIGNAL_REDRAW_NEEDED] = g_signal_new("redraw-needed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ GEGL_TYPE_RECTANGLE);
+
+ /* Emitted when the size of the view changes, with the new size. */
+ view_helper_signals[SIGNAL_SIZE_CHANGED] = g_signal_new("size-changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ GEGL_TYPE_RECTANGLE);
+}
+
+static void
+view_helper_init(ViewHelper *self)
+{
+ GdkRectangle invalid_gdkrect = {0, 0, -1, -1};
+
+ self->node = NULL;
+ self->x = 0;
+ self->y = 0;
+ self->scale = 1.0;
+ self->autoscale_policy = GEGL_GTK_VIEW_AUTOSCALE_CONTENT;
+ self->block = FALSE;
+
+ self->monitor_id = 0;
+ self->processor = NULL;
+ self->processing_queue = g_queue_new();
+ self->currently_processed_rect = NULL;
+
+ self->widget_allocation = invalid_gdkrect;
+}
+
+static void
+finalize(GObject *gobject)
+{
+ ViewHelper *self = VIEW_HELPER(gobject);
+
+ if (self->monitor_id) {
+ g_source_remove(self->monitor_id);
+ self->monitor_id = 0;
+ }
+
+ if (self->node)
+ g_object_unref(self->node);
+
+ if (self->processor)
+ g_object_unref(self->processor);
+
+ g_queue_free_full(self->processing_queue, g_free);
+
+ if (self->currently_processed_rect) {
+ g_free(self->currently_processed_rect);
+ }
+}
+
+/* Transform a rectangle from model to view coordinates. */
+static void
+model_rect_to_view_rect(ViewHelper *self, GeglRectangle *rect)
+{
+ GeglRectangle temp;
+
+ temp.x = self->scale * (rect->x) - self->x;
+ temp.y = self->scale * (rect->y) - self->y;
+ temp.width = ceil(self->scale * rect->width);
+ temp.height = ceil(self->scale * rect->height);
+
+ *rect = temp;
+}
+
+static void
+update_autoscale(ViewHelper *self)
+{
+ GdkRectangle viewport = self->widget_allocation;
+ GeglRectangle bbox = gegl_node_get_bounding_box(self->node);
+ model_rect_to_view_rect(self, &bbox);
+
+ if (!self->node || viewport.width < 0 || viewport.height < 0
+ || bbox.width < 0 || bbox.height < 0)
+ return;
+
+ if (self->autoscale_policy == GEGL_GTK_VIEW_AUTOSCALE_WIDGET) {
+ /* Request widget size change */
+ /* XXX: Should we reset scale/x/y here? */
+ g_signal_emit(self, view_helper_signals[SIGNAL_SIZE_CHANGED],
+ 0, &bbox, NULL);
+
+ } else if (self->autoscale_policy == GEGL_GTK_VIEW_AUTOSCALE_CONTENT) {
+ /* Calculate and set scaling factor to make the content fit inside */
+ float width_ratio = bbox.width / (float)viewport.width;
+ float height_ratio = bbox.height / (float)viewport.height;
+ float max_ratio = width_ratio >= height_ratio ? width_ratio : height_ratio;
+
+ float current_scale = view_helper_get_scale(self);
+ view_helper_set_scale(self, current_scale * (1.0 / max_ratio));
+ }
+
+}
+
+static void
+invalidated_event(GeglNode *node,
+ GeglRectangle *rect,
+ ViewHelper *self)
+{
+ trigger_processing(self, *rect);
+}
+
+static gboolean
+task_monitor(ViewHelper *self)
+{
+ if (!self->processor || !self->node) {
+ return FALSE;
+ }
+
+ // PERFORMANCE: combine all the rects added to the queue during a single
+ // iteration of the main loop somehow
+
+ if (!self->currently_processed_rect) {
+
+ if (g_queue_is_empty(self->processing_queue)) {
+ // Unregister worker
+ self->monitor_id = 0;
+ return FALSE;
+ }
+ else {
+ // Fetch next rect to process
+ self->currently_processed_rect = (GeglRectangle *)g_queue_pop_tail(self->processing_queue);
+ g_assert(self->currently_processed_rect);
+ gegl_processor_set_rectangle(self->processor, self->currently_processed_rect);
+ }
+ }
+
+ gboolean processing_done = !gegl_processor_work(self->processor, NULL);
+
+ if (processing_done) {
+ // Go to next region
+ if (self->currently_processed_rect) {
+ g_free(self->currently_processed_rect);
+ }
+ self->currently_processed_rect = NULL;
+ }
+
+ return TRUE;
+}
+
+
+/* When the GeglNode has been computed,
+ * find out if the size of the vie changed and
+ * emit the "size-changed" signal to notify view
+ * find out which area in the view was computed and emit the
+ * "redraw-needed" signal to notify it that a redraw is needed */
+static void
+computed_event(GeglNode *node,
+ GeglRectangle *rect,
+ ViewHelper *self)
+{
+ update_autoscale(self);
+
+ /* Emit redraw-needed */
+ GeglRectangle redraw_rect = *rect;
+ model_rect_to_view_rect(self, &redraw_rect);
+
+ trigger_redraw(self, &redraw_rect);
+}
+
+ViewHelper *
+view_helper_new(void)
+{
+ return VIEW_HELPER(g_object_new(VIEW_HELPER_TYPE, NULL));
+}
+
+/* Draw the view of the GeglNode to the provided cairo context,
+ * taking into account transformations et.c.
+ * @rect the bounding box of the area to draw in view coordinates
+ *
+ * For instance called by widget during the draw/expose */
+void
+view_helper_draw(ViewHelper *self, cairo_t *cr, GdkRectangle *rect)
+{
+ cairo_surface_t *surface = NULL;
+ guchar *buf = NULL;
+ GeglRectangle roi;
+
+ roi.x = self->x + rect->x;
+ roi.y = self->y + rect->y;
+ roi.width = rect->width;
+ roi.height = rect->height;
+
+ buf = g_malloc((roi.width) * (roi.height) * 4);
+
+ gegl_node_blit(self->node,
+ self->scale,
+ &roi,
+ babl_format("B'aG'aR'aA u8"),
+ (gpointer)buf,
+ GEGL_AUTO_ROWSTRIDE,
+ GEGL_BLIT_CACHE | (self->block ? 0 : GEGL_BLIT_DIRTY));
+
+ surface = cairo_image_surface_create_for_data(buf,
+ CAIRO_FORMAT_ARGB32,
+ roi.width, roi.height,
+ roi.width * 4);
+ cairo_set_source_surface(cr, surface, rect->x, rect->y);
+ cairo_paint(cr);
+
+ cairo_surface_destroy(surface);
+ g_free(buf);
+
+}
+
+void
+view_helper_set_allocation(ViewHelper *self, GdkRectangle *allocation)
+{
+ self->widget_allocation = *allocation;
+ update_autoscale(self);
+}
+
+/* Trigger processing of the GeglNode */
+void
+trigger_processing(ViewHelper *self, GeglRectangle roi)
+{
+ //GeglRectangle roi;
+
+ // PERFORMANCE: determine the area that the view widget is interested in,
+ // and calculate the intersection with the invalidated rect
+ // and only pass this value as the ROI
+ // Would then also have to follow changes in view transformation
+
+ if (!self->node)
+ return;
+
+// roi.x = self->x / self->scale;
+// roi.y = self->y / self->scale;
+
+// roi.width = ceil(self->widget_allocation.width / self->scale + 1);
+// roi.height = ceil(self->widget_allocation.height / self->scale + 1);
+
+ if (self->monitor_id == 0) {
+ self->monitor_id = g_idle_add_full(G_PRIORITY_LOW,
+ (GSourceFunc) task_monitor, self,
+ NULL);
+ }
+
+ // Add the invalidated region to the dirty
+ GeglRectangle *rect = g_new(GeglRectangle, 1);
+ rect->x = roi.x;
+ rect->y = roi.y;
+ rect->width = roi.width;
+ rect->height = roi.height;
+ g_queue_push_head(self->processing_queue, rect);
+}
+
+void
+trigger_redraw(ViewHelper *self, GeglRectangle *redraw_rect)
+{
+ if (!redraw_rect) {
+ GeglRectangle invalid_rect = {0, 0, -1, -1}; /* Indicates full redraw */
+ redraw_rect = &invalid_rect;
+ }
+
+ g_signal_emit(self, view_helper_signals[SIGNAL_REDRAW_NEEDED],
+ 0, redraw_rect, NULL);
+}
+
+void
+view_helper_set_node(ViewHelper *self, GeglNode *node)
+{
+ if (self->node == node)
+ return;
+
+ if (self->node)
+ g_object_unref(self->node);
+
+ if (node) {
+ g_object_ref(node);
+ self->node = node;
+
+ g_signal_connect_object(self->node, "computed",
+ G_CALLBACK(computed_event),
+ self, 0);
+ g_signal_connect_object(self->node, "invalidated",
+ G_CALLBACK(invalidated_event),
+ self, 0);
+
+ if (self->processor)
+ g_object_unref(self->processor);
+
+ GeglRectangle bbox = gegl_node_get_bounding_box(self->node);
+ self->processor = gegl_node_new_processor(self->node, &bbox);
+
+ update_autoscale(self);
+ trigger_processing(self, bbox);
+
+ } else
+ self->node = NULL;
+}
+
+GeglNode *
+view_helper_get_node(ViewHelper *self)
+{
+ return self->node;
+}
+
+void
+view_helper_set_scale(ViewHelper *self, float scale)
+{
+ if (self->scale == scale)
+ return;
+
+ self->scale = scale;
+ update_autoscale(self);
+ trigger_redraw(self, NULL);
+}
+
+float
+view_helper_get_scale(ViewHelper *self)
+{
+ return self->scale;
+}
+
+void
+view_helper_set_x(ViewHelper *self, float x)
+{
+ if (self->x == x)
+ return;
+
+ self->x = x;
+ update_autoscale(self);
+ trigger_redraw(self, NULL);
+}
+
+float
+view_helper_get_x(ViewHelper *self)
+{
+ return self->x;
+}
+
+void
+view_helper_set_y(ViewHelper *self, float y)
+{
+ if (self->y == y)
+ return;
+
+ self->y = y;
+ update_autoscale(self);
+ trigger_redraw(self, NULL);
+}
+
+float
+view_helper_get_y(ViewHelper *self)
+{
+ return self->y;
+}
+
+void view_helper_get_transformation(ViewHelper *self, GeglMatrix3 *matrix)
+{
+ /* XXX: Below gives the right result, but is it really the
+ * way we want transformations to work? */
+
+ /* API change in GEGL 1.7 (1.6+git):
+ * GeglMatrix3 changed from float[3][3] to
+ * struct with a float[3][3] coeff member */
+
+#if GEGL_MINOR_VERSION == 1 && GEGL_MICRO_VERSION >= 7 || GEGL_MINOR_VERSION >= 2
+ matrix->coeff [0][0] = self->scale; /* xx */
+ matrix->coeff [0][1] = 0.0; /* xy */
+ matrix->coeff [0][2] = -self->x; /* x0 */
+
+ matrix->coeff [1][0] = 0.0; /* yx */
+ matrix->coeff [1][1] = self->scale; /* yy */
+ matrix->coeff [1][2] = -self->y; /* y0 */
+
+ matrix->coeff [2][0] = 0.0;
+ matrix->coeff [2][1] = 0.0;
+ matrix->coeff [2][2] = 1.0;
+#else
+ (*matrix) [0][0] = self->scale;
+ (*matrix) [0][1] = 0.0;
+ (*matrix) [0][2] = -self->x;
+
+ (*matrix) [1][0] = 0.0;
+ (*matrix) [1][1] = self->scale;
+ (*matrix) [1][2] = -self->y;
+
+ (*matrix) [2][0] = 0.0;
+ (*matrix) [2][1] = 0.0;
+ (*matrix) [2][2] = 1.0;
+#endif
+
+}
+
+void
+view_helper_set_autoscale_policy(ViewHelper *self, GeglGtkViewAutoscale autoscale)
+{
+ if (self->autoscale_policy == autoscale)
+ return;
+
+ self->autoscale_policy = autoscale;
+ update_autoscale(self);
+}
+
+GeglGtkViewAutoscale
+view_helper_get_autoscale_policy(ViewHelper *self)
+{
+ return self->autoscale_policy;
+}
diff --git a/src/gegl-gtk-view-helper.h b/src/gegl-gtk-view-helper.h
new file mode 100644
index 0000000..022ac5e
--- /dev/null
+++ b/src/gegl-gtk-view-helper.h
@@ -0,0 +1,90 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2003, 2004, 2006 Øyvind Kolås <pippin gimp org>
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#ifndef __VIEW_HELPER_H__
+#define __VIEW_HELPER_H__
+
+#include <glib-object.h>
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include <gegl-gtk-enums.h>
+
+G_BEGIN_DECLS
+
+#define VIEW_HELPER_TYPE (view_helper_get_type ())
+#define VIEW_HELPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIEW_HELPER_TYPE, ViewHelper))
+#define VIEW_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VIEW_HELPER_TYPE, ViewHelperClass))
+#define IS_VIEW_HELPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIEW_HELPER_TYPE))
+#define IS_VIEW_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VIEW_HELPER_TYPE))
+#define VIEW_HELPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VIEW_HELPER_TYPE, ViewHelperClass))
+
+typedef struct _ViewHelper ViewHelper;
+typedef struct _ViewHelperClass ViewHelperClass;
+
+struct _ViewHelper {
+ GObject parent_instance;
+
+ GeglNode *node;
+ gfloat x;
+ gfloat y;
+ gdouble scale;
+ gboolean block; /* blocking render */
+ GeglGtkViewAutoscale autoscale_policy;
+
+ guint monitor_id;
+ GeglProcessor *processor;
+ GQueue *processing_queue; /* Queue of rectangles that needs to be processed */
+ GeglRectangle *currently_processed_rect;
+
+ GdkRectangle widget_allocation; /* The allocated size of the widget */
+};
+
+struct _ViewHelperClass {
+ GObjectClass parent_class;
+};
+
+
+GType view_helper_get_type(void) G_GNUC_CONST;
+
+ViewHelper *view_helper_new(void);
+
+void view_helper_draw(ViewHelper *self, cairo_t *cr, GdkRectangle *rect);
+void view_helper_set_allocation(ViewHelper *self, GdkRectangle *allocation);
+
+void view_helper_set_node(ViewHelper *self, GeglNode *node);
+GeglNode *view_helper_get_node(ViewHelper *self);
+
+void view_helper_set_scale(ViewHelper *self, float scale);
+float view_helper_get_scale(ViewHelper *self);
+
+void view_helper_set_x(ViewHelper *self, float x);
+float view_helper_get_x(ViewHelper *self);
+
+void view_helper_set_y(ViewHelper *self, float y);
+float view_helper_get_y(ViewHelper *self);
+
+void view_helper_get_transformation(ViewHelper *self, GeglMatrix3 *matrix);
+
+void view_helper_set_autoscale_policy(ViewHelper *self, GeglGtkViewAutoscale autoscale);
+GeglGtkViewAutoscale view_helper_get_autoscale_policy(ViewHelper *self);
+
+G_END_DECLS
+
+#endif /* __VIEW_HELPER_H__ */
diff --git a/src/gegl-gtk-view.c b/src/gegl-gtk-view.c
new file mode 100644
index 0000000..74a3737
--- /dev/null
+++ b/src/gegl-gtk-view.c
@@ -0,0 +1,638 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2003, 2004, 2006 Øyvind Kolås <pippin gimp org>
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gegl.h>
+
+#ifdef HAVE_CAIRO_GOBJECT
+#include <cairo-gobject.h>
+#endif
+
+#include "gegl-gtk-view.h"
+#include "gegl-gtk-view-helper.h"
+#include "gegl-gtk-marshal.h"
+
+/**
+ * SECTION:gegl-gtk-view
+ * @short_description: Widget for displaying a #GeglNode
+ * @stability: Unstable
+ * @include: gegl-gtk.h
+ *
+ * The view widget displays the output of a node in a GEGL graph.
+ * It will tracks changes in the node, and will therefore automatically
+ * show the correct content when the GEGL graph is changed.
+ *
+ * For setting which #GeglNode to display, use gegl_gtk_view_set_node(),
+ * or use the gegl_gtk_view_new_for_node() convenience constructor.
+ *
+ * Transformations:
+ *
+ * The widget can show a transformed view of the GeglNode. Scaling and
+ * transformations are supported, as well as autoscaling.
+ * For manual control over the transformation see
+ * methods gegl_gtk_view_set_scale(), gegl_gtk_view_set_x() and
+ * gegl_gtk_view_set_y(), or use the corresponding properties.
+ * For changing the autoscaling behavior, see
+ * gegl_gtk_view_set_autoscale_policy()
+ * For getting the effective affine transformation applied, use
+ * gegl_gtk_view_get_transformation()
+ *
+ * Examples:
+ *
+ * In the GEGL-GTK example directories, you can find code examples for
+ * how to use #GeglGtkView in files with names starting with gegl-gtk-view
+ **/
+
+/*
+ * This class is responsible for providing the public interface
+ * consumers expect of the view widget, and for rendering onto the widget.
+ * Tracking changes in the GeglNode, dealing with model<->view transformations
+ * et.c. is delegated to the internal/private class ViewHelper.
+ *
+ * This separation of concerns keeps the classes small and "stupid", and
+ * allows to test a lot of functionality without having to instantiate
+ * a widget and rely on the presence and behaviour of a windowing system.
+ */
+
+/*
+ * TODO: Emit a transformation-changed signal whenever the tranformation changes
+ */
+
+G_DEFINE_TYPE(GeglGtkView, gegl_gtk_view, GTK_TYPE_DRAWING_AREA)
+
+
+enum {
+ PROP_0,
+ PROP_NODE,
+ PROP_X,
+ PROP_Y,
+ PROP_SCALE,
+ PROP_BLOCK,
+ PROP_AUTOSCALE_POLICY
+};
+
+#ifdef HAVE_CAIRO_GOBJECT
+enum {
+ SIGNAL_DRAW_BACKGROUND,
+ SIGNAL_DRAW_OVERLAY,
+ N_SIGNALS
+};
+
+static guint gegl_view_signals[N_SIGNALS];
+#endif
+
+static ViewHelper *
+get_private(GeglGtkView *self)
+{
+ return VIEW_HELPER(self->priv);
+}
+
+#define GET_PRIVATE(self) (get_private(self))
+
+
+static void gegl_gtk_view_class_init(GeglGtkViewClass *klass);
+static void gegl_gtk_view_init(GeglGtkView *self);
+static void finalize(GObject *gobject);
+static void set_property(GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void get_property(GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+#ifdef HAVE_GTK2
+static gboolean expose_event(GtkWidget *widget,
+ GdkEventExpose *event);
+#endif
+#ifdef HAVE_GTK3
+static gboolean draw(GtkWidget *widget,
+ cairo_t *cr);
+#endif
+
+
+static void
+trigger_redraw(ViewHelper *priv, GeglRectangle *rect, GeglGtkView *view);
+static void
+size_allocate(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data);
+
+static void
+view_size_changed(ViewHelper *priv, GeglRectangle *rect, GeglGtkView *view);
+
+static void
+gegl_gtk_view_class_init(GeglGtkViewClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ gobject_class->finalize = finalize;
+ gobject_class->set_property = set_property;
+ gobject_class->get_property = get_property;
+
+#ifdef HAVE_GTK2
+ widget_class->expose_event = expose_event;
+#endif
+
+#ifdef HAVE_GTK3
+ widget_class->draw = draw;
+#endif
+
+ g_object_class_install_property(gobject_class, PROP_X,
+ g_param_spec_float("x",
+ "X",
+ "X origin",
+ -G_MAXFLOAT, G_MAXFLOAT, 0.0,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, PROP_Y,
+ g_param_spec_float("y",
+ "Y",
+ "Y origin",
+ -G_MAXFLOAT, G_MAXFLOAT, 0.0,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, PROP_SCALE,
+ g_param_spec_double("scale",
+ "Scale",
+ "Zoom factor",
+ 0.0, 100.0, 1.00,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, PROP_NODE,
+ g_param_spec_object("node",
+ "Node",
+ "The node to render",
+ G_TYPE_OBJECT,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, PROP_BLOCK,
+ g_param_spec_boolean("block",
+ "Blocking render",
+ "Make sure all data requested to blit is generated.",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property(gobject_class, PROP_AUTOSCALE_POLICY,
+ g_param_spec_enum("autoscale-policy",
+ "Autoscale policy", "The autoscaling behavior used",
+ GEGL_GTK_TYPE_VIEW_AUTOSCALE,
+ GEGL_GTK_VIEW_AUTOSCALE_CONTENT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+
+/* XXX: maybe we should just allow a second GeglNode to be specified for background? */
+
+/**
+ * GeglGtkView::draw-background:
+ * @widget: the #GeglGtkView widget that emitted the signal
+ * @cr: the #CairoContext to render to
+ * @rect: the area that was updated, view coordinates
+ *
+ * Emitted during painting, before the node contents has been rendered.
+ * Allows consumers to draw a custom background for the widget.
+ *
+ * Note:
+ * Manipulating the view widget in the signal handler is not supported.
+ * This signal is only available if GEGL-GTK was build with Cairo GObject support.
+ **/
+
+/**
+* GeglGtkView::draw-overlay:
+* @widget: the #GeglGtkView widget that emitted the signal
+* @cr: the #CairoContext to render to
+* @rect: the area that was updated, in view coordinates
+*
+* Emitted during painting, before the node contents has been rendered.
+*
+* Allows consumers to draw an overlay for the widget, for instance
+* for simple user interface elements.
+*
+* Note:
+* Manipulating the view widget in the signal handler is not supported.
+* This signal is only available if GEGL-GTK was build with Cairo GObject support.
+**/
+#ifdef HAVE_CAIRO_GOBJECT
+ gegl_view_signals[SIGNAL_DRAW_BACKGROUND] =
+ g_signal_new("draw-background",
+ G_TYPE_FROM_CLASS(klass),
+ 0,
+ 0,
+ NULL,
+ NULL,
+ gegl_gtk_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE, 2, CAIRO_GOBJECT_TYPE_CONTEXT, GDK_TYPE_RECTANGLE);
+
+ gegl_view_signals[SIGNAL_DRAW_OVERLAY] =
+ g_signal_new("draw-overlay",
+ G_TYPE_FROM_CLASS(klass),
+ 0,
+ 0,
+ NULL,
+ NULL,
+ gegl_gtk_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE, 2, CAIRO_GOBJECT_TYPE_CONTEXT, GDK_TYPE_RECTANGLE);
+#endif
+
+}
+
+static void
+gegl_gtk_view_init(GeglGtkView *self)
+{
+ self->priv = (GeglGtkViewPrivate *)view_helper_new();
+
+ g_signal_connect(self->priv, "redraw-needed", G_CALLBACK(trigger_redraw), (gpointer)self);
+ g_signal_connect(self->priv, "size-changed", G_CALLBACK(view_size_changed), (gpointer)self);
+
+ g_signal_connect(self, "size-allocate", G_CALLBACK(size_allocate), NULL);
+}
+
+static void
+finalize(GObject *gobject)
+{
+ GeglGtkView *self = GEGL_GTK_VIEW(gobject);
+
+ g_object_unref(G_OBJECT(self->priv));
+
+ G_OBJECT_CLASS(gegl_gtk_view_parent_class)->finalize(gobject);
+}
+
+static void
+set_property(GObject *gobject,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeglGtkView *self = GEGL_GTK_VIEW(gobject);
+ ViewHelper *priv = GET_PRIVATE(self);
+
+ switch (property_id) {
+ case PROP_NODE:
+ gegl_gtk_view_set_node(self, GEGL_NODE(g_value_get_object(value)));
+ break;
+ case PROP_X:
+ gegl_gtk_view_set_x(self, g_value_get_float(value));
+ break;
+ case PROP_BLOCK:
+ priv->block = g_value_get_boolean(value);
+ break;
+ case PROP_Y:
+ gegl_gtk_view_set_y(self, g_value_get_float(value));
+ break;
+ case PROP_SCALE:
+ gegl_gtk_view_set_scale(self, g_value_get_double(value));
+ break;
+ case PROP_AUTOSCALE_POLICY:
+ gegl_gtk_view_set_autoscale_policy(self, g_value_get_enum(value));
+ break;
+ default:
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property(GObject *gobject,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeglGtkView *self = GEGL_GTK_VIEW(gobject);
+ ViewHelper *priv = GET_PRIVATE(self);
+
+ switch (property_id) {
+ case PROP_NODE:
+ g_value_set_object(value, gegl_gtk_view_get_node(self));
+ break;
+ case PROP_X:
+ g_value_set_float(value, gegl_gtk_view_get_x(self));
+ break;
+ case PROP_BLOCK:
+ g_value_set_boolean(value, priv->block);
+ break;
+ case PROP_Y:
+ g_value_set_float(value, gegl_gtk_view_get_y(self));
+ break;
+ case PROP_SCALE:
+ g_value_set_double(value, gegl_gtk_view_get_scale(self));
+ break;
+ case PROP_AUTOSCALE_POLICY:
+ g_value_set_enum(value, gegl_gtk_view_get_autoscale_policy(self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec);
+ break;
+ }
+}
+
+/* Trigger a redraw */
+static void
+trigger_redraw(ViewHelper *priv,
+ GeglRectangle *rect,
+ GeglGtkView *view)
+{
+ if (rect->width < 0 || rect->height < 0)
+ gtk_widget_queue_draw(GTK_WIDGET(view));
+ else
+ gtk_widget_queue_draw_area(GTK_WIDGET(view),
+ rect->x, rect->y, rect->width, rect->height);
+}
+
+/* Bounding box of the node view changed */
+static void
+view_size_changed(ViewHelper *priv, GeglRectangle *rect, GeglGtkView *view)
+{
+ /* Resize the widget to fit the entire view bounding box
+ * TODO: implement a policy for this
+ * consumers should be able to have the view not autoscale at all
+ * or to have it autoscale the content to fit the size of widget */
+ gtk_widget_set_size_request(GTK_WIDGET(view), rect->width, rect->height);
+}
+
+static void
+size_allocate(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data)
+{
+ GeglGtkView *self = GEGL_GTK_VIEW(widget);
+ view_helper_set_allocation(GET_PRIVATE(self), allocation);
+}
+
+static void
+draw_implementation(GeglGtkView *self, cairo_t *cr, GdkRectangle *rect)
+{
+ ViewHelper *priv = GET_PRIVATE(self);
+
+#ifdef HAVE_CAIRO_GOBJECT
+ /* Draw background */
+ cairo_save(cr);
+ g_signal_emit(G_OBJECT(self), gegl_view_signals[SIGNAL_DRAW_BACKGROUND],
+ 0, cr, rect, NULL);
+ cairo_restore(cr);
+#endif
+
+ /* Draw the gegl node */
+ cairo_save(cr);
+ view_helper_draw(priv, cr, rect);
+ cairo_restore(cr);
+
+#ifdef HAVE_CAIRO_GOBJECT
+ /* Draw overlay */
+ cairo_save(cr);
+ g_signal_emit(G_OBJECT(self), gegl_view_signals[SIGNAL_DRAW_OVERLAY],
+ 0, cr, rect, NULL);
+ cairo_restore(cr);
+#endif
+}
+
+#ifdef HAVE_GTK3
+static gboolean
+draw(GtkWidget *widget, cairo_t *cr)
+{
+ GeglGtkView *self = GEGL_GTK_VIEW(widget);
+ ViewHelper *priv = GET_PRIVATE(self);
+ GdkRectangle rect;
+
+ if (!priv->node)
+ return FALSE;
+
+ gdk_cairo_get_clip_rectangle(cr, &rect);
+
+ draw_implementation(self, cr, &rect);
+
+ return FALSE;
+}
+#endif
+
+#ifdef HAVE_GTK2
+static gboolean
+expose_event(GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GeglGtkView *self = GEGL_GTK_VIEW(widget);
+ ViewHelper *priv = GET_PRIVATE(self);
+ cairo_t *cr;
+ GdkRectangle rect;
+
+ if (!priv->node)
+ return FALSE;
+
+ cr = gdk_cairo_create(widget->window);
+ gdk_cairo_region(cr, event->region);
+ cairo_clip(cr);
+ gdk_region_get_clipbox(event->region, &rect);
+
+ draw_implementation(self, cr, &rect);
+
+ cairo_destroy(cr);
+
+ return FALSE;
+}
+#endif
+
+
+/**
+ * gegl_gtk_view_new:
+ *
+ * Create a new #GeglGtkView
+ *
+ * Returns: New #GeglGtkView
+ **/
+GeglGtkView *
+gegl_gtk_view_new()
+{
+ return GEGL_GTK_VIEW(g_object_new(GEGL_GTK_TYPE_VIEW, NULL));
+}
+
+GeglGtkView *
+gegl_gtk_view_new_for_buffer(GeglBuffer *buffer)
+{
+ GeglNode *node = gegl_node("gegl:buffer-source",
+ "buffer", buffer, NULL);
+ return gegl_gtk_view_new_for_node(node);
+}
+
+/**
+ * gegl_gtk_view_new_for_node:
+ * @node: The #GeglNode to display
+ *
+ * Create a new #GeglGtkView for a given #GeglNode
+ *
+ * Returns: New #GeglGtkView displaying @node
+ **/
+GeglGtkView *
+gegl_gtk_view_new_for_node(GeglNode *node)
+{
+ GeglGtkView *view = gegl_gtk_view_new();
+ gegl_gtk_view_set_node(view, node);
+ return view;
+}
+
+/**
+ * gegl_gtk_view_set_node:
+ * @self: A #GeglGtkView
+ * @node: (transfer full)(allow-none): a #GeglNode instance or %NULL
+ *
+ * Change the #GeglNode to display
+ **/
+void
+gegl_gtk_view_set_node(GeglGtkView *self, GeglNode *node)
+{
+ view_helper_set_node(GET_PRIVATE(self), node);
+}
+
+/**
+ * gegl_gtk_view_get_node:
+ * @self: A #GeglGtkView
+ * Returns: (transfer none): The #GeglNode this widget displays
+ *
+ * Get the displayed #GeglNode
+ **/
+GeglNode *
+gegl_gtk_view_get_node(GeglGtkView *self)
+{
+ return view_helper_get_node(GET_PRIVATE(self));
+}
+
+/**
+ * gegl_gtk_view_set_scale:
+ * @self: A #GeglGtkView
+ * @scale:
+ *
+ * Setter for the :scale property
+ **/
+void
+gegl_gtk_view_set_scale(GeglGtkView *self, float scale)
+{
+ view_helper_set_scale(GET_PRIVATE(self), scale);
+}
+
+/**
+ * gegl_gtk_view_get_scale:
+ * @self: A #GeglGtkView
+ *
+ * Getter for the :scale property
+ *
+ * Returns:
+ **/
+float
+gegl_gtk_view_get_scale(GeglGtkView *self)
+{
+ return view_helper_get_scale(GET_PRIVATE(self));
+}
+
+/**
+ * gegl_gtk_view_set_x:
+ * @self: A #GeglGtkView
+ * @x:
+ *
+ * Setter for the :x property
+ **/
+void
+gegl_gtk_view_set_x(GeglGtkView *self, float x)
+{
+ view_helper_set_x(GET_PRIVATE(self), x);
+}
+
+/**
+ * gegl_gtk_view_get_x:
+ * @self: A #GeglGtkView
+ *
+ * Getter for the :x property
+ *
+ * Returns:
+ **/
+float
+gegl_gtk_view_get_x(GeglGtkView *self)
+{
+ return view_helper_get_x(GET_PRIVATE(self));
+}
+
+/**
+ * gegl_gtk_view_set_y:
+ * @self: A #GeglGtkView
+ * @y:
+ *
+ * Setter for the :y property
+ **/
+void
+gegl_gtk_view_set_y(GeglGtkView *self, float y)
+{
+ view_helper_set_y(GET_PRIVATE(self), y);
+}
+
+/**
+ * gegl_gtk_view_get_y:
+ * @self: A #GeglGtkView
+ *
+ * Getter for the :y property
+ *
+ * Returns:
+ **/
+float
+gegl_gtk_view_get_y(GeglGtkView *self)
+{
+ return view_helper_get_y(GET_PRIVATE(self));
+}
+
+/**
+ * gegl_gtk_view_get_transformation:
+ * @self: A #GeglGtkView
+ * @matrix: (out caller-allocates): Pointer to location for transformation matrix
+ *
+ * Get the model->view transformation
+ *
+ * The transformation matrix describes the transformation between the
+ * model (the output of the GeglNode) and the view (the display in the widget).
+ * To transform coordinates use gegl_matrix3_transform_point().
+ * To get a matrix representing the view->model space transformation, use gegl_matrix3_invert()
+ **/
+void gegl_gtk_view_get_transformation(GeglGtkView *self, GeglMatrix3 *matrix)
+{
+ view_helper_get_transformation(GET_PRIVATE(self), matrix);
+}
+
+/**
+ * gegl_gtk_view_set_autoscale_policy:
+ * @self: A #GeglGtkView
+ * @autoscale: #GeglGtkViewAutoscale policy to use
+ *
+ * Set the autoscaling policy
+ **/
+void
+gegl_gtk_view_set_autoscale_policy(GeglGtkView *self, GeglGtkViewAutoscale autoscale)
+{
+ view_helper_set_autoscale_policy(GET_PRIVATE(self), autoscale);
+}
+
+/**
+ * gegl_gtk_view_get_autoscale_policy:
+ * @self: A #GeglGtkView
+ *
+ * Get the autoscaling policy
+ *
+ * Returns: Current #GeglGtkViewAutoscale policy in use
+ **/
+GeglGtkViewAutoscale
+gegl_gtk_view_get_autoscale_policy(GeglGtkView *self)
+{
+ return view_helper_get_autoscale_policy(GET_PRIVATE(self));
+}
diff --git a/src/gegl-gtk-view.h b/src/gegl-gtk-view.h
new file mode 100644
index 0000000..d6611c7
--- /dev/null
+++ b/src/gegl-gtk-view.h
@@ -0,0 +1,79 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2003, 2004, 2006 Øyvind Kolås <pippin gimp org>
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#ifndef __GEGL_GTK_VIEW_H__
+#define __GEGL_GTK_VIEW_H__
+
+#include <gtk/gtk.h>
+#include <gegl.h>
+
+#include "gegl-gtk-enums.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_GTK_TYPE_VIEW (gegl_gtk_view_get_type ())
+#define GEGL_GTK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_GTK_TYPE_VIEW, GeglGtkView))
+#define GEGL_GTK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEGL_GTK_TYPE_VIEW,
GeglGtkViewClass))
+#define GEGL_GTK_IS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_GTK_TYPE_VIEW))
+#define GEGL_GTK_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_GTK_TYPE_VIEW))
+#define GEGL_GTK_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_GTK_TYPE_VIEW,
GeglGtkViewClass))
+
+typedef struct _GeglGtkView GeglGtkView;
+typedef struct _GeglGtkViewClass GeglGtkViewClass;
+
+typedef struct _ViewHelper GeglGtkViewPrivate;
+
+struct _GeglGtkView {
+ /*< private >*/
+ GtkDrawingArea parent_instance;
+ GeglGtkViewPrivate *priv; /* Can't use the GType private mechanism for GObjects */
+};
+
+struct _GeglGtkViewClass {
+ /*< private >*/
+ GtkDrawingAreaClass parent_class;
+};
+
+GType gegl_gtk_view_get_type(void) G_GNUC_CONST;
+
+
+GeglGtkView *gegl_gtk_view_new(void);
+GeglGtkView *gegl_gtk_view_new_for_node(GeglNode *node);
+GeglGtkView *gegl_gtk_view_new_for_buffer(GeglBuffer *buffer);
+
+void gegl_gtk_view_set_node(GeglGtkView *self, GeglNode *node);
+GeglNode *gegl_gtk_view_get_node(GeglGtkView *self);
+
+void gegl_gtk_view_set_scale(GeglGtkView *self, float scale);
+float gegl_gtk_view_get_scale(GeglGtkView *self);
+
+void gegl_gtk_view_set_x(GeglGtkView *self, float x);
+float gegl_gtk_view_get_x(GeglGtkView *self);
+
+void gegl_gtk_view_set_y(GeglGtkView *self, float y);
+float gegl_gtk_view_get_y(GeglGtkView *self);
+
+void gegl_gtk_view_get_transformation(GeglGtkView *self, GeglMatrix3 *matrix);
+
+void gegl_gtk_view_set_autoscale_policy(GeglGtkView *self, GeglGtkViewAutoscale autoscale);
+GeglGtkViewAutoscale gegl_gtk_view_get_autoscale_policy(GeglGtkView *self);
+
+G_END_DECLS
+
+#endif /* __GEGL_GTK_VIEW_H__ */
diff --git a/src/photos-preview-view.c b/src/photos-preview-view.c
index 8c7815b..1b1183a 100644
--- a/src/photos-preview-view.c
+++ b/src/photos-preview-view.c
@@ -25,11 +25,11 @@
#include "config.h"
-#include <gegl-gtk.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include "gegl-gtk-view.h"
#include "photos-preview-view.h"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]