gnome-scan r647 - in trunk: . bindings doc/ref lib modules po src tools



Author: bersace
Date: Sat Dec  6 17:38:48 2008
New Revision: 647
URL: http://svn.gnome.org/viewvc/gnome-scan?rev=647&view=rev

Log:
Rewrited lib/ in vala

Added:
   trunk/lib/gnome-scan-acquisition-widget.vala
   trunk/lib/gnome-scan-backend.vala
   trunk/lib/gnome-scan-dialog.vala
   trunk/lib/gnome-scan-init.vala
   trunk/lib/gnome-scan-job.vala
   trunk/lib/gnome-scan-module-manager.vala
   trunk/lib/gnome-scan-node.vala
   trunk/lib/gnome-scan-option-box.vala
   trunk/lib/gnome-scan-option-manager.vala
   trunk/lib/gnome-scan-option-page.vala
   trunk/lib/gnome-scan-scanner-selector.vala
   trunk/lib/gnome-scan-scanner.vala
   trunk/lib/gnome-scan-sink.vala
   trunk/src/flegita-option-widgets.vala
   trunk/src/flegita-options.vala
   trunk/src/flegita-sink.vala
   trunk/src/flegita.vala
   trunk/tools/gs-test.c
Removed:
   trunk/bindings/
   trunk/lib/gnome-scan-acquisition-dialog.c
   trunk/lib/gnome-scan-acquisition-dialog.h
   trunk/lib/gnome-scan-backend.c
   trunk/lib/gnome-scan-backend.h
   trunk/lib/gnome-scan-boolean-widget.h
   trunk/lib/gnome-scan-dialog.c
   trunk/lib/gnome-scan-dialog.h
   trunk/lib/gnome-scan-enum-widget.h
   trunk/lib/gnome-scan-init.c
   trunk/lib/gnome-scan-init.h
   trunk/lib/gnome-scan-job.c
   trunk/lib/gnome-scan-job.h
   trunk/lib/gnome-scan-module-manager.c
   trunk/lib/gnome-scan-module-manager.h
   trunk/lib/gnome-scan-number-widget.h
   trunk/lib/gnome-scan-page-orientation-widget.h
   trunk/lib/gnome-scan-paper-size-widget.h
   trunk/lib/gnome-scan-param-specs.h
   trunk/lib/gnome-scan-param-widget.h
   trunk/lib/gnome-scan-plugin.h
   trunk/lib/gnome-scan-preview-area.h
   trunk/lib/gnome-scan-preview-plugin-area.h
   trunk/lib/gnome-scan-preview-plugin-rotation.h
   trunk/lib/gnome-scan-preview-plugin.h
   trunk/lib/gnome-scan-preview-sink.h
   trunk/lib/gnome-scan-private.h
   trunk/lib/gnome-scan-processor-common.h
   trunk/lib/gnome-scan-range-widget.h
   trunk/lib/gnome-scan-scanner.h
   trunk/lib/gnome-scan-settings.h
   trunk/lib/gnome-scan-sink.h
   trunk/lib/gnome-scan-string-widget.h
   trunk/src/flegita-sink.c
   trunk/src/flegita-sink.h
   trunk/src/flegita.c
   trunk/src/flegita.h
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/THANKS
   trunk/config.vapi
   trunk/configure.ac
   trunk/doc/ref/gnome-scan.types
   trunk/lib/Makefile.am
   trunk/lib/gnome-scan-common.vala
   trunk/lib/gnome-scan-module-helper.h
   trunk/lib/gnome-scan-module.vala
   trunk/lib/gnome-scan-option-widget.vala
   trunk/lib/gnome-scan-option.vala
   trunk/lib/gnome-scan.h
   trunk/modules/Makefile.am
   trunk/modules/gsfile-backend.c
   trunk/modules/gsfile-filenames-widget.c
   trunk/modules/gsfile-filenames-widget.h
   trunk/modules/gsfile-module.c
   trunk/modules/gsfile-scanner.c
   trunk/modules/gsfile-scanner.h
   trunk/po/ChangeLog
   trunk/po/POTFILES.in
   trunk/src/Makefile.am
   trunk/tools/Makefile.am

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am	(original)
+++ trunk/Makefile.am	Sat Dec  6 17:38:48 2008
@@ -9,7 +9,9 @@
 	bindings	\
 	po		\
 	doc		\
-	data
+	tools		\
+	data		\
+	$(NULL)
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = \

Modified: trunk/THANKS
==============================================================================
--- trunk/THANKS	(original)
+++ trunk/THANKS	Sat Dec  6 17:38:48 2008
@@ -1,10 +1,7 @@
-Well, all commits are tagged "bersace", but all this couldn't have
-been done without a lot of people.
-
-Thanks for all people who helped me for Gnome Scan :
+GNOME Scan has some years of development. Nothing could have been
+possible alone.  Thanks for all people who helped me for GNOME Scan :
 
  * Philip Sadleder, the earliest gnome-scan tester and translator.
- * Donald Straney, for his work on imcapd.
  * Olaf Leidinger, for his disable-gnome patch (0.4 series).
  * Ross Burton, for its review of 0.5.93 (no gnome, module version,
    build system, etc.)
@@ -26,4 +23,4 @@
  * SANE
  * HAL
  * Emmanuele Bassi ;)
- * Google for his sponsorship and Vincent Untz for its mentoring.
+ * Google for his sponsorship and Vincent Untz for his mentoring.

Modified: trunk/config.vapi
==============================================================================
--- trunk/config.vapi	(original)
+++ trunk/config.vapi	Sat Dec  6 17:38:48 2008
@@ -1,4 +1,7 @@
 [CCode (cprefix="", lower_case_prefix="", cheader_filename="config.h")]
 namespace Config {
-	public const string GETTEXT_PACKAGE;
+	[CCode (cname = "GETTEXT_PACKAGE")]
+    public const string GETTEXT_PACKAGE;
+	[CCode (cname = "MODULE_DIR")]
+    public const string MODULE_DIR;
 }
\ No newline at end of file

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Sat Dec  6 17:38:48 2008
@@ -12,7 +12,7 @@
 AM_PROG_CC_C_O
 
 dnl VALA
-VALA_PROG_VALAC(0.5.1)
+VALA_PROG_VALAC(0.5.2)
 
 GNOME_COMPILE_WARNINGS([maximum])
 
@@ -49,18 +49,18 @@
 
 AM_PROG_LIBTOOL
 
-LIB_NAME=[gnomescan]
 LIB_CUR=[1]
 LIB_REV=[0]
 LIB_AGE=[0]
 LIB_VERSION=[${LIB_CUR}.${LIB_REV}.${LIB_AGE}]
 API_VERSION=[${LIB_CUR}.0]
-SONAME=[${LIB_NAME}]
+SONAME=[${PACKAGE_NAME}]
+VAPINAME=[${SONAME}-${API_VERSION}]
 
 AC_SUBST(SONAME)
 AC_SUBST(LIB_VERSION)
 AC_SUBST(API_VERSION)
-
+AC_SUBST(VAPINAME)
 
 PKG_CHECK_MODULES(GNOME_SCAN, [gmodule-2.0 gthread-2.0 glib-2.0 gdk-2.0 >= 2.11 gdk-pixbuf-2.0 gtk+-2.0 >= 2.12 gegl >= 0.0.21 gconf-2.0 ])
 AC_SUBST(GNOME_SCAN_CFLAGS)
@@ -112,9 +112,20 @@
 dnl TOOLS
 dnl ***************************************************************************
 
-PKG_CHECK_MODULES(TOOLS, [libglade-2.0 >= 2.6])
-AC_SUBST(TOOLS_CFLAGS)
-AC_SUBST(TOOLS_LIBS)
+AC_ARG_ENABLE(tools,
+              [	--enable-tools  Enable developers tools [default=no]],
+	      enable_tools="$enableval", enable_tools=no)
+if test x$enable_tools = xauto ; then
+  if test x$GTKDOC = xtrue ; then
+    enable_tools=yes
+    PKG_CHECK_MODULES(TOOLS, [libglade-2.0 >= 2.6])
+    AC_SUBST(TOOLS_CFLAGS)
+    AC_SUBST(TOOLS_LIBS)
+  else
+    enable_tools=no
+  fi
+fi
+AM_CONDITIONAL(ENABLE_TOOLS, test x$enable_tools = xyes)
 
 dnl ***************************************************************************
 dnl FLEGITA
@@ -148,15 +159,13 @@
 GIMP_LIBDIR=`$PKG_CONFIG $pcdv --variable=gimplibdir gimp-2.0`
 AC_SUBST(GIMP_LIBDIR)
 
-# GObject Introspection, required
-PKG_CHECK_MODULES(GIR, [gobject-introspection-1.0 gir-repository-1.0])
-
-G_IR_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
-AC_SUBST(G_IR_SCANNER)
+dnl GOBJECT INTROSPECTION
+PKG_CHECK_MODULES(GIR, [gobject-introspection-1.0])
 
 girdir=`$PKG_CONFIG $pcdv --variable=girdir gobject-introspection-1.0`
 AC_SUBST(girdir)
 
+dnl OUTPUT
 AC_OUTPUT([
 	gnome-scan.pc
 	Makefile
@@ -168,6 +177,5 @@
 	doc/ref/Makefile
 	doc/ref/version.xml
 	data/Makefile
-	bindings/Makefile
-	bindings/gir/Makefile
+	tools/Makefile
 ])

Modified: trunk/doc/ref/gnome-scan.types
==============================================================================
--- trunk/doc/ref/gnome-scan.types	(original)
+++ trunk/doc/ref/gnome-scan.types	Sat Dec  6 17:38:48 2008
@@ -1,17 +1,7 @@
 gnome_scan_backend_get_type
 gnome_scan_module_get_type
 gnome_scan_module_manager_get_type
-gnome_scan_settings_get_type
-gnome_scan_plugin_get_type
+gnome_scan_node_get_type
 gnome_scan_scanner_get_type
-gnome_scan_sink_get_type
-gnome_scan_preview_sink_get_type
-gnome_scan_processor_common_get_type
 gnome_scan_job_get_type
-gnome_scan_acquisition_dialog_get_type
-gnome_scan_preview_area_get_type
 gnome_scan_dialog_get_type
-gnome_scan_param_widget_get_type
-gnome_scan_preview_plugin_get_type
-gnome_scan_preview_plugin_rotation_get_type
-gnome_scan_preview_plugin_area_get_type

Modified: trunk/lib/Makefile.am
==============================================================================
--- trunk/lib/Makefile.am	(original)
+++ trunk/lib/Makefile.am	Sat Dec  6 17:38:48 2008
@@ -1,125 +1,69 @@
 INCLUDES = \
 	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"	\
 	-DGETTEXT_PACKAGE=\""@GETTEXT_PACKAGE@"\"	\
-	-DICON_DIR=\""@ICON_DIR@"\"
+	-DICON_DIR=\""@ICON_DIR@"\" \
+	-include ../config.h
 
 AM_CFLAGS = \
 	-Wall -g
 
-BUILT_SOURCES = \
-	gnome-scan.vala.stamp
+BUILT_SOURCES = gnome-scan.vala.stamp
 
 lib_LTLIBRARIES = \
-	lib SONAME@.la 
+	libgnome-scan.la 
 
-libgnomescan_la_VALASOURCES = \
-	gnome-scan-common.vala	\
-	gnome-scan-option.vala	\
-	gnome-scan-option-widget.vala \
-	gnome-scan-module.vala \
+libgnome_scan_la_VALASOURCES = \
+	gnome-scan-common.vala			\
+	gnome-scan-module.vala			\
+	gnome-scan-module-helper.h		\
+	gnome-scan-module-manager.vala		\
+	gnome-scan-option.vala			\
+	gnome-scan-node.vala			\
+	gnome-scan-scanner.vala			\
+	gnome-scan-sink.vala			\
+	gnome-scan-job.vala			\
+	gnome-scan-backend.vala			\
+	gnome-scan-option-manager.vala		\
+	gnome-scan-init.vala			\
+	gnome-scan-scanner-selector.vala	\
+	gnome-scan-acquisition-widget.vala	\
+	gnome-scan-dialog.vala			\
+	gnome-scan-option-page.vala		\
+	gnome-scan-option-box.vala		\
+	gnome-scan-option-widget.vala		\
 	$(NULL)
 
-lib SONAME@_la_VALAPKGADD = \
-	--pkg=glib-2.0	\
-	--pkg=gmodule-2.0 \ 
-	--pkg=gtk+-2.0	\
-	--pkg=gconf-2.0 \
+libgnome_scan_la_VALAPKGADD = \
+	--pkg=gmodule-2.0	\
+	--pkg=gtk+-2.0		\
+	--pkg=gconf-2.0 	\
+	--pkg=gegl-0.0		\
 	--vapidir=$(top_srcdir) --pkg=config \
-	--vapidir=$(top_srcdir)/bindings/vapi \
 	$(NULL)
 
-lib SONAME@_la_SOURCES = \
+libgnome_scan_la_SOURCES = \
 	gnome-scan.vala.stamp	\
-	$(BUILT_SOURCE) \
-	$(BUILT_HEADER) \
-	$(libgnomescan_la_VALASOURCES:.vala=.c)	\
-	$(libgnomescan_la_VALASOURCES:.vala=.h)	\
-	gnome-scan-settings.h          \
-	gnome-scan-settings.c          \
-	gnome-scan-plugin.h          \
-	gnome-scan-plugin.c          \
-	gnome-scan-scanner.h          \
-	gnome-scan-scanner.c          \
-	gnome-scan-sink.h          \
-	gnome-scan-sink.c          \
-	gnome-scan-backend.h          \
-	gnome-scan-backend.c          \
-	gnome-scan-job.h          \
-	gnome-scan-job.c          \
-	gnome-scan-preview-area.h          \
-	gnome-scan-preview-area.c          \
-	gnome-scan-param-widget.h          \
-	gnome-scan-param-widget.c          \
-	gnome-scan-acquisition-dialog.h          \
-	gnome-scan-acquisition-dialog.c          \
-	gnome-scan-module-manager.h	\
-	gnome-scan-module-manager.c	\
-	gnome-scan-dialog.h          \
-	gnome-scan-dialog.c          \
-	gnome-scan-param-specs.c          \
-	gnome-scan-param-specs.h          \
-	gnome-scan-init.c          \
-	gnome-scan-init.h          \
-	gnome-scan-range-widget.h          \
-	gnome-scan-range-widget.c          \
-	gnome-scan-enum-widget.h          \
-	gnome-scan-enum-widget.c          \
-	gnome-scan-number-widget.h          \
-	gnome-scan-number-widget.c          \
-	gnome-scan-string-widget.h          \
-	gnome-scan-string-widget.c          \
-	gnome-scan-boolean-widget.h          \
-	gnome-scan-boolean-widget.c          \
-	gnome-scan-paper-size-widget.h          \
-	gnome-scan-paper-size-widget.c          \
-	gnome-scan-page-orientation-widget.h          \
-	gnome-scan-page-orientation-widget.c          \
-	gnome-scan-preview-sink.h          \
-	gnome-scan-preview-sink.c          \
-	gnome-scan-preview-plugin.h          \
-	gnome-scan-preview-plugin.c          \
-	gnome-scan-preview-plugin-area.h          \
-	gnome-scan-preview-plugin-area.c          \
-	gnome-scan-processor-common.h          \
-	gnome-scan-processor-common.c          \
-	gnome-scan-preview-plugin-rotation.h          \
-	gnome-scan-preview-plugin-rotation.c          \
-	gnome-scan-private.h
+	$(libgnome_scan_la_VALASOURCES:.vala=.c)	\
+	$(libgnome_scan_la_VALASOURCES:.vala=.h)	\
+	$(NULL)
 
-lib SONAME@_la_CFLAGS = \
+libgnome_scan_la_CFLAGS = \
 	$(GNOME_SCAN_CFLAGS) \
 	-DMODULE_DIR="\"@MODULE_DIR \""
 
-lib SONAME@_la_LIBADD = \
+libgnome_scan_la_LIBADD = \
 	$(GNOME_SCAN_LIBS)
 
-includegsdir = $(includedir)/gnome-scan- API_VERSION@
+includegsdir = $(includedir)/@SONAME@
 includegs_HEADERS = \
 	gnome-scan.h	\
-	$(BUILT_HEADER)	\
-	gnome-scan-common.h		\
-	gnome-scan-settings.h          	\
-	gnome-scan-plugin.h          	\
-	gnome-scan-scanner.h          	\
-	gnome-scan-sink.h          	\
-	gnome-scan-backend.h          	\
-	gnome-scan-job.h          	\
-	gnome-scan-preview-area.h       \
-	gnome-scan-param-widget.h       \
-	gnome-scan-acquisition-dialog.h \
-	gnome-scan-dialog.h          	\
-	gnome-scan-module-manager.h     \
-	gnome-scan-module.h          	\
-	gnome-scan-param-specs.h        \
-	gnome-scan-init.h 
-
-gnome-scan.vala.stamp: $(lib SONAME@_la_VALASOURCES)
-	$(VALAC) -C $(lib SONAME@_la_VALAPKGADD) $^
-	touch $@
+	$(NULL)
+
+gnome-scan.vala.stamp: $(libgnome_scan_la_VALASOURCES)
+	$(VALAC) --library= VAPINAME@ --thread -C $(libgnome_scan_la_VALAPKGADD) $^ && touch $@
 
 EXTRA_DIST = \
 	gnome-scan.vala.stamp	\
-	$(lib SONAME@_la_VALASOURCES)	\
+	$(libgnome_scan_la_VALASOURCES)	\
+	@VAPINAME  vapi @VAPINAME  gir \
 	$(NULL)
-
-## File created by the gnome-build tools

Added: trunk/lib/gnome-scan-acquisition-widget.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-acquisition-widget.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,90 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
+using Gtk;
+ 
+namespace Gnome.Scan {
+	public class AcquisitionWidget : Alignment {
+		private ProgressBar progressbar;
+		private Label status_label;
+
+		public Job		job			{ get; set construct; }
+		public string	primary		{ get; set construct; }
+		public string	secondary	{ get; set construct; }
+		public string	icon_name	{ get; set construct; }
+
+		construct {
+			this.xscale = 0;
+			this.yscale = 0;
+			this.border_width = 6;
+
+			var box = new VBox(false, 6);
+			this.add(box);
+
+			var head_box = new HBox(false, 6);
+			box.pack_start(head_box, false, true, 0);
+
+			var image = new Gtk.Image.from_icon_name(this.icon_name, IconSize.DIALOG);
+			image.set_alignment(0, 0);
+			image.set_padding(6, 6);
+			head_box.pack_start(image, false, true, 0);
+
+			var message_box = new VBox(false, 4);
+			head_box.pack_start(message_box, false, true, 0);
+
+			var primary_label = new Label(null);
+			primary_label.set_markup("<b><big>%s</big></b>".printf(this.primary));
+			primary_label.set_alignment(0, 0);
+			message_box.pack_start(primary_label, false, true, 0);
+
+			var secondary_label = new Label(this.secondary);
+			secondary_label.set_alignment(0, 0);
+			secondary_label.set_line_wrap(true);
+			message_box.pack_start(secondary_label, true, true, 0);
+
+			this.progressbar = new ProgressBar();
+			box.pack_start(this.progressbar, false, true, 0);
+
+			this.status_label = new Label(null);
+			this.status_label.set_alignment(0, 0);
+			this.status_label.set_line_wrap(true);
+			box.pack_start(this.status_label, false, true, 0);
+		}
+
+		public AcquisitionWidget(Job job, string primary, string secondary, string? icon_name)
+		{
+			if (icon_name == null)
+				icon_name = "scanner";
+
+			this.job = job;
+			this.primary = primary;
+			this.secondary = secondary;
+			this.icon_name = icon_name;
+		}
+
+		// to be add to a timeout source
+		public bool monitor_job()
+		{
+			this.progressbar.set_fraction(double.min(this.job.progress, 1.0));
+			return this.job.is_running();
+		}
+	}
+}
\ No newline at end of file

Added: trunk/lib/gnome-scan-backend.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-backend.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,30 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2007  Ãtienne Bersac <bersace03 laposte net>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
+namespace Gnome.Scan {
+    public abstract class Backend : Object {
+		public abstract void* probe_scanners();
+
+		public signal void scanner_added(Scanner scanner);
+		public signal void scanner_removed(Scanner scanner);
+		public signal void probe_done();
+    }
+}
\ No newline at end of file

Modified: trunk/lib/gnome-scan-common.vala
==============================================================================
--- trunk/lib/gnome-scan-common.vala	(original)
+++ trunk/lib/gnome-scan-common.vala	Sat Dec  6 17:38:48 2008
@@ -1,102 +1,144 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
 using GLib;
 using Gtk;
+using Config;
 
-namespace Gnome {
-	namespace Scan {
-		public enum Unit {
-			NONE	= -1,
-			PIXEL	,//= Gtk.Unit.PIXEL,
-			POINTS	,//= Gtk.Unit.POINTS,
-			MM		,//= Gtk.Unit.MM,
-			BIT,
-			DPI,
-			PERCENT,
-			MICROSECOND
-		}
-
-		public enum Status {
-			UNKNOWN,
-			READY,
-			BUSY
-		}
-
-		public struct Point {
-			double x;
-			double y;
-		}
-
-		public struct Format {
-			public string		name;
-			public string		description;
-			public string		domain;
-			[NoArrayLength]
-			public string[]	mime_types;
-			[NoArrayLength]
-			public string[]	extensions;
-		}
+namespace Gnome.Scan {
+	public enum Unit {
+		NONE	= -1,
+		PIXEL,
+		POINTS,
+		MM,
+		BIT,
+		DPI,
+		PERCENT,
+		MICROSECOND
+	}
 
-		private const double MM_PER_INCH	= 25.4;
+	// Status in reverse order of priority
+    public enum Status {
+		UNKNOWN		= 0,
+		FAILED		= 10,
+		INITIALIZING= 20,
+		// needs option to be set by user
+		UNCONFIGURED= 30,
+		// ready to start a process
+		READY		= 40,
+		// acquiring/processing/outputting
+		PROCESSING	= 50,
+		// processing done;
+		DONE		= 60;
+    }
+
+	public struct Point {
+		public double x;
+		public double y;
+	}
 
-		private string get_enum_nick(GLib.Type enum_type,
-									int value)
-		{
-			EnumClass klass = (EnumClass) enum_type.class_ref();
-			weak EnumValue evalue = klass.get_value(value);
-			return evalue.value_nick;
-		}
+	public class Format : GLib.Object {
+		public weak string	name;
+		public weak string	desc;
+		public weak string	domain;
+		public weak string	icon_name;
+		public string[]		mime_types;
+		public string[]		suffixes;
 
-		private void warn_unsupported_unit(Unit unit)
+		public Format(string name, string desc, string domain, string icon_name, string[] mime_types, string[] suffixes)
 		{
-			warning("Unit %s conversion not supported.",
-					get_enum_nick(typeof(Unit), unit));
+			this.name		= name;
+			this.desc		= desc;
+			this.domain		= domain;
+			this.icon_name	= icon_name;
+			this.mime_types	= mime_types;
+			this.suffixes	= suffixes;
 		}
+	}
 
-		/**
-		 * gnome_scan_convert:
-		 * @val:	the value to convert
-		 * @from:	the current @val unit
-		 * @to:		the target unit fro @val
-		 * @res:	the resolution in dpi
-		 *
-		 * Convert @val from @from unit to @to at @res resolution. Useful for
-		 * preview area, #GnomeScanScanner, etc.
-		 **/
-		public double convert(double val,
-							  Unit from,
-							  Unit to,
-							  double res)
-		{
-			if (from == to)
-				return val;
+	private const double MM_PER_INCH	= 25.4;
 
-			switch(from) {
-			case Unit.NONE:
-			case Unit.BIT:
-			case Unit.PERCENT:
-			case Unit.MICROSECOND:
-			case Unit.DPI:
-				warn_unsupported_unit(from);
-				return val;
-			default:
-				switch (to) {
-				case Unit.NONE:
-				case Unit.BIT:
-				case Unit.PERCENT:
-				case Unit.MICROSECOND:
-				case Unit.DPI:
-					warn_unsupported_unit(to);
-					return val;
-				default:
-					return convert_from_mm (convert_to_mm (val, from, res),
-											to, res);
-				}
+	// debugging facility, return the nickk of value.
+	public string enum_get_nick(GLib.Type enum_type,
+								int value)
+	{
+		EnumClass klass = (EnumClass) enum_type.class_ref();
+		weak EnumValue enum_value = klass.get_value(value);
+		if (enum_value == null)
+			return "%i".printf(value);
+		else
+			return enum_value.value_nick;
+	}
+
+	// debugging facility. return the list of flags in value as "{nick,nick}"
+	public string flags_get_nicks(GLib.Type flags_type,
+								 int value)
+	{
+		FlagsClass klass = (FlagsClass) flags_type.class_ref();
+		weak FlagsValue flags_value = null;
+		string nicks = "{";
+		for (; value > 0 && ((flags_value = klass.get_first_value(value)) != null); value = value ^ flags_value.value) {
+			if (flags_value != null) {
+				if (nicks.len() > 1)
+					nicks = nicks.concat(",");
+				nicks = nicks.concat(flags_value.value_nick);
 			}
 		}
 
-		public double convert_from_mm(double val,
-									  Unit to,
-									  double res)
-		{
+		return nicks.concat("}");
+	}
+
+	private void warn_unsupported_unit(Unit unit)
+	{
+		warning("Unit %s conversion not supported.",
+				enum_get_nick(typeof(Unit), unit));
+	}
+
+	/**
+	 * gnome_scan_convert:
+	 * @val:	the value to convert
+	 * @from:	the current @val unit
+	 * @to:		the target unit fro @val
+	 * @res:	the resolution in dpi
+	 *
+	 * Convert @val from @from unit to @to at @res resolution. Useful for
+	 * preview area, #GnomeScanScanner, etc.
+	 **/
+	public double convert(double val,
+						  Unit from,
+						  Unit to,
+						  double res)
+	{
+		if (from == to)
+			return val;
+
+		switch(from) {
+		case Unit.NONE:
+		case Unit.BIT:
+		case Unit.PERCENT:
+		case Unit.MICROSECOND:
+		case Unit.DPI:
+			warn_unsupported_unit(from);
+			return val;
+		default:
 			switch (to) {
 			case Unit.NONE:
 			case Unit.BIT:
@@ -105,101 +147,115 @@
 			case Unit.DPI:
 				warn_unsupported_unit(to);
 				return val;
-			case Unit.MM:
-				return val;
-			case Unit.PIXEL:
-				return val * (MM_PER_INCH / res);
+			default:
+				return convert_from_mm (convert_to_mm (val, from, res),
+										to, res);
 			}
-			return 0;
 		}
+	}
 
-		public double convert_to_mm(double val,
-									Unit from,
-									double res)
-		{
-			switch (from) {
-			case Unit.NONE:
-			case Unit.BIT:
-			case Unit.PERCENT:
-			case Unit.MICROSECOND:
-			case Unit.DPI:
-				warn_unsupported_unit(from);
-				return val;
-			case Unit.MM:
-				return val;
-			case Unit.PIXEL:
-				return val / (MM_PER_INCH / res);
-			}
-			return 0;
+	public double convert_from_mm(double val,
+								  Unit to,
+								  double res)
+	{
+		switch (to) {
+		case Unit.NONE:
+		case Unit.BIT:
+		case Unit.PERCENT:
+		case Unit.MICROSECOND:
+		case Unit.DPI:
+			warn_unsupported_unit(to);
+			return val;
+		case Unit.MM:
+			return val;
+		case Unit.PIXEL:
+			return val * (MM_PER_INCH / res);
 		}
+		return 0;
+	}
 
-		public struct Rectangle {
-			public double	x;
-			public double	y;
-			public double	width;
-			public double	height;
+	public double convert_to_mm(double val,
+								Unit from,
+								double res)
+	{
+		switch (from) {
+		case Unit.NONE:
+		case Unit.BIT:
+		case Unit.PERCENT:
+		case Unit.MICROSECOND:
+		case Unit.DPI:
+			warn_unsupported_unit(from);
+			return val;
+		case Unit.MM:
+			return val;
+		case Unit.PIXEL:
+			return val / (MM_PER_INCH / res);
+		}
+		return 0;
+	}
 
-			private static double max(double a, double b)
-			{
-				return a > b ? a : b;
-			}
+	[Compact]
+	public class Rectangle {
+		public double	x;
+		public double	y;
+		public double	width;
+		public double	height;
 
-			public void	rotate(Rectangle	area,
-							   int		angle)
-			{
-				angle%= 360;
+		public void	rotate(Rectangle	area,
+						   int		angle)
+		{
+			angle%= 360;
 	
-				switch (angle)
-				{
-				case 0:
-					break;
-				case 270:
-					this.width = this.height;
-					this.height = this.width;
-					this.x = this.y;
-					this.y = max(area.width - this.x - this.width, area.x);
-					break;
-				case 180:
-					this.x = max(area.width - this.x - this.width, area.x);
-					this.y = max(area.height - this.y - this.height, area.y);
-					break;
-				case 90:
-					this.width = this.height;
-					this.height = this.width;
-					this.y = this.x;
-					this.x = max(area.height - this.y - this.height, area.y);
-					break;
-				default:
-					warning("%i degree rotation is not supported", angle);
-					break;
-				}
-			}
-
-			public void convert(Unit	from,
-								Unit	to,
-								double	res)
+			switch (angle)
 			{
-				convert_to_mm(from, res);
-				convert_from_mm(to, res);
+			case 0:
+				break;
+			case 270:
+				this.width = this.height;
+				this.height = this.width;
+				this.x = this.y;
+				this.y = double.max(area.width - this.x - this.width, area.x);
+				break;
+			case 180:
+				this.x = double.max(area.width - this.x - this.width, area.x);
+				this.y = double.max(area.height - this.y - this.height, area.y);
+				break;
+			case 90:
+				this.width = this.height;
+				this.height = this.width;
+				this.y = this.x;
+				this.x = double.max(area.height - this.y - this.height, area.y);
+				break;
+			default:
+				warning("%i degree rotation is not supported", angle);
+				break;
 			}
+		}
 
-			public void	convert_to_mm(Unit	from,
-									  double	res)
-			{
-				this.x		= Gnome.Scan.convert_to_mm(this.x,		from, res);
-				this.y		= Gnome.Scan.convert_to_mm(this.y,		from, res);
-				this.width	= Gnome.Scan.convert_to_mm(this.width,	from, res);
-				this.height = Gnome.Scan.convert_to_mm(this.height,	from, res);
-			}
+		public void convert(Unit	from,
+							Unit	to,
+							double	res)
+		{
+			convert_to_mm(from, res);
+			convert_from_mm(to, res);
+		}
 
-			public void	convert_from_mm(Unit	to,
-										double	res)
-			{
-				this.x		= Gnome.Scan.convert_from_mm(this.x,		to, res);
-				this.y		= Gnome.Scan.convert_from_mm(this.y,		to, res);
-				this.width	= Gnome.Scan.convert_from_mm(this.width,	to, res);
-				this.height = Gnome.Scan.convert_from_mm(this.height,	to, res);
-			}
+		public void	convert_to_mm(Unit	from,
+								  double	res)
+		{
+			this.x		= Gnome.Scan.convert_to_mm(this.x,		from, res);
+			this.y		= Gnome.Scan.convert_to_mm(this.y,		from, res);
+			this.width	= Gnome.Scan.convert_to_mm(this.width,	from, res);
+			this.height = Gnome.Scan.convert_to_mm(this.height,	from, res);
+		}
+
+		public void	convert_from_mm(Unit	to,
+									double	res)
+		{
+			this.x		= Gnome.Scan.convert_from_mm(this.x,		to, res);
+			this.y		= Gnome.Scan.convert_from_mm(this.y,		to, res);
+			this.width	= Gnome.Scan.convert_from_mm(this.width,	to, res);
+			this.height = Gnome.Scan.convert_from_mm(this.height,	to, res);
 		}
 	}
 }

Added: trunk/lib/gnome-scan-dialog.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-dialog.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,461 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+/**
+ * SECTION: gnome-scan-dialog
+ * @short_description: Scan configuration dialog
+ * @include: gnome-scan.h
+ *
+ **/
+
+using Gtk;
+using Gdk;
+
+namespace Gnome.Scan {
+    enum Pages {
+		GENERAL,
+		FRONT_SCANNER,
+		FRONT_SINK,
+		PREVIEW,
+		ADVANCED,
+		PROCESSING,
+		OUTPUT,
+		ACQUISITION,
+		LAST
+    }
+
+    public class Dialog : Gtk.Window {
+		public	Job job { get; set construct; }
+
+		private Notebook			notebook;
+		private Box					acquisition_page;
+		private AcquisitionWidget	acquisitor;
+
+		// buttons
+		private Button bcancel;
+		private Button bclose;
+		private Button bscan;
+		private Button bnext;
+		private Button bback;
+
+		// tabs
+		private Widget[]	pages;
+
+		// nodes
+		private Gnome.Scan.Node scanner	= null;
+
+		// general
+		private ScannerSelector selector;
+
+		construct {
+			Box 		box;
+
+			this.border_width	= 6;
+			this.default_width	= 320;
+			this.default_height	= 420;
+			this.icon_name		= "scanner";
+			this.title			= _("Scan");
+			this.window_position= WindowPosition.CENTER;
+			this.delete_event  += this.on_window_delete_event;
+			this.type_hint		= Gdk.WindowTypeHint.DIALOG;
+
+			this.job.notify["scanner"]	+= this.on_scanner_selected;
+			this.job.notify["status"]	+= this.on_status_changed;
+
+			box = new VBox(false, 6);
+			box.border_width = 6;
+			this.add(box);
+
+			// notebook
+			this.notebook = new Notebook();
+			this.notebook.border_width = 6;
+			box.pack_start(this.notebook, true, true, 0);
+
+			this.acquisition_page = new VBox(false, 6);
+			this.acquisition_page.no_show_all = true;
+			box.pack_start(this.acquisition_page, true, true, 0);
+
+			// build basic UI
+			this.pages = new Widget[Pages.LAST];
+			this.build_general_tab();
+			this.build_scanner_page();
+			this.build_node_ui(this.job.sink);
+
+			// buttons
+			this.add_buttons(box);
+		}
+		
+		public Dialog(Gtk.Window? parent, Job job)
+		{
+			this.job = job;
+
+			if (parent != null) {
+				this.set_transient_for(parent);
+				this.window_position = Gtk.WindowPosition.CENTER_ON_PARENT;
+			}
+		}
+
+		public void run()
+		{
+			this.selector.probe_scanners();
+			this.init_buttons();
+			this.show_all();
+			this.window.set_cursor(new Cursor(CursorType.WATCH));
+			Gtk.main();
+		}
+
+
+		// INTERNAL
+		private void add_buttons(Box container)
+		{
+			ButtonBox	button_box;
+
+			button_box = new HButtonBox();
+			button_box.spacing = 6;
+			button_box.layout_style = ButtonBoxStyle.END;
+			container.pack_start(button_box, false, true, 0);
+
+			this.bclose	= this.add_button(button_box, Gtk.STOCK_CLOSE);
+			this.bclose.clicked+= this.on_button_close_clicked;
+			// TODO: register stock item "scan".
+			this.bscan	= this.add_button(button_box, Gtk.STOCK_APPLY);
+			this.bscan.clicked+= this.on_button_scan_clicked;
+			this.bback	= this.add_button(button_box, Gtk.STOCK_EDIT);
+			this.bback.clicked+= this.on_button_back_clicked;
+			this.bcancel = this.add_button(button_box, Gtk.STOCK_CANCEL);
+			this.bcancel.clicked+= this.on_button_cancel_clicked;
+			this.bnext	= this.add_button(button_box, Gtk.STOCK_GO_FORWARD);
+			this.bnext.clicked+= this.on_button_next_clicked;
+		}
+
+		private Button add_button(Box button_box, string stock_id)
+		{
+			Button button = new Button.from_stock(stock_id);
+			button.sensitive = false;
+			button_box.pack_start(button, false, false, 0);
+			return button;
+		}
+
+		private Widget build_page(Pages page_id)
+		{
+			if (this.pages[page_id] is Widget)
+				return this.pages[page_id];
+
+			switch(page_id) {
+			case Pages.GENERAL:
+				this.build_general_tab();
+				break;
+			case Pages.FRONT_SCANNER:
+				this.build_scanner_page();
+				break;
+			case Pages.FRONT_SINK:
+				this.build_sink_page();
+				break;
+			case Pages.ADVANCED:
+			case Pages.PROCESSING:
+			case Pages.OUTPUT:
+				this.build_option_page(page_id);
+				break;
+			case Pages.ACQUISITION:
+				this.build_acquisition_page();
+				break;
+			default:
+				warning("Don't know how to build %s page",
+						enum_get_nick(typeof(Pages), page_id));
+				break;
+			}
+			return this.pages[page_id];
+		}
+
+		private void build_general_tab()
+		{
+			Widget page;
+			Box box;
+
+			page = box = new VBox(false, 6);
+			box.border_width = 12;
+
+			this.selector = new ScannerSelector(this.job);
+			this.selector.probe_done += this.on_probe_done;
+			box.pack_start(this.selector, true, true, 0);
+
+			this.append_page(Pages.GENERAL, _("_General"), page);
+		}
+
+		private void build_scanner_page()
+		{
+			OptionPage opage = new OptionHPage();
+			Box box = (Box) this.pages[Pages.GENERAL];
+			box.pack_start(opage, false, true, 0);
+			this.append_page(Pages.FRONT_SCANNER, null, opage);
+		}
+
+		private void build_sink_page()
+		{
+			OptionPage opage = new OptionHPage();
+			Box box = (Box) this.pages[Pages.GENERAL];
+			box.pack_start(opage, false, true, 0);
+			this.append_page(Pages.FRONT_SINK, null, opage);
+		}
+
+		private void build_acquisition_page()
+		{
+			this.acquisitor = new AcquisitionWidget(this.job,
+													_("Acquisition"),
+													_("The software now acquires and processes images according to settings."),
+													"scanner");
+			this.acquisition_page.pack_start(this.acquisitor, true, true, 0);
+
+			var page = new OptionVPage() as Container;
+			page.border_width = 12;
+			this.acquisition_page.pack_start(page, false, true, 0);
+
+			this.pages[Pages.ACQUISITION] = page;
+		}
+
+		private void build_option_page(Pages page_id)
+		{
+			string label;
+
+			switch(page_id) {
+			case Pages.ADVANCED:
+				label = _("_Advanced");
+				break;
+			case Pages.PROCESSING:
+				label = _("_Processing");
+				break;
+			case Pages.OUTPUT:
+				label = _("_Output");
+				break;
+			default:
+				return;
+			}
+
+			this.append_page(page_id, label, new OptionVPage());
+		}
+
+		private void append_page(int tab, string? label, Widget page)
+		{
+			if (this.pages[tab] != null)
+				return;
+
+			if (label != null) {
+				Widget tab_label = new Label.with_mnemonic(label);
+				this.notebook.append_page(page, tab_label);
+			}
+			this.pages[tab] = page;
+			page.show_all();
+		}
+
+		private void build_node_ui(Node node)
+		{
+			Pages page_id = Pages.ADVANCED;
+			OptionPage page;
+
+			foreach(Option option in node.options) {
+				if (option.hint == OptionHint.HIDDEN)
+					continue;
+
+				page_id = this.get_page_id_for_option(node, option);
+				page = (OptionPage) this.build_page(page_id);
+				if (!(page is OptionPage))
+					continue;
+
+				page.pack_option(option);
+				page.show_all();
+			}
+		}
+
+		private Pages get_page_id_for_option(Node node, Option option)
+		{
+			switch(option.hint) {
+			case OptionHint.HIDDEN:
+				warning("Option %s of node %s is hidden.", node.get_type().name(), option.name);
+				return Pages.LAST;
+			case OptionHint.PRIMARY:
+			case OptionHint.REPEAT:
+				if (node is Scanner)
+					return Pages.FRONT_SCANNER;
+				else if (node is Sink)
+					return Pages.FRONT_SINK;
+				else
+					return Pages.ADVANCED;
+			case OptionHint.SECONDARY:
+				return Pages.ADVANCED;
+			case OptionHint.PREVIEW:
+				return Pages.PREVIEW;
+			}
+			return Pages.ADVANCED;
+		}
+
+		private void destroy_node_ui(Node node)
+		{
+		}
+
+		private void init_buttons()
+		{
+			this.bclose.no_show_all	= false;
+			this.bclose.show();
+			this.bscan.no_show_all	= false;
+			this.bscan.show();
+			
+			this.bback.no_show_all	= true;
+			this.bback.hide();
+			this.bcancel.no_show_all= true;
+			this.bcancel.hide();
+			this.bnext.no_show_all	= true;
+			this.bnext.hide();
+		}
+
+		private void scan()
+		{
+			try {
+				Timeout.add(42, this.acquisitor.monitor_job);
+				Thread.create(this.job_run_thread, false);
+			}
+			catch (ThreadError e) {
+				// run in same thread ?
+				warning("Unable to create thread for acquiring");
+			}
+		}
+
+		private void back()
+		{
+			this.notebook.no_show_all			= false;
+			this.acquisition_page.no_show_all	= true;
+			this.acquisition_page.hide();
+			this.init_buttons();
+			this.notebook.show_all();
+		}
+		
+		private void close()
+		{
+			Gtk.main_quit();
+		}
+
+
+		private void* job_run_thread()
+		{
+			this.job.run();
+
+			return null;
+		}
+
+		// CALLBACKS
+		private void on_probe_done(ScannerSelector selector)
+		{
+			this.window.set_cursor(null);
+		}
+
+		private void on_scanner_selected(Job job, ParamSpec pspec)
+		{
+			if (job.scanner == this.scanner)
+				return;
+
+			if (this.scanner != null)
+				this.destroy_node_ui(this.scanner);
+
+			this.scanner = job.scanner;
+
+			if (this.scanner != null)
+				this.build_node_ui(this.scanner);
+		}
+
+		private void on_status_changed(Job job, ParamSpec pspec)
+		{
+			debug("job status updated to %s", enum_get_nick(typeof(Status), job.status));
+			switch(job.status) {
+			case Status.UNCONFIGURED:
+				this.bclose.sensitive	= true;
+				this.bscan.sensitive	= false;
+				break;
+			case Status.READY:
+				this.bclose.sensitive	= true;
+				this.bscan.sensitive	= true;
+				break;
+			case Status.PROCESSING:
+				this.bclose.sensitive	= false;
+				this.bscan.sensitive	= false;
+				this.bscan.no_show_all	= true;
+				this.bscan.hide();
+
+				this.bcancel.no_show_all= false;
+				this.bcancel.sensitive	= true;
+				this.bnext.no_show_all	= false;
+				this.bnext.sensitive	= false;
+				this.bback.no_show_all	= false;
+				this.bback.sensitive	= false;
+				break;
+			case Status.DONE:
+				this.bclose.sensitive	= true;
+				this.bback.sensitive	= true;
+				this.bcancel.sensitive	= false;
+				this.bnext.sensitive	= true;
+				this.bscan.sensitive	= true;
+				break;
+			default:
+				debug("Job status set to %s", enum_get_nick(typeof(Status), job.status));
+				break;
+			}
+
+			this.show_all();
+		}
+
+		private void on_button_scan_clicked(Button button)
+		{
+			this.build_page(Pages.ACQUISITION);
+			this.notebook.no_show_all = true;
+			this.notebook.hide();
+			this.acquisition_page.no_show_all = false;
+			this.show_all();
+			this.scan();
+		}
+
+		private void on_button_next_clicked(Button button)
+		{
+			this.scan();
+		}
+
+		private void on_button_cancel_clicked(Button button)
+		{
+			this.job.cancel();
+			this.back();
+		}
+
+		private void on_button_back_clicked(Button button)
+		{
+			this.job.end();
+			this.back();
+		}
+
+		private void on_button_close_clicked(Button button)
+		{
+			this.job.end();
+			this.close();
+		}
+
+		private bool on_window_delete_event(Gnome.Scan.Dialog window, Event evt)
+		{
+			this.close();
+			return false;
+		}
+    }
+}

Added: trunk/lib/gnome-scan-init.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-init.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,60 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
+using Config;
+using GLib;
+using Gegl;
+using Gtk;
+
+namespace Gnome.Scan {
+	// should be private !
+	public ModuleManager module_manager;
+	/**
+	 * Calls g_thread_init(), must be called before gtk_init(), but
+	 * after g_type_init().
+	 */
+    public void init([CCode (array_length_pos = 0.9)]ref weak string[] argv)
+    {
+		string module_path;
+
+		// TODO: i18n
+		// TODO: install stock items
+
+		Gegl.init(ref argv);
+
+		option_manager = new OptionManager();
+
+		module_path = string.join(GLib.Path.SEARCHPATH_SEPARATOR_S, MODULE_DIR, "modules", "../modules");
+		module_manager = new ModuleManager(module_path);
+
+		if (!GLib.Thread.supported())
+			GLib.Thread.init(null);
+    }
+
+    public void exit()
+    {
+		module_manager = null;
+		option_manager = null;
+
+		Gegl.exit();
+		// TODO: uninstall stock items
+    }
+}
\ No newline at end of file

Added: trunk/lib/gnome-scan-job.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-job.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,218 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using GLib;
+using Gegl;
+
+namespace Gnome.Scan {
+	public class Job : Object {
+		public Status status {get; set; default = Status.INITIALIZING;}
+
+		private Scanner _scanner;
+		public Scanner scanner {
+			get {
+				return this._scanner;
+			}
+			set construct {
+				Scanner old = this._scanner;
+				this._scanner = value;
+				this.register_node(value, old);
+			}
+		}
+
+		private Sink _sink;
+		public Sink sink {
+			get {
+				return this._sink;
+			}
+			set {
+				Sink old = this._sink;
+				this._sink = value;
+				this.register_node(value, old);
+			}
+		}
+
+		private double 	_progress = 0;
+		public double progress {
+			get {
+				return this._progress;
+			}
+		}
+
+		private bool cancelled = false;
+		private SList<Gegl.Node> graph;
+		private Gegl.Node gegl_sink;
+		private Gegl.Processor processor = null;
+		private SList<Gnome.Scan.Node> nodes = null;
+
+		construct {
+			this.graph = null;
+		}
+
+		public Job(Sink sink)
+		{
+			this.sink = sink;
+		}
+
+		public bool is_running()
+		{
+			return this._status == Status.PROCESSING;
+		}
+
+		public void run()
+		{
+			this.cancelled = false;
+			int count = 0;
+
+			if (!this.is_running()) {
+				foreach(Gnome.Scan.Node node in this.nodes) {
+					node.start_scan();
+				}
+				this.status = Status.PROCESSING;
+			}
+
+			while(run_once())
+				count++;
+
+			debug("%d frames acquired", count);
+			this.status = Status.DONE;
+		}
+
+		public void end()
+		{
+			if (!this.is_running())
+				return;
+
+			foreach(Gnome.Scan.Node node in this.nodes) {
+				node.end_scan();
+			}
+
+			this.status = Status.READY;
+		}
+
+		public void cancel()
+		{
+			this.cancelled = true;
+		}
+
+		public bool run_once()
+		{
+			foreach(Gnome.Scan.Node node in this.nodes) {
+				if (!node.start_frame() && node is Gnome.Scan.Scanner) {
+					return false;
+				}
+			}
+
+			processor = new Gegl.Processor(this.gegl_sink, null);
+			while(!this.cancelled && processor.work(out this._progress))
+				debug("%.2f%%", this._progress);
+
+			foreach(Gnome.Scan.Node node in this.nodes)
+				node.end_frame();
+
+			return true;
+		}
+
+
+		private void register_node(Node? node, Node? old)
+		{
+			if (old != null) {
+				old.notify["status"]	-= this.check_nodes_status;
+				old.notify["graph"]		-= this.build_graph;
+				this.nodes.remove(old);
+			}
+
+			if (node != null) {
+				node.notify["status"]	+= this.check_nodes_status;
+				node.notify["graph"]	+= this.build_graph;
+
+				if (node is Scanner)
+					this.nodes.prepend(node);
+				else if (node is Sink)
+					this.nodes.append(node);
+				else {
+					weak SList last = this.nodes.last();
+					if (last.data is Sink)
+						this.nodes.insert_before(last, node);
+					else
+						this.nodes.append(node);
+				}
+			}
+
+			this.check_nodes_status();
+			this.build_graph();
+		}
+
+		private void build_graph()
+		{
+			if ((int)this._status < (int)Status.READY)
+				return;
+
+			// remove all children from current graph
+			foreach(Gegl.Node node in this.graph) {
+				node.disconnect("input");
+			}
+			this.graph = null;
+
+			// list all nodes
+			weak Gegl.Node prev = null;
+			foreach(Gnome.Scan.Node gsnode in this.nodes) {
+				foreach(Gegl.Node gnode in gsnode.nodes) {
+					this.graph.append(gnode);
+					if (prev != null) {
+						debug("Link %s to %s", prev.operation, gnode.operation);
+						prev.link(gnode);
+					}
+					prev = gnode;
+				}
+			}
+			this.gegl_sink = prev;
+			debug("Sink is %s", this.gegl_sink.operation);
+		}
+
+		private void check_nodes_status()
+		{
+			Status status;
+			if (this._scanner == null || this._sink == null)
+				this.status = Status.UNCONFIGURED;
+			else {
+				status = Status.READY;
+				if (this._scanner != null && ((int)this._scanner.status) < ((int)status))
+					status = this._scanner.status;
+
+				if (this._sink != null && ((int)this._sink.status) < ((int)status))
+					status = this._sink.status;
+
+				var redo_graph = (int)status > (int)this._status && status == Status.READY;
+
+				this.status = status;
+
+				// auto cancel job is status is not ready (failure,
+				// etc.)
+				if ((int)status < (int)Status.READY)
+					this.cancelled = true;
+
+				if (redo_graph)
+					this.build_graph();
+			}
+		}
+	}
+}
\ No newline at end of file

Modified: trunk/lib/gnome-scan-module-helper.h
==============================================================================
--- trunk/lib/gnome-scan-module-helper.h	(original)
+++ trunk/lib/gnome-scan-module-helper.h	Sat Dec  6 17:38:48 2008
@@ -1,18 +1,18 @@
-/* Gnome Scan - Scan as easy as you print
- * Copyright  2007  Ãtienne Bersac <bersace03 laposte net>
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
  *
- * Gnome Scan is free software; you can redistribute it and/or
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
  * 
- * gnome-scan is distributed in the hope that it will be useful,
+ * GNOME Scan 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 gnome-scan.  If not, write to:
+ * License along with GNOME Scan. If not, write to:
  *
  *	the Free Software Foundation, Inc.
  *	51 Franklin Street, Fifth Floor
@@ -75,35 +75,38 @@
  *
  * See: G_DEFINE_TYPE
  **/
-#define GS_DEFINE_MODULE_TYPE(TN, t_n, T_P)			static void     t_n##_init       (TN      *self);	\
-static void     t_n##_class_init (TN##Class *klass);	\
-\
-static GType t_n##_type = 0;	\
-GType	\
-t_n##_get_type () \
-{ return t_n##_type; } \
-\
-void \
-t_n##_register_type (GTypeModule *module)	\
-{	\
-  if (!t_n##_type)\
-    {	\
-      static const GTypeInfo type_info =	\
-      {	\
-        sizeof (TN##Class),						\
-        (GBaseInitFunc) NULL,					\
-        (GBaseFinalizeFunc) NULL,				\
-        (GClassInitFunc) t_n##_class_init, 		\
-        NULL,           /* class_finalize */	\
-        NULL,           /* class_data     */	\
-        sizeof (TN),							\
-        0,              /* n_preallocs    */	\
-        (GInstanceInitFunc) t_n##_init			\
-      }; \
-\
-      t_n##_type =	\
-        g_type_module_register_type (module, T_P,	\
-                                     g_intern_static_string (#TN), &type_info, 0);	\
-    } \
-}
+#define GS_DEFINE_MODULE_TYPE(TN, t_n, T_P)				\
+	static GType t_n##_type = 0;					\
+	static gpointer t_n##_parent_class = NULL;			\
+	static void     t_n##_init (TN *self);				\
+	static void     t_n##_class_init (TN##Class *klass);		\
+	static void	t_n##_class_intern_init(gpointer klass)		\
+	{								\
+		t_n##_parent_class = g_type_class_peek_parent(klass);	\
+		t_n##_class_init((TN##Class*) klass);			\
+	}								\
+									\
+	GType								\
+	t_n##_get_type ()						\
+	{ return t_n##_type; }						\
+									\
+	void								\
+	t_n##_register_type (GTypeModule *module)			\
+	{								\
+		if (!t_n##_type) {					\
+			const GTypeInfo type_info = {			\
+				.class_size = sizeof (TN##Class),	\
+				.base_init = NULL,			\
+				.base_finalize = NULL,			\
+				.class_init = (GClassInitFunc) t_n##_class_intern_init, \
+				.class_finalize = NULL,			\
+				.class_data = NULL,			\
+				.instance_size = sizeof (TN),		\
+				.n_preallocs = 0,			\
+				.instance_init = (GInstanceInitFunc) t_n##_init \
+			};						\
+		 							\
+			t_n##_type = g_type_module_register_type (module, T_P, #TN, &type_info, 0); \
+		}							\
+	}
 

Added: trunk/lib/gnome-scan-module-manager.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-module-manager.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,133 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using GLib;
+
+namespace Gnome {
+    namespace Scan {
+		
+		/**
+		 * SECTION: gnome-scan-module-manager
+		 * @short_description: Finding installed modules
+		 *
+		 * The #GnomeScanModuleManager search in a list of path shared object,
+		 * and instanciate a #GnomeScanModule for each shared object. Upon
+		 * initialization, the #GnomeScanModule will register new GTypes. This
+		 * implementation is meant to be portable, but never tested on other
+		 * plateform that GNU/Linux.
+		 **/
+		public class ModuleManager : Object {
+			
+			construct {
+				if (path != null)
+					query_modules ();
+			}
+			
+			/**
+			 * GnomeScanModuleManager:path:
+			 *
+			 * The search path where are installed #GnomeScanModule shared
+			 * object. A search path is a string formed by a list of absolute
+			 * path to directory separated by #G_SEARCHPATH_SEPARATOR.
+			 **/
+			[Description(nick="Path", blurb="Module path")]
+			public string path { get; construct set; }
+
+			private SList<TypeModule> modules;
+			
+			/**
+			 * gnome_scan_module_manager_new:
+			 * @path: Search path.
+			 * 
+			 * Create a new #GnomeScanModuleManager which will handle @path.
+			 * 
+			 * Returns: a new #GnomeScanModuleManager
+			 **/
+			public ModuleManager (string path) {
+				this.path = path;
+			}
+
+			/**
+			 * gnome_scan_module_manager_query_modules:
+			 * @self: a #GnomeScanModuleManager
+			 * 
+			 * Search for shared objects in path, instanciate and initialize a
+			 * #GnomeScanModule for each shared object. Note that it won't search
+			 * in subdirectories.
+			 **/
+			public void query_modules () {
+				Module module;
+				Dir dir = null;
+				string[] paths = path.split (GLib.Path.SEARCHPATH_SEPARATOR_S);
+				string name;
+				string filename;
+	
+				foreach (string path in paths) {
+					try {
+						dir = Dir.open (path, 0);
+					}
+					catch (GLib.Error error) {
+						/* Show warning only for absolute path, else should be devel pathâ */
+						if (path[0] == '/')
+							warning("%s", error.message);
+					}
+
+					if (dir == null)
+						continue;
+				  
+					/* Scan for lib*.{so,la} */
+					while ((name = dir.read_name ()) != null) {
+						if (is_valid_module_name (name)) {
+							filename = Path.build_filename (path, name);
+							module = new Module (filename);
+							
+							if (!module.use ()) {
+								warning ("%s", GLib.Module.error());
+								// throw exception ?
+							}
+							modules.append (module);
+						}
+					}
+				}
+			}
+			
+			/**
+			 * gnome_scan_module_manager_unload_modules:
+			 * @self: a #GnomeScanModuleManager
+			 * 
+			 * Search for shared objects in path, instanciate and initialize a
+			 * #GnomeScanModule for each shared object. Note that it won't search
+			 * in subdirectories.
+			 **/
+			public void unload_modules () {
+				foreach (TypeModule module in modules)
+				module.unuse ();
+			}
+
+			private static bool is_valid_module_name (string name)
+			{
+				return name.has_prefix ("lib")
+				&& (name.has_suffix (GLib.Module.SUFFIX)
+					|| name.has_suffix (".la"));
+			}
+		}
+    }
+}

Modified: trunk/lib/gnome-scan-module.vala
==============================================================================
--- trunk/lib/gnome-scan-module.vala	(original)
+++ trunk/lib/gnome-scan-module.vala	Sat Dec  6 17:38:48 2008
@@ -1,70 +1,89 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
 using GLib;
 
-namespace Gnome {
-	namespace Scan {
+namespace Gnome.Scan {
 		
-		/**
-		 * SECTION: gnome-scan-module
-		 * @short_description: Module loading and initialization
-		 *
-		 * A module represent the library opened with #GModule where are
-		 * stored a list of #GObjects.
-		 **/
-		public class Module : TypeModule {
-
-			[Description(nick="Filename", blurb="Library filename for use with GModule")]
-			public string filename { get; construct set; }
-
-			private GLib.Module library;
-			private InitFunc init;
-			private	FinalizeFunc finalize;
-
-			public delegate void InitFunc (Module module);
-			public delegate void FinalizeFunc ();
-
-			public override bool load () {
-				library = GLib.Module.open (filename, ModuleFlags.BIND_MASK);
-				if (library == null) {
-					warning (GLib.Module.error());
-					return false;
-				}
+	/**
+	 * SECTION: gnome-scan-module
+	 * @short_description: Module loading and initialization
+	 *
+	 * A module represent the library opened with #GModule where are
+	 * stored a list of #GObjects.
+	 **/
+	public class Module : TypeModule {
+
+		[Description(nick="Filename", blurb="Library filename for use with GModule")]
+		public string filename { get; construct set; }
+
+		private GLib.Module library;
+		private InitFunc init;
+		private	FinalizeFunc finalize;
+
+		public delegate void InitFunc (Module module);
+		public delegate void FinalizeFunc ();
+
+		public override bool load () {
+			library = GLib.Module.open (filename, ModuleFlags.BIND_MASK);
+			if (library == null) {
+				warning("%s",GLib.Module.error());
+				return false;
+			}
 				
-				void * init_function;
-				void * finalize_function;
+			void * init_function = null;
+			void * finalize_function = null;
 				
-				if (!library.symbol ("gnome_scan_module_init", out init_function) ||
-					!library.symbol ("gnome_scan_module_finalize", out finalize_function))
-				{
-					warning ("%s does not contain a valid %s", filename, ( this.get_type().name() ));
-					return false;
-				}
+			if (!library.symbol ("gnome_scan_module_init", out init_function) ||
+				!library.symbol ("gnome_scan_module_finalize", out finalize_function))
+			{
+				warning ("%s does not contain a valid %s", filename, ( this.get_type().name() ));
+				return false;
+			}
 				
-				init = (InitFunc) init_function;
-				finalize = (FinalizeFunc) finalize_function;
+			init = (InitFunc) init_function;
+			finalize = (FinalizeFunc) finalize_function;
 				
-				init (this);	
+			init (this);	
 				
-				return true;
-			}
+			return true;
+		}
 			
-			public override void unload () {
-				finalize ();
-			}
+		public override void unload () {
+			finalize ();
+		}
 			
 
-			/**
-			 * gnome_scan_module_new:
-			 * @filename: The path to shared object
-			 * 
-			 * Open and initialize a new module. This function should be used only
-			 * by #GnomeScanModuleManager.
-			 * 
-			 * Returns: a new #GnomeScanModule
-			 **/
-			public Module (string filename) {
-				this.filename = filename;
-			}
-			
+		/**
+		 * gnome_scan_module_new:
+		 * @filename: The path to shared object
+		 * 
+		 * Open and initialize a new module. This function should be used only
+		 * by #GnomeScanModuleManager.
+		 * 
+		 * Returns: a new #GnomeScanModule
+		 **/
+		public Module (string filename) {
+			this.filename = filename;
 		}
+			
 	}
-}
\ No newline at end of file
+}

Added: trunk/lib/gnome-scan-node.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-node.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,118 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using GLib;
+using Gegl;
+
+namespace Gnome.Scan {
+	public abstract class Node : Object {
+		public Status status	{set; get; default = Status.INITIALIZING;}
+		public string? message	{set; get;}
+
+		private SList<Option> _options;
+		public SList<Option>	options {
+			get {
+				return this._options;
+			}
+		}
+
+		// Subgraph owned by this node. Subclass must create a Gegl
+		// pipeline in this graph.
+		private SList<Gegl.Node> _nodes;
+		public SList<Gegl.Node> nodes {
+			get {
+				return this._nodes;
+			}
+		}
+
+		public virtual void start_scan()
+		{
+		}
+
+		// scanner returns true whend new frame is to acquire. Allows
+		// nodes to prepare next frame (e.g. next filename, next page
+		// in pdf, etc.) for multi-frame acquisition
+		public virtual bool start_frame()
+		{
+			return false;
+		}
+
+		public virtual void end_frame()
+		{
+		}
+
+		public virtual void end_scan()
+		{
+		}
+
+		// Let message to null and the message will be determined from
+		// status.
+		public void update_status(Status status, string? message)
+		{
+			if (message == null) {
+				switch(status) {
+				case Status.UNKNOWN:
+					this.message = _("Unknown");
+					break;
+				case Status.FAILED:
+					this.message = _("Failed");
+					break;
+				case Status.INITIALIZING:
+					this.message = _("Initializing");
+					break;
+				case Status.UNCONFIGURED:
+					this.message = _("Unconfigured");
+					break;
+				case Status.READY:
+					this.message = _("Ready");
+					break;
+				case Status.PROCESSING:
+					this.message = _("Processing");
+					break;
+				case Status.DONE:
+					this.message = _("Done");
+					break;
+				}
+			}
+			else {
+				this.message = message;
+			}
+			this.status = status;
+		}
+
+		public void install_option(Option option)
+		{
+			this._options.append(option);
+		}
+
+		public void append_node(Gegl.Node node)
+		{
+			this._nodes.append(node);
+			// notify ?
+		}
+
+		public void remove_node(Gegl.Node node)
+		{
+			this._nodes.remove(node);
+			// notify ?
+		}
+	}
+}
\ No newline at end of file

Added: trunk/lib/gnome-scan-option-box.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-option-box.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,117 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using Gtk;
+
+namespace Gnome.Scan {
+    public class OptionBox : VBox {
+		public string label {get; construct set;}
+		public bool expand {set; get; default = false;}
+
+		// The actual box containing option widget.
+		Table table;
+		int child_count = 0;
+		int child_visible_count = 0;
+		int child_expanding_count = 0;
+
+		construct {
+			this.spacing = 6;
+			this.no_show_all = true;
+			Label label = new Label(null);
+			label.set_markup("<b>%s</b>".printf(this.label));
+			label.set_alignment((float)0, (float)0.5);
+			this.pack_start(label, false, false, 0);
+			Alignment alignment = new Alignment(0, 0, 1, 1);
+			alignment.set_padding(0, 0, 24, 0);
+			this.pack_start(alignment, true, true, 0);
+			this.table = new Table(0, 2, false);
+			this.table.set_col_spacings(6);
+			this.table.set_row_spacings(4);
+			alignment.add(this.table);
+		}
+
+		public OptionBox(string label)
+		{
+			this.label = label;
+		}
+
+		public void pack_option(Option option)
+		{
+			GLib.Type wtype = option_manager.get_widget_type_for(option);
+			if (!wtype.is_a(typeof(Gtk.Widget))) {
+				warning("No widget for option %s", option.name);
+				return;
+			}
+
+			OptionWidget widget = (OptionWidget) new Gtk.Widget(wtype, "option", option);
+			widget.hide += this.on_option_widget_visibility_changed;
+			widget.show += this.on_option_widget_visibility_changed;
+
+			this.child_count++;
+			// consider option visible to hide it after attach
+			if (!option.active)
+				this.child_visible_count++;
+
+			// compute attach option
+			var opts = AttachOptions.FILL;
+			if (widget.expand) {
+				opts|=AttachOptions.EXPAND;
+			}
+
+			// insert directly the widget, spanning two columns
+			if (widget.no_label) {
+				this.table.attach(widget, 0, 2, this.child_count-1, this.child_count, opts, opts, 0, 0);
+			}
+			else {
+				// translator: %s is the name of an option and is
+				// prepended before the option widget. Accord ":" to
+				// locale typographic rules.
+				Label label = new Label(_("%s:").printf(option.title));
+				label.set_alignment((float)0, (float)0);
+				this.table.attach(label, 0, 1, this.child_count-1, this.child_count,
+								  AttachOptions.FILL, AttachOptions.FILL, 0, 0);
+				this.table.attach(widget, 1, 2, this.child_count-1, this.child_count,opts, opts, 0, 0);
+			}
+
+			this.on_option_widget_visibility_changed(widget);
+		}
+
+		public void on_option_widget_visibility_changed(OptionWidget widget)
+		{
+			if (widget.expand) {
+				this.child_expanding_count += widget.visible ? +1 : -1;
+				var parent = (Container) this.parent;
+				this.expand = this.child_expanding_count > 0;
+				parent.child_set(this, "expand", this.expand);
+			}
+
+			this.child_visible_count += widget.visible ? +1 : -1;
+			if (this.child_visible_count == 0) {
+				this.no_show_all = true;
+				this.hide();
+			}
+			else {
+				this.no_show_all = false;
+				this.show_all();
+			}
+		}
+    }
+}
\ No newline at end of file

Added: trunk/lib/gnome-scan-option-manager.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-option-manager.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,73 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using GLib;
+
+namespace Gnome.Scan {
+	// option_manager instance.
+	public OptionManager option_manager;
+
+	public class OptionManager : Object {
+		// option name -> Type
+		private HashTable<string,Type>		rules_by_name;
+		// option type -> Type
+		private HashTable<Type,Type>		rules_by_type;
+		// option name -> option instance
+		private HashTable<string,Option>	options;
+
+		construct {
+			this.rules_by_name	= new HashTable<string,Type>(GLib.str_hash, GLib.str_equal);
+			this.rules_by_type	= new HashTable<Type,Type>(GLib.int_hash, GLib.int_equal);
+			this.options		= new HashTable<string,Type>(GLib.str_hash, GLib.str_equal);
+
+			// add default rules ?
+		}
+
+		public void register_option(Option option)
+		{
+			this.options.insert(option.name, option);
+		}
+
+		public void register_rule_by_name(string option_name, Type handler_type)
+		{
+			this.rules_by_name.insert(option_name, handler_type);
+		}
+
+		public void register_rule_by_type(Type option_type, Type handler_type)
+		{
+			this.rules_by_type.insert(option_type, handler_type);
+		}
+
+		public Type get_widget_type_for(Option option)
+		{
+			Type wtype;
+			wtype = this.rules_by_name.lookup(option.name);
+			if (wtype != Type.INVALID)
+				return wtype;
+
+			wtype = this.rules_by_type.lookup(option.get_type());
+			if (wtype != Type.INVALID)
+				return wtype;
+
+			return Type.INVALID;
+		}
+	}
+}

Added: trunk/lib/gnome-scan-option-page.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-option-page.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,86 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
+using GLib; 
+using Gtk;
+
+namespace Gnome.Scan {
+	// waiting for Gtk+ 2.16 for extendings directly Gtk.Box :)
+    public abstract class OptionPage : Alignment {
+		public Box container { get;set construct; }
+		private HashTable<string,OptionBox> boxes;
+		int box_visible_count = 0;
+		int box_expanding_count = 0;
+
+		construct {
+			this.boxes = new HashTable<string,OptionBox>(GLib.str_hash, GLib.str_equal);
+			this.no_show_all = true;
+		}
+
+		public void pack_option(Option option)
+		{
+			OptionBox box = this.boxes.lookup(option.group);
+			if (box == null) {
+				box = new OptionBox(option.group);
+				box.hide += this.on_box_visibility_changed;
+				box.show += this.on_box_visibility_changed;
+				this.box_visible_count++;
+				this.container.pack_start(box, box.expand, true, 0);
+				this.boxes.insert(option.group, box);
+				this.on_box_visibility_changed(box);
+			}
+			box.pack_option(option);
+		}
+
+		private void on_box_visibility_changed(OptionBox box)
+		{
+			if (box.expand) {
+				this.box_expanding_count+= box.visible ? +1 : -1;
+				var parent = (Container) this.parent;
+				parent.child_set(this, "expand", this.box_expanding_count > 0);
+			}
+
+			this.box_visible_count += box.visible ? +1 : -1;
+			if (this.box_visible_count == 0) {
+				this.no_show_all = true;
+				this.hide();
+			}
+			else {
+				this.no_show_all = false;
+				this.show_all();
+			}
+		}
+    }
+
+    public class OptionVPage : OptionPage {
+		construct {
+			this.container = new VBox(false, 6);
+			this.add(this.container);
+		}
+    }
+
+    public class OptionHPage : OptionPage {
+		construct {
+			this.container = new HBox(false, 6);
+			this.add(this.container);
+		}
+    }
+}

Modified: trunk/lib/gnome-scan-option-widget.vala
==============================================================================
--- trunk/lib/gnome-scan-option-widget.vala	(original)
+++ trunk/lib/gnome-scan-option-widget.vala	Sat Dec  6 17:38:48 2008
@@ -1,18 +1,62 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
 using GLib;
 using Gtk;
-//using Gnome.Scan;
 
-namespace Gnome {
-	namespace Scan {
-		/** GnomeScanOptionWidget:
-		 *
-		 * A #GnomeScanOptionWidget expose a #GnomeScanOption to user
-		 * and pass user defined value to #GnomeScanSettings.
-		 */
-		abstract class OptionWidget : HBox {
-			public Option	option		{set construct; get;}
-			public Settings	settings	{set construct; get;}
-			public bool		expand		{set; get;}
+namespace Gnome.Scan {
+	/** GnomeScanOptionWidget:
+	 *
+	 * A #GnomeScanOptionWidget expose a #GnomeScanOption to user
+	 * and pass user defined value to #GnomeScanSettings.
+	 */
+	// TODO: with Gtk+ 2.16, herits directly from Box and let children
+	// decide orientation.
+	public abstract class OptionWidget : HBox {
+		public Option	option		{get; set construct;}
+		public bool		no_label	{get; set; default = false;}
+		public bool		expand		{get; set;}
+
+		construct {
+			this.option.notify["active"] += this.on_option_active_changed;
+			this.auto_hide(option);
+		}
+
+		public OptionWidget(Option option)
+		{
+			this.option = option;
+		}
+
+		private void on_option_active_changed(Option option, ParamSpec pspec)
+		{
+			this.auto_hide(option);
+		}
+
+		private void auto_hide(Option option)
+		{
+			this.no_show_all = !option.active;
+			if (option.active)
+				this.show_all();
+			else
+				this.hide();
 		}
 	}
 }

Modified: trunk/lib/gnome-scan-option.vala
==============================================================================
--- trunk/lib/gnome-scan-option.vala	(original)
+++ trunk/lib/gnome-scan-option.vala	Sat Dec  6 17:38:48 2008
@@ -1,203 +1,53 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
 using GLib;
 
-namespace Gnome {
-	namespace Scan {
-		public const Quark GROUP_SCANNER_FRONT	= Quark.from_string(N_("Scan Options"));
-		public const Quark GROUP_SINK_FRONT		= Quark.from_string(N_("Output Options"));
-		public const Quark GROUP_FORMAT			= Quark.from_string(N_("Format"));
-		public const Quark GROUP_HIDDEN			= Quark.from_string("$$HIDDEN$$");
-		public const Quark GROUP_PREVIEW		= Quark.from_string("$$PREVIEW");
-
-		[Flags]
-		public enum OptionFlags {
-			ACTIVE	= 1 << 0,
-			RANGE	= 1 << 1,
-			ENUM	= 1 << 2
-		}
-	}
-}
-
-public abstract class Gnome.Scan.Option : Object {
-	[Description(nick="Option name",
-				 blurb="Unique name of the option.")]
-	public string	name	{get; set construct;}
-	[Description(nick="Option title",
-				 blurb="Translated title of the option")]
-	public string	title	{get; set construct;}
-	[Description(nick="Description",
-				 blurb="Translated option description")]
-	public string	desc	{get; set construct;}
-	[Description(nick="Translation domaine")]
-	public string	domain	{get; set construct;}
-	[Description(nick="Option group")]
-	public Quark	group	{get; set construct;}
-	public Gnome.Scan.Unit	unit		{get; set construct; default = Unit.NONE;}
-	[Notify]
-		public OptionFlags	flags	{get; set construct;}
-	public int	index	{get; set construct; default = 0;}
-}
-
-public class Gnome.Scan.OptionInt : Gnome.Scan.Option {
-	public int 	default_value {get; set construct; default = 0;}
-	public int	min;
-	public int	max;
-	public int	step;
-	public SList<int>	values;
-
-	public OptionInt(string name,
-					 string title,
-					 string desc,
-					 string domain,
-					 Quark group,
-					 int index,
-					 int default_value,
-					 OptionFlags flags)
-	{
-		this.name	= name;
-		this.title	= title;
-		this.desc	= desc;
-		this.domain = domain;
-		this.group	= group;
-		this.index	= index;
-		this.default_value = default_value;
-		this.flags	= flags;
-	}
-
-	public void set_range(int min, int max, int step)
-	{
-		return_if_fail ((bool) (this.flags & OptionFlags.RANGE));
-
-		this.min = min;
-		this.max = max;
-		this.step = step;
-	}
-
-	public void set_enum(SList values)
-	{
-		return_if_fail ((bool) (this.flags & OptionFlags.ENUM));
-		this.values = values.copy();
-	}
-}
-
-public class Gnome.Scan.OptionDouble : Gnome.Scan.Option {
-	public double default_value {get; set construct; default = 0;}
-	public double	min;
-	public double	max;
-	public double	step;
-	public SList	values;
-
-
-	public OptionDouble(string name,
-						string title,
-						string desc,
-						string domain,
-						Quark group,
-						int index,
-						double default_value,
-						OptionFlags flags)
-	{
-		this.name	= name;
-		this.title	= title;
-		this.desc	= desc;
-		this.domain = domain;
-		this.group	= group;
-		this.index	= index;
-		this.default_value = default_value;
-		this.flags	= flags;
-	}
-
-	public void set_range(double min, double max, double step)
-	{
-		return_if_fail ((bool) (this.flags & OptionFlags.RANGE));
-
-		this.min = min;
-		this.max = max;
-		this.step = step;
-	}
-
-	public void set_enum(SList values)
-	{
-		return_if_fail ((bool) (this.flags & OptionFlags.ENUM));
-		this.values = values.copy();
-	}
-}
-
-public class Gnome.Scan.OptionString : Gnome.Scan.Option {
-	public string default_value {get; set construct; default = null;}
-	public SList	values;
-
-	public OptionString(string name,
-						string title,
-						string desc,
-						string domain,
-						Quark group,
-						int index,
-						string default_value,
-						OptionFlags flags)
-	{
-		this.name	= name;
-		this.title	= title;
-		this.desc	= desc;
-		this.domain = domain;
-		this.group	= group;
-		this.index	= index;
-		this.default_value = default_value;
-		this.flags	= flags;
-	}
-
-	public void set_enum(SList values)
-	{
-		return_if_fail ((bool) (this.flags & OptionFlags.ENUM));
-		this.values = values.copy();
-	}
-}
-
-public class Gnome.Scan.OptionPaperSize : Gnome.Scan.Option {
-	[Notify]
-		public weak SList		paper_sizes		{set; get;}
-	public weak Gtk.PaperSize	default_value	{set construct; get;}
-
-	public OptionPaperSize(string name,
-						   string title,
-						   string desc,
-						   string domain,
-						   Quark group,
-						   int index,
-						   Gtk.PaperSize# default_value,
-						   SList# paper_sizes,
-						   OptionFlags flags)
-	{
-		this.name	= name;
-		this.title	= title;
-		this.desc	= desc;
-		this.domain = domain;
-		this.group	= group;
-		this.index	= index;
-		this.default_value = default_value;
-		this.paper_sizes = paper_sizes;
-		this.flags	= flags;
-	}
-}
-
-public class Gnome.Scan.OptionPageOrientation : Gnome.Scan.Option {
-	public Gtk.PageOrientation	default_value	{set construct; get;}
-
-	public OptionPageOrientation(string name,
-								 string title,
-								 string desc,
-								 string domain,
-								 Quark group,
-								 int index,
-								 Gtk.PageOrientation default_value,
-								 OptionFlags flags)
-	{
-		this.name	= name;
-		this.title	= title;
-		this.desc	= desc;
-		this.domain = domain;
-		this.group	= group;
-		this.index	= index;
-		this.default_value = default_value;
-		this.flags	= flags;
+namespace Gnome.Scan {
+	public const string OPTION_GROUP_SCANNER	= N_("Scan Options");
+	public const string OPTION_GROUP_SINK		= N_("Output Options");
+	public const string OPTION_GROUP_FORMAT		= N_("Format");
+
+	/**
+	 * GnomeScanOptionHint:
+	 *
+	 * Hint for packing option widget in UI.
+	 */
+	public enum OptionHint {
+		HIDDEN,
+		PRIMARY,
+		SECONDARY,
+		PREVIEW,
+		REPEAT, // imply PRIMARY
+	}
+
+	public abstract class Option : Object {
+		public string			name		{get; set construct;}
+		public string			title		{get; set construct;}
+		public string			desc		{get; set construct;}
+		public string			domain		{get; set construct;}
+		public string			group		{get; set construct;}
+
+		public Gnome.Scan.Unit	unit		{get; set construct; default = Unit.NONE;}
+		public OptionHint		hint		{get; set construct;}
+		public bool				active		{get; set; default = true;}
 	}
 }

Added: trunk/lib/gnome-scan-scanner-selector.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-scanner-selector.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,171 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
+using Gtk;
+
+namespace Gnome.Scan {
+    enum Column {
+		ICON,
+		NAME,
+		STATUS,
+		OBJECT,
+		LAST,
+    }
+
+	public class ScannerSelector : ScrolledWindow {
+		ListStore	scanners;
+		TreeView	view;
+		SList<Backend> backends;
+		int backends_probing_count;
+
+		signal void probe_done();
+
+		public Job job {get; set construct; }
+
+		construct {
+			CellRenderer renderer;
+			TreeViewColumn col;
+			TreeSelection selection;
+
+			this.backends_probing_count = 0;
+			this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+
+			// list
+			this.load_backends();
+			this.scanners = new ListStore(Column.LAST,
+										  typeof(string), typeof(string), typeof(string), typeof(GLib.Object));
+			
+			// view
+			this.view = new TreeView.with_model(this.scanners);
+			this.view.headers_visible = true;
+
+			selection = this.view.get_selection();
+			selection.set_mode(SelectionMode.SINGLE);
+			selection.changed += this.on_selection_changed;
+
+			// columns;
+			renderer = new CellRendererPixbuf();
+			col = new TreeViewColumn.with_attributes(null, renderer, "icon-name", Column.ICON);
+			this.view.append_column(col);
+
+			renderer = new CellRendererText();
+			col = new TreeViewColumn.with_attributes(_("Device"), renderer, "text", Column.NAME);
+			this.view.append_column(col);
+
+			renderer = new CellRendererText();
+			col = new TreeViewColumn.with_attributes(_("Status"), renderer, "text", Column.STATUS);
+			this.view.append_column(col);
+
+			this.add_with_viewport(this.view);
+		}
+
+		public ScannerSelector(Job job)
+		{
+			this.job = job;
+		}
+
+		public void probe_scanners()
+		{
+			foreach(Backend backend in this.backends) {
+				try {
+					this.backends_probing_count++;
+					GLib.Thread.create(backend.probe_scanners, false);
+				}
+				catch(GLib.ThreadError error) {
+					warning("Unable to create new thread : %s", error.message);
+					this.backends_probing_count--;
+				}
+			}
+		}
+
+		private void load_backends()
+		{
+			GLib.Type[] backend_types;
+			Backend backend;
+
+			backend_types = typeof(Backend).children();
+			foreach(GLib.Type type in backend_types) {
+				backend = (Backend)GLib.Object.new(type);
+				this.backends.append(backend);
+				backend.scanner_added += this.on_scanner_added;
+				backend.probe_done += this.on_probe_done;
+				GLib.Idle.add(this.on_idle_check_probe_done);
+			}
+		}
+
+		private void on_scanner_added(Backend backend, Scanner new_scanner)
+		{
+			TreeIter iter;
+			this.scanners.append(out iter);
+			this.scanners.set(iter,
+							  Column.ICON,	new_scanner.icon_name,
+							  Column.NAME,	new_scanner.name,
+							  Column.STATUS,_(new_scanner.message),
+							  Column.OBJECT,new_scanner);
+			new_scanner.set_data("path", this.scanners.get_path(iter).to_string());
+			new_scanner.notify["status"] += on_scanner_status_changed;
+		}
+
+		private void on_probe_done(Backend backend)
+		{
+			this.backends_probing_count--;
+		}
+
+		private bool on_idle_check_probe_done()
+		{
+			TreeIter iter;
+
+			if (this.backends_probing_count == 0) {
+				this.probe_done();
+				// TODO: remember selection in GConf
+				this.scanners.get_iter_first(out iter);
+				this.view.get_selection().select_iter(iter);
+				return false;
+			}
+			return true;
+		}
+
+		private void on_selection_changed(TreeSelection selection)
+		{
+			TreeModel model;
+			TreeIter iter;
+			Scanner scanner;
+
+			if (selection.get_selected(out model, out iter))
+				model.get(iter, Column.OBJECT, out scanner);
+			else
+				scanner = null;
+
+			this.job.scanner = scanner;
+		}
+
+		private void on_scanner_status_changed(Scanner scanner, ParamSpec pspec)
+		{
+			TreeIter iter;
+			this.scanners.get_iter_from_string(out iter,
+											   (string)scanner.get_data("path"));
+			if (!this.scanners.iter_is_valid(iter))
+				warning("Unable to update '%s' status in scanner selector!", scanner.name);
+
+			this.scanners.set(iter, Column.STATUS, _(scanner.message));
+		}
+	}
+}

Added: trunk/lib/gnome-scan-scanner.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-scanner.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,30 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using GLib;
+
+namespace Gnome.Scan {
+    public abstract class Scanner : Node {
+		public string name		{set; get;}
+		public string blurb		{set; get;}
+		public string icon_name {set; get;}
+    }
+}
\ No newline at end of file

Added: trunk/lib/gnome-scan-sink.vala
==============================================================================
--- (empty file)
+++ trunk/lib/gnome-scan-sink.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,31 @@
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+ * 
+ * GNOME Scan 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 GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using GLib;
+
+namespace Gnome.Scan {
+	public class Sink : Node {
+		public virtual void finalize_process()
+		{
+			debug("Finalizing process");
+		}
+	}
+}
\ No newline at end of file

Modified: trunk/lib/gnome-scan.h
==============================================================================
--- trunk/lib/gnome-scan.h	(original)
+++ trunk/lib/gnome-scan.h	Sat Dec  6 17:38:48 2008
@@ -23,11 +23,8 @@
 #define	_GNOME_SCAN_H_
 
 #include <gnome-scan-init.h>
-#include <gnome-scan-param-specs.h>
 #include <gnome-scan-job.h>
-#include <gnome-scan-plugin.h>
-#include <gnome-scan-sink.h>
+#include <gnome-scan-node.h>
 #include <gnome-scan-dialog.h>
-#include <gnome-scan-acquisition-dialog.h>
 
 #endif

Modified: trunk/modules/Makefile.am
==============================================================================
--- trunk/modules/Makefile.am	(original)
+++ trunk/modules/Makefile.am	Sat Dec  6 17:38:48 2008
@@ -8,38 +8,45 @@
 modulesdir = @MODULE_DIR@
 modules_LTLIBRARIES = \
 	libgsfiles.la \
-	libgsane.la
+	$(NULL)
+
+# 	libgsane.la 
 
 libgsfiles_la_SOURCES = \
-	gsfile-scanner.h\
-	gsfile-scanner.c                            \
-	gsfile-module.c                            \
+	gsfile-scanner.h	\
+	gsfile-scanner.c        \
+	gsfile-module.c         \
 	gsfile-module.h		\
-	gsfile-backend.h                            \
-	gsfile-backend.c                            \
+	gsfile-backend.h        \
+	gsfile-backend.c        \
+	gsfile-options.h	\
+	gsfile-options.c	\
 	gsfile-filenames-widget.h		\
 	gsfile-filenames-widget.c		\
-	gsfile-pspec.h		\
-	gsfile-pspec.c
+	$(NULL)
 
 libgsfiles_la_LDFLAGS = -avoid-version -module
 
-libgsane_la_SOURCES = \
-	gsane-backend.h     \
-	gsane-backend.c     \
-	gsane-scanner.h     \
-	gsane-scanner.c     \
-	gsane-module.c     \
-	gsane-meta-param.h     \
-	gsane-meta-param.c     \
-	gsane-common.h     \
-	gsane-common.c 
-
-libgsane_la_LDFLAGS = -avoid-version -module
-
-libgsane_la_LIBADD = \
-	-L$(top_builddir)/lib -l SONAME@ \
-	-lsane
-
+# libgsane_la_SOURCES = \
+# 	gsane-backend.h     \
+# 	gsane-backend.c     \
+# 	gsane-scanner.h     \
+# 	gsane-scanner.c     \
+# 	gsane-module.c     \
+# 	gsane-meta-param.h     \
+# 	gsane-meta-param.c     \
+# 	gsane-common.h     \
+# 	gsane-common.c 
+
+# libgsane_la_LDFLAGS = -avoid-version -module
+
+# libgsane_la_LIBADD = \
+# 	-L$(top_builddir)/lib -l SONAME@ \
+# 	-lsane
+
+EXTRA_DIST = \
+	$(wildcard gsane-*.c)	\
+	$(wildcard gsane-*.h)	\
+	$(NULL)
 #
 ## File created by the gnome-build tools

Modified: trunk/modules/gsfile-backend.c
==============================================================================
--- trunk/modules/gsfile-backend.c	(original)
+++ trunk/modules/gsfile-backend.c	Sat Dec  6 17:38:48 2008
@@ -27,7 +27,7 @@
 
 static GnomeScanBackendClass* parent_class = NULL;
 
-void	gsfb_probe_scanners (GnomeScanBackend *backend);
+void*	gsfb_probe_scanners (GnomeScanBackend *backend);
 
 GS_DEFINE_MODULE_TYPE (GSFileBackend, gsfile_backend, GNOME_SCAN_TYPE_BACKEND);
 
@@ -38,11 +38,11 @@
 }
 
 static void
-gsfile_backend_finalize (GObject *object)
+gsfile_backend_finalize (GObject *self)
 {
 	/* TODO: Add deinitalization code here */
 
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	G_OBJECT_CLASS (parent_class)->finalize (self);
 }
 
 static void
@@ -57,11 +57,13 @@
 	object_class->finalize = gsfile_backend_finalize;
 }
 
-void
-gsfb_probe_scanners (GnomeScanBackend *backend)
+void*
+gsfb_probe_scanners (GnomeScanBackend *self)
 {
 	GnomeScanScanner *scanner;
 	scanner = gsfile_scanner_new ();
-	gnome_scan_backend_add_scanner (backend, scanner);
+	g_signal_emit_by_name(self, "scanner-added", scanner);
 	g_object_unref (scanner);
+	g_signal_emit_by_name(self, "probe-done");
+	return NULL;
 }

Modified: trunk/modules/gsfile-filenames-widget.c
==============================================================================
--- trunk/modules/gsfile-filenames-widget.c	(original)
+++ trunk/modules/gsfile-filenames-widget.c	Sat Dec  6 17:38:48 2008
@@ -1,23 +1,23 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-/*
- * gnome-scan
- * Copyright (C) Ãtienne Bersac 2007 <bersace03 laposte net>
- * 
- * gnome-scan is free software; you can redistribute it and/or
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
  * 
- * gnome-scan is distributed in the hope that it will be useful,
+ * GNOME Scan 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 gnome-scan.  If not, write to:
- * 	The Free Software Foundation, Inc.,
- * 	51 Franklin Street, Fifth Floor
- * 	Boston, MA  02110-1301, USA.
+ * License along with GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
  */
 
 #ifdef  HAVE_CONFIG_H
@@ -25,27 +25,28 @@
 #endif
 
 #include <glib/gi18n.h>
-#include "gsfile-pspec.h"
+#include <gnome-scan-module-helper.h>
+#include <gnome-scan-option-widget.h>
+#include "gsfile-options.h"
 #include "gsfile-filenames-widget.h"
 
-#define	GET_PRIVATE(o)	(G_TYPE_INSTANCE_GET_PRIVATE ((o), GSFILE_TYPE_FILENAMES_WIDGET, GSFileFilenamesWidgetPrivate))
+#define	GSFILE_FILENAMES_WIDGET_GET_PRIVATE(o)	(G_TYPE_INSTANCE_GET_PRIVATE ((o), GSFILE_TYPE_FILENAMES_WIDGET, GSFileFilenamesWidgetPrivate))
 
 #undef  _
 #define _(string)   dgettext(GETTEXT_PACKAGE, string)
 
 #define	PREVIEW_SIZE	96
 
-typedef struct _GSFileFilenamesWidgetPrivate GSFileFilenamesWidgetPrivate;
-
 struct _GSFileFilenamesWidgetPrivate
 {
 	GtkWidget			*filechooser;
 	GtkListStore		*liststore;
 	GtkTreeSelection	*selection;
+	GtkWidget			*clear;
+	GtkWidget			*remove;
 };
 
-enum
-{
+enum {
 	FILENAMES_PREVIEW,
 	FILENAMES_BASENAME,
 	FILENAMES_PATHNAME,
@@ -53,62 +54,51 @@
 };
 
 static void	gsffw_filenames_add (GtkButton *button,
-								   GSFileFilenamesWidget *widget);
-static void	gsffw_filenames_populate (GSFileFilenamesWidget *widget);
-static gboolean gsffw_filenames_preview_foreach_func (GtkTreeModel *model,
-													 GtkTreePath *path,
-													 GtkTreeIter *iter,
-													 GSFileFilenamesWidget *widget);
+								 GSFileFilenamesWidget *self);
 static void	gsffw_filenames_remove (GtkButton *button,
-									  GSFileFilenamesWidget *widget);
+									GSFileFilenamesWidget *self);
 static void	gsffw_filenames_clear (GtkButton *button,
-									 GSFileFilenamesWidget *widget);
-static gboolean	gsffw_filenames_foreach_func (GtkTreeModel *model,
-												GtkTreePath *path,
-												GtkTreeIter *iter,
-												GSList **widget);
-static void	gsffw_filenames_changed (GSFileFilenamesWidget *widget);
+								   GSFileFilenamesWidget *self);
+static void	gsffw_filenames_preview (GSFileFilenamesWidget *self);
+static gboolean gsffw_filenames_foreach_preview (GtkTreeModel *model,
+												 GtkTreePath *path,
+												 GtkTreeIter *iter,
+												 GSFileFilenamesWidget *self);
+static gboolean	gsffw_filenames_foreach_fetch (GtkTreeModel *model,
+											   GtkTreePath *path,
+											   GtkTreeIter *iter,
+											   GSList **list);
+
+static void gsffw_filenames_changed(GSFileFilenamesWidget *self);
+static void gsffw_selection_changed(GSFileFilenamesWidget *self);
+static void gsffw_filenames_update(GSFileFilenamesWidget *self);
 
-GS_DEFINE_PARAM_WIDGET (GSFileFilenamesWidget, gsfile_filenames_widget)
+GS_DEFINE_MODULE_TYPE (GSFileFilenamesWidget, gsfile_filenames_widget, GNOME_SCAN_TYPE_OPTION_WIDGET)
 
-static void
-gsfile_filenames_widget_init (GSFileFilenamesWidget *object)
+static GObject*
+gsfile_filenames_widget_construct (GType type, guint n_construct_properties, GObjectConstructParam* construct_properties)
 {
-	/* TODO: Add initialization code here */
-}
-
-static void
-gsfile_filenames_widget_finalize (GObject *object)
-{
-	/* TODO: Add deinitalization code here */
-
-	G_OBJECT_CLASS (gsfile_filenames_widget_parent_class)->finalize (object);
-}
-
-
-
-static void
-gsfile_filenames_widget_build (GnomeScanParamWidget *gspw)
-{
-	GSFileFilenamesWidget *gsffw = GSFILE_FILENAMES_WIDGET (gspw);
-	GSFileFilenamesWidgetPrivate *priv = GET_PRIVATE (gsffw);
+	GObject* object = G_OBJECT_CLASS(gsfile_filenames_widget_parent_class)->constructor(type, n_construct_properties, construct_properties);
+	GSFileFilenamesWidget* self = GSFILE_FILENAMES_WIDGET(object);
 	GtkWidget *scrolled, *tree_view, *box, *button;
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
 	
-	gtk_box_set_spacing (GTK_BOX (gspw), 6);
-	gspw->shows_label = TRUE; /* yes, that's a lie :o) */
-	gspw->expands = TRUE;
-	
-	priv->liststore = gtk_list_store_new (FILENAMES_N_COLUMNS,
-										  GDK_TYPE_PIXBUF,
-										  G_TYPE_STRING,
-										  G_TYPE_STRING);
+	gtk_box_set_spacing (GTK_BOX (self), 6);
+	g_object_set(self, "no_label", TRUE, "expand", TRUE, NULL);
 	
-	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->liststore));
+	self->priv->liststore = gtk_list_store_new (FILENAMES_N_COLUMNS,
+												GDK_TYPE_PIXBUF,
+												G_TYPE_STRING,
+												G_TYPE_STRING);
+	g_signal_connect_swapped(self->priv->liststore, "row-inserted", G_CALLBACK(gsffw_filenames_changed), self);
+	g_signal_connect_swapped(self->priv->liststore, "row-deleted", G_CALLBACK(gsffw_filenames_changed), self);
+	
+	tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->priv->liststore));
 	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (tree_view), TRUE);
 	gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (tree_view), TRUE);
-	priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+	self->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+	g_signal_connect_swapped(self->priv->selection, "changed", G_CALLBACK(gsffw_selection_changed), self);	
 	
 	/* preview */
 	renderer = gtk_cell_renderer_pixbuf_new ();
@@ -130,134 +120,155 @@
 									GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
 										   tree_view);
-	gtk_box_pack_start (GTK_BOX (gspw), scrolled, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (self), scrolled, TRUE, TRUE, 0);
 	
 	/* buttons */
 	box = gtk_vbutton_box_new ();
 	gtk_box_set_spacing (GTK_BOX (box), 4);
 	gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_START);
-	gtk_box_pack_start (GTK_BOX (gspw), box, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (self), box, FALSE, FALSE, 0);
 	
+	/* add */
 	button = gtk_button_new_from_stock (GTK_STOCK_ADD);
 	g_signal_connect (button, "clicked",
-					  (GCallback) gsffw_filenames_add, gsffw);
+					  (GCallback) gsffw_filenames_add, self);
 	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
 	
-	button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+	/* remove */
+	self->priv->remove = button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+	gtk_widget_set_sensitive(button, FALSE);
 	g_signal_connect (button, "clicked",
-					  (GCallback) gsffw_filenames_remove, gsffw);
+					  (GCallback) gsffw_filenames_remove, self);
 	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
 	
-	button = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
+	/* clear */
+	self->priv->clear = button = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
+	gtk_widget_set_sensitive(button, FALSE);
 	g_signal_connect (button, "clicked",
-					  (GCallback) gsffw_filenames_clear, gsffw);
+					  (GCallback) gsffw_filenames_clear, self);
 	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+
+	return object;
 }
 
 static void
-gsfile_filenames_widget_set (GnomeScanParamWidget *gspw, GValue *value)
+gsfile_filenames_widget_class_init (GSFileFilenamesWidgetClass *klass)
 {
+	g_type_class_add_private(klass, sizeof(GSFileFilenamesWidgetPrivate));
+	G_OBJECT_CLASS(klass)->constructor = gsfile_filenames_widget_construct;
 }
-/* INTERNALS */
 
 static void
-gsffw_filenames_add (GtkButton *button, GSFileFilenamesWidget *gsffw)
+gsfile_filenames_widget_init (GSFileFilenamesWidget *self)
+{
+	self->priv = GSFILE_FILENAMES_WIDGET_GET_PRIVATE(self);
+}
+
+
+/* INTERNALS */
+
+static GtkWidget*
+gsffw_build_filechooser(GSFileFilenamesWidget *self)
 {
-	GnomeScanParamWidget *gspw = GNOME_SCAN_PARAM_WIDGET (gsffw);
-	GSFileFilenamesWidgetPrivate *priv = GET_PRIVATE (gsffw);
+	GnomeScanOption *option;
+	GtkWidget* filechooser;
 	GtkFileFilter *filter, *filter1;
 	GSList *node;
+	GnomeScanFormat *format;
 	gchar **mimes, **exts;
 	gchar *pattern;
 	gint i;
-	GError *error = NULL;
-	GnomeScanFormat *format;
-	
-	
-	/* filechooser */
-	if (!priv->filechooser) {
-		priv->filechooser =
-			gtk_file_chooser_dialog_new (_("Select files"),
-										 GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gsffw))),
-										 GTK_FILE_CHOOSER_ACTION_OPEN,
-										 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-										 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-										 NULL);
-		gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (priv->filechooser),
-											 g_get_home_dir ());
-		gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (priv->filechooser),
-											  TRUE);
+
+	g_object_get(self, "option", &option, NULL);
+	filechooser = gtk_file_chooser_dialog_new (_("Select files"),
+											   GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))),
+											   GTK_FILE_CHOOSER_ACTION_OPEN,
+											   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+											   GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+											   NULL);
+	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser),
+										 g_get_home_dir ());
+	gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (filechooser),
+										  TRUE);
 		
-		/* add a global filter and a per format filter */
-		filter = gtk_file_filter_new ();
-		gtk_file_filter_set_name (filter, _("Supported formats"));
-		gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (priv->filechooser), filter);
-		node = gsfile_param_spec_filenames_get_formats (gspw->pspec);
-		for (; node ; node = node->next) {
-			format = node->data;
-			filter1 = gtk_file_filter_new ();
-			
-			mimes = format->mime_types;
-			for (i = 0; mimes[i]; i++) {
-				gtk_file_filter_add_mime_type (filter, mimes[i]);
-				gtk_file_filter_add_mime_type (filter1, mimes[i]);
-			}
+	/* add a global filter and a per format filter */
+	filter = gtk_file_filter_new ();
+	gtk_file_filter_set_name (filter, _("Supported formats"));
+	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filechooser), filter);
+	g_object_get(option, "formats", &node, NULL);
+	for (; node ; node = node->next) {
+		format = node->data;
+		filter1 = gtk_file_filter_new ();
 			
-			exts = format->extensions;
-			for (i = 0; exts[i]; i++) {
-				pattern = g_strdup_printf ("*.%s", exts[i]);
-				gtk_file_filter_add_pattern (filter, pattern);
-				gtk_file_filter_add_pattern (filter1, pattern);
-			}
+		mimes = format->mime_types;
+		for (i = 0; mimes[i]; i++) {
+			gtk_file_filter_add_mime_type (filter, mimes[i]);
+			gtk_file_filter_add_mime_type (filter1, mimes[i]);
+		}
 			
-			gtk_file_filter_set_name (filter1,
-									  g_strdup_printf ("%s (*.%s)",
-													   dgettext(format->domain, format->description),
-													   g_strjoinv(", *.", format->extensions)));
-			gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (priv->filechooser),
-										 filter1);
+		exts = format->suffixes;
+		for (i = 0; exts[i]; i++) {
+			pattern = g_strdup_printf ("*.%s", exts[i]);
+			gtk_file_filter_add_pattern (filter, pattern);
+			gtk_file_filter_add_pattern (filter1, pattern);
 		}
+			
+		gtk_file_filter_set_name (filter1,
+								  g_strdup_printf ("%s (*.%s)",
+												   dgettext(format->domain, format->desc),
+												   g_strjoinv(", *.", format->suffixes)));
+		gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filechooser),
+									 filter1);
+	}
+
+	return filechooser;
+}
+
+static void
+gsffw_filenames_add (GtkButton *button, GSFileFilenamesWidget *self)
+{
+	GtkTreeIter iter;
+	GSList *node;
+	GError *error = NULL;
+
+	/* filechooser */
+	if (!self->priv->filechooser) {
+		self->priv->filechooser = gsffw_build_filechooser(self);
 	}
 	
 	/* run filechooser */
-	if (gtk_dialog_run (GTK_DIALOG (priv->filechooser)) == GTK_RESPONSE_ACCEPT) {
-		gtk_widget_hide (priv->filechooser);
+	if (gtk_dialog_run (GTK_DIALOG (self->priv->filechooser)) == GTK_RESPONSE_ACCEPT) {
+		gtk_widget_hide (self->priv->filechooser);
+		node = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (self->priv->filechooser));
+		/* first populate list store */
+		for (; node ; node = node->next) {
+			gtk_list_store_insert_with_values (self->priv->liststore, &iter, G_MAXINT,
+											   FILENAMES_BASENAME, g_path_get_basename (node->data),
+											   FILENAMES_PATHNAME, node->data,
+											   -1);
+		}
+		gsffw_filenames_update(self);
+	
 		/* delegate populate creation in a thread */
-		g_thread_create ((GThreadFunc) gsffw_filenames_populate,
-						 gsffw, FALSE, &error);
+		g_thread_create ((GThreadFunc) gsffw_filenames_preview,
+						 self, FALSE, &error);
 	}
-	gtk_widget_hide (priv->filechooser);
+	gtk_widget_hide (self->priv->filechooser);
 }
 
 static void
-gsffw_filenames_populate (GSFileFilenamesWidget *gsffw)
+gsffw_filenames_preview (GSFileFilenamesWidget *self)
 {
-	GSFileFilenamesWidgetPrivate *priv = GET_PRIVATE (gsffw);
-	GSList *node;
-	GtkTreeIter iter;
-	
-	/* first populate list store */
-	node = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (priv->filechooser));
-	for (; node ; node = node->next) {
-		gtk_list_store_insert_with_values (priv->liststore, &iter, G_MAXINT,
-										   FILENAMES_PREVIEW, NULL,
-										   FILENAMES_BASENAME, g_path_get_basename (node->data),
-										   FILENAMES_PATHNAME, node->data,
-										   -1);
-	}
-	
 	/* trigger preview update (this may take some time considering list length and image size) */
-	gtk_tree_model_foreach (GTK_TREE_MODEL (GET_PRIVATE (gsffw)->liststore),
-							(GtkTreeModelForeachFunc) gsffw_filenames_preview_foreach_func,
-							gsffw);
-	gsffw_filenames_changed (gsffw);
+	gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->liststore),
+							(GtkTreeModelForeachFunc) gsffw_filenames_foreach_preview,
+							self);
 }
 
 /* create a preview if not present */
 gboolean
-gsffw_filenames_preview_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GSFileFilenamesWidget *gsffw)
+gsffw_filenames_foreach_preview (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GSFileFilenamesWidget *self)
 {
-	GSFileFilenamesWidgetPrivate *priv = GET_PRIVATE (gsffw);
 	GdkPixbuf *preview;
 	GError *error = NULL;
 	gchar *pathname;
@@ -270,7 +281,7 @@
 		preview = gdk_pixbuf_new_from_file_at_scale (pathname,
 													 PREVIEW_SIZE, PREVIEW_SIZE,
 													 TRUE, &error);
-		gtk_list_store_set (priv->liststore, iter,
+		gtk_list_store_set (self->priv->liststore, iter,
 							FILENAMES_PREVIEW, preview,
 							-1);
 	}
@@ -278,55 +289,66 @@
 }
 
 static void
-gsffw_filenames_remove (GtkButton *button, GSFileFilenamesWidget *gsffw)
+gsffw_filenames_remove (GtkButton *button, GSFileFilenamesWidget *self)
 {
-	GSFileFilenamesWidgetPrivate *priv = GET_PRIVATE (gsffw);
-	GtkTreeModel *model = GTK_TREE_MODEL (priv->liststore);
-	GList *node, *first = gtk_tree_selection_get_selected_rows (priv->selection,
+	GtkTreeModel *model = GTK_TREE_MODEL (self->priv->liststore);
+	GList *node, *first = gtk_tree_selection_get_selected_rows (self->priv->selection,
 																&model);
 	GtkTreeIter iter;
 
 	for (node = first; node ; node = node->next) {
 		gtk_tree_model_get_iter (model, &iter, node->data);
-		gtk_list_store_remove (priv->liststore, &iter);
+		gtk_list_store_remove (self->priv->liststore, &iter);
 		gtk_tree_path_free (node->data);
 	}
 	g_list_free (first);
-	gsffw_filenames_changed (gsffw);
+	gsffw_filenames_update(self);
 }
 
 static void
-gsffw_filenames_clear (GtkButton *button, GSFileFilenamesWidget *gsffw)
+gsffw_filenames_clear (GtkButton *button, GSFileFilenamesWidget *self)
 {
-	gtk_list_store_clear (GET_PRIVATE (gsffw)->liststore);
-	gsffw_filenames_changed (gsffw);
+	gtk_list_store_clear (self->priv->liststore);
+	gsffw_filenames_update(self);
 }
 
 static void
-gsffw_filenames_changed (GSFileFilenamesWidget *gsffw)
+gsffw_filenames_update (GSFileFilenamesWidget *self)
 {
-	GnomeScanParamWidget *gspw = GNOME_SCAN_PARAM_WIDGET (gsffw);
-	GSFileFilenamesWidgetPrivate *priv = GET_PRIVATE (gsffw);
 	GSList *list = NULL;
-	
-	gtk_tree_model_foreach (GTK_TREE_MODEL (priv->liststore),
-							(GtkTreeModelForeachFunc) gsffw_filenames_foreach_func,
+	GnomeScanOption *option;
+	gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->liststore),
+							(GtkTreeModelForeachFunc) gsffw_filenames_foreach_fetch,
 							&list);
-	g_value_set_pointer (gspw->value, list);
-
-	gnome_scan_param_widget_changed (gspw);
+	g_object_get(self, "option", &option, NULL);
+	g_object_set(option, "value", list, NULL);
 }
 
 static gboolean
-gsffw_filenames_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GSList **list)
+gsffw_filenames_foreach_fetch (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GSList **list)
 {
 	gchar*pathname;
 	gtk_tree_model_get (model, iter,
 						FILENAMES_PATHNAME, &pathname,
 						-1);
-	*list = g_slist_append (*list, g_strdup (pathname));
+	*list = g_slist_append (*list, g_strdup(pathname));
 	
 	return FALSE;
 }
 
+static void
+gsffw_filenames_changed(GSFileFilenamesWidget *self)
+{
+	GtkTreePath*path = gtk_tree_path_new_first();
+	GtkTreeIter iter;
+	gtk_tree_model_get_iter(GTK_TREE_MODEL(self->priv->liststore), &iter, path);
+	gtk_widget_set_sensitive(self->priv->clear, (gtk_list_store_iter_is_valid(self->priv->liststore, &iter)));
+}
 
+static void
+gsffw_selection_changed(GSFileFilenamesWidget *self)
+{
+	gtk_widget_set_sensitive(self->priv->remove,
+							 gtk_tree_selection_get_selected(self->priv->selection,
+															 NULL, NULL));
+}

Modified: trunk/modules/gsfile-filenames-widget.h
==============================================================================
--- trunk/modules/gsfile-filenames-widget.h	(original)
+++ trunk/modules/gsfile-filenames-widget.h	Sat Dec  6 17:38:48 2008
@@ -1,30 +1,30 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-/*
- * gnome-scan
- * Copyright (C) Ãtienne Bersac 2007 <bersace03 laposte net>
- * 
- * gnome-scan is free software; you can redistribute it and/or
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
  * 
- * gnome-scan is distributed in the hope that it will be useful,
+ * GNOME Scan 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 gnome-scan.  If not, write to:
- * 	The Free Software Foundation, Inc.,
- * 	51 Franklin Street, Fifth Floor
- * 	Boston, MA  02110-1301, USA.
+ * License along with GNOME Scan. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
  */
 
 #ifndef _GSFILE_FILENAMES_WIDGET_H_
 #define _GSFILE_FILENAMES_WIDGET_H_
 
 #include <glib-object.h>
-#include <gnome-scan-param-widget.h>
+#include <gnome-scan-option-widget.h>
 
 G_BEGIN_DECLS
 
@@ -36,12 +36,23 @@
 #define GSFILE_FILENAMES_WIDGET_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GSFILE_TYPE_FILENAMES_WIDGET, GSFileFilenamesWidgetClass))
 
 typedef struct _GSFileFilenamesWidget GSFileFilenamesWidget;
+typedef struct _GSFileFilenamesWidgetClass GSFileFilenamesWidgetClass;
+typedef struct _GSFileFilenamesWidgetPrivate GSFileFilenamesWidgetPrivate;
+
 struct _GSFileFilenamesWidget
 {
-	GnomeScanParamWidget parent_instance;
+	GnomeScanOptionWidget parent_instance;
+	GSFileFilenamesWidgetPrivate *priv;
+};
+
+struct _GSFileFilenamesWidgetClass
+{
+	GnomeScanOptionWidgetClass parent_class;
 };
 
-GS_DEFINE_PARAM_WIDGET_HEADER (GSFileFilenamesWidget, gsfile_filenames_widget)
+void gsfile_filenames_widget_register_type(GTypeModule* module);
+GType gsfile_filenames_widget_get_type(void) G_GNUC_CONST;
+
 
 G_END_DECLS
 

Modified: trunk/modules/gsfile-module.c
==============================================================================
--- trunk/modules/gsfile-module.c	(original)
+++ trunk/modules/gsfile-module.c	Sat Dec  6 17:38:48 2008
@@ -1,18 +1,18 @@
-/* Gnome Scan - Scan as easy as you print
- * Copyright  2007  Ãtienne Bersac <bersace gnome org>
+/* GNOME Scan - Scan as easy as you print
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
  *
- * Gnome Scan is free software; you can redistribute it and/or
+ * GNOME Scan 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 2.1 of the License, or (at your option) any later version.
  * 
- * gnome-scan is distributed in the hope that it will be useful,
+ * GNOME Scan 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 gnome-scan.  If not, write to:
+ * License along with GNOME Scan. If not, write to:
  *
  *	the Free Software Foundation, Inc.
  *	51 Franklin Street, Fifth Floor
@@ -21,14 +21,21 @@
 
 
 #include <gnome-scan-module.h>
+#include <gnome-scan-option-manager.h>
 #include "gsfile-backend.h"
 #include "gsfile-scanner.h"
+#include "gsfile-options.h"
+#include "gsfile-filenames-widget.h"
 
 G_MODULE_EXPORT void
 gnome_scan_module_init (GnomeScanModule *module)
 {
-	gsfile_scanner_register_type (G_TYPE_MODULE (module));
 	gsfile_backend_register_type (G_TYPE_MODULE (module));
+	gsfile_scanner_register_type (G_TYPE_MODULE (module));
+	gsfile_option_filenames_register_type(G_TYPE_MODULE(module));
+	gsfile_filenames_widget_register_type(G_TYPE_MODULE(module));
+
+	gnome_scan_option_manager_register_rule_by_type(gnome_scan_option_manager, GSFILE_TYPE_OPTION_FILENAMES, GSFILE_TYPE_FILENAMES_WIDGET);
 }
 
 G_MODULE_EXPORT void

Modified: trunk/modules/gsfile-scanner.c
==============================================================================
--- trunk/modules/gsfile-scanner.c	(original)
+++ trunk/modules/gsfile-scanner.c	Sat Dec  6 17:38:48 2008
@@ -1,23 +1,23 @@
-/* Gnome Scan - Scan as easy as you print
- * Copyright  2007  Ãtienne Bersac <bersace gnome org>
- *
- * Gnome Scan 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 2.1 of the License, or (at your option) any later version.
- * 
- * gnome-scan 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 gnome-scan.  If not, write to:
- *
- *	the Free Software Foundation, Inc.
- *	51 Franklin Street, Fifth Floor
- *	Boston, MA 02110-1301, USA
- */
+/* GNOME Scan - Scan as easy as you print
+* Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+*
+* GNOME Scan 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 2.1 of the License, or (at your option) any later version.
+* 
+* GNOME Scan 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 GNOME Scan. If not, write to:
+*
+*	the Free Software Foundation, Inc.
+*	51 Franklin Street, Fifth Floor
+*	Boston, MA 02110-1301, USA
+*/
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -26,172 +26,151 @@
 #include <glib/gi18n.h>
 #include <gnome-scan-module.h>
 #include <gnome-scan-module-helper.h>
-#include <gnome-scan-param-specs.h>
-#include "gsfile-pspec.h"
+#include <gnome-scan-option.h>
+#include <gnome-scan-common.h>
+#include "gsfile-options.h"
 #include "gsfile-scanner.h"
 
-#define	GET_PRIVATE(o)	(G_TYPE_INSTANCE_GET_PRIVATE ((o), GSFILE_TYPE_SCANNER, GSFileScannerPrivate))
-
-typedef struct _GSFileScannerPrivate GSFileScannerPrivate;
+#define	GSFILE_SCANNER_GET_PRIVATE(o)	(G_TYPE_INSTANCE_GET_PRIVATE ((o), GSFILE_TYPE_SCANNER, GSFileScannerPrivate))
 
 struct _GSFileScannerPrivate
 {
-  GeglNode		*load;
+	GSList* filenames;
+	GSList* current;
+	GeglNode* load;
 };
 
-static GnomeScanScannerClass* parent_class = NULL;
-
-static void	gsf_configure			(GnomeScanPlugin *plugin,
-									 GnomeScanSettings *settings);
-static GList*	gsf_get_child_nodes	(GnomeScanPlugin *plugin,
-										 GeglNode *root);
-static gboolean	gsf_start_frame		(GnomeScanPlugin *plugin);
-static gboolean	gsf_work			(GnomeScanPlugin *plugin,
-										gdouble *progress);
-
 GS_DEFINE_MODULE_TYPE (GSFileScanner, gsfile_scanner, GNOME_SCAN_TYPE_SCANNER);
 
-static void
-gsfile_scanner_init (GSFileScanner *object)
+GnomeScanScanner*
+gsfile_scanner_new ()
 {
-	GParamSpec *pspec;
-	GSList *formats = NULL;
-	
-	static gchar *png_mime[] = {
-		"image/png",
-		NULL
-	};
-	static gchar *png_exts[] = {
-		"png",
-		NULL
-	};
-	
-	formats = g_slist_append (formats,
-							  gnome_scan_format_new ("png",
-													 GETTEXT_PACKAGE,
-													 N_("PNG picture"),
-													 png_mime,
-													 png_exts));
-	
-	static gchar *jpeg_mime[] = {
-		"image/jpeg",
-		NULL
-	};
-	static gchar *jpeg_exts[] = {
-		"jpeg",
-		"jpe",
-		"jpg",
-		NULL
-	};
-	
-	formats = g_slist_append (formats,
-							  gnome_scan_format_new ("jpeg",
-													 GETTEXT_PACKAGE,
-													 N_("JPEG picture"),
-													 jpeg_mime,
-													 jpeg_exts));
-	
-	pspec = gsfile_param_spec_filenames ("input-filenames",
-										 N_("Files"),
-										 N_("Files to import."),
-										 GS_PARAM_GROUP_SCANNER_FRONT,
-										 formats, G_PARAM_WRITABLE);
-	gs_param_spec_set_domain (pspec, GETTEXT_PACKAGE);
-	gs_param_spec_set_unit (pspec, GNOME_SCAN_UNIT_NONE);
-	gnome_scan_plugin_params_add (GNOME_SCAN_PLUGIN (object), pspec);
-	GNOME_SCAN_SCANNER (object)->status = GNOME_SCAN_STATUS_READY;
+	GObject *object = g_object_new (GSFILE_TYPE_SCANNER,
+					/* translator: this is the name of the file
+					loader backend which allow user to scan 
+					a list a images */
+					"name", _("Files"),
+					"blurb", _("Import from files."),
+					"icon-name", "gnome-mime-image",
+					NULL);
+	return GNOME_SCAN_SCANNER (object);
 }
 
 static void
-gsfile_scanner_finalize (GObject *object)
+gsfile_scanner_start_scan(GnomeScanNode *node)
 {
-	/* TODO: Add deinitalization code here */
-	
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	GSFileScanner *self = GSFILE_SCANNER(node);
+	self->priv->current = self->priv->filenames;
 }
 
-static void
-gsfile_scanner_class_init (GSFileScannerClass *klass)
+static gboolean
+gsfile_scanner_start_frame(GnomeScanNode *node)
 {
-	GObjectClass* object_class = G_OBJECT_CLASS (klass);
-	parent_class = GNOME_SCAN_SCANNER_CLASS (g_type_class_peek_parent (klass));
-	GnomeScanPluginClass* plugin_class = GNOME_SCAN_PLUGIN_CLASS (klass);
-	
-	g_type_class_add_private (object_class, sizeof (GSFileScannerPrivate));
-	
-	plugin_class->configure			= gsf_configure;
-	plugin_class->start_frame		= gsf_start_frame;
-	plugin_class->work				= gsf_work;
-	plugin_class->get_child_nodes   = gsf_get_child_nodes;
-	
-	object_class->finalize	= gsfile_scanner_finalize;
+	GSFileScanner *self = GSFILE_SCANNER(node);
+	if (!self->priv->current)
+		return FALSE;
+
+	gegl_node_set(self->priv->load,
+		      "path", self->priv->current->data,
+		      NULL);
+	g_debug(G_STRLOC ": Scan %s", (gchar*) self->priv->current->data);
+	return TRUE;
 }
 
-GnomeScanScanner*
-gsfile_scanner_new ()
+static void
+gsfile_scanner_end_frame(GnomeScanNode *node)
 {
-	GObject *object = g_object_new (GSFILE_TYPE_SCANNER,
-									/* translator: this is the name of the file
-									 loader backend which allow user to scan 
-									 a list a images */
-									"name", _("Files"),
-									"blurb", _("Import from files."),
-									"icon-name", "gnome-mime-image",
-									NULL);
-	return GNOME_SCAN_SCANNER (object);
+	GSFileScanner *self = GSFILE_SCANNER(node);
+	self->priv->current = g_slist_next(self->priv->current);
 }
 
-/* INTERNALS */
-
 static void
-gsf_configure (GnomeScanPlugin *plugin, GnomeScanSettings *settings)
+gsfile_scanner_on_filenames_modified(GSFileScanner* self, GParamSpec *pspec, GSFileOptionFilenames *option)
 {
-	GSFileScanner *scanner = GSFILE_SCANNER (plugin);
-	GValue *value;
-	
-	value = gnome_scan_settings_get (settings, "input-filenames");
-	scanner->filenames = g_value_get_pointer (value);
-	scanner->current = scanner->filenames;
-}
-
-static GList*
-gsf_get_child_nodes (GnomeScanPlugin *plugin,
-					 GeglNode *root)
-{
-	GSFileScanner *scanner = GSFILE_SCANNER (plugin);
-	GSFileScannerPrivate *priv = GET_PRIVATE (scanner);
-	GList *list = NULL;
-	
-	priv->load = gegl_node_new_child (root,
-									  "operation", "gegl:load",
-									  NULL);
-	
-	list = g_list_append (list, priv->load);
-	return list;
+	GSList *list;
+	GnomeScanStatus status;
+	g_return_if_fail(GSFILE_IS_SCANNER(self));
+	g_object_get(option, "value", &list, NULL);
+	self->priv->filenames = list;
+	self->priv->current = list;
+	status = g_slist_length(list) > 0 ? GNOME_SCAN_STATUS_READY : GNOME_SCAN_STATUS_UNCONFIGURED;
+	gnome_scan_node_update_status((GnomeScanNode*) self, status, NULL);
 }
 
 
-static gboolean
-gsf_start_frame (GnomeScanPlugin *plugin)
+
+
+
+/* GOBJECT */
+static GObject*
+gsfile_scanner_constructor(GType type, guint n_construct_properties, GObjectConstructParam* construct_params)
 {
-	GSFileScanner *scanner = GSFILE_SCANNER (plugin);
-	GSFileScannerPrivate *priv = GET_PRIVATE (scanner);
-	
-	if (scanner->current == NULL) {
-		return FALSE;
-	}
-	
-	gegl_node_set (priv->load,
-				   "path", scanner->current->data,
-				   NULL);
-	
-	scanner->current = scanner->current->next;
-	return TRUE;
+	GObject* object = G_OBJECT_CLASS(gsfile_scanner_parent_class)->constructor(type, n_construct_properties, construct_params);
+	GSFileScanner* self = GSFILE_SCANNER(object);
+	GSList *formats = NULL;
+	GSFileOptionFilenames *option;
+
+	static gchar* png_mime[] = {"image/png",NULL};
+	static gchar* png_exts[] = {"png",NULL};
+
+	formats = g_slist_append (formats,
+				  gnome_scan_format_new("png",
+							N_("PNG picture"),
+							GETTEXT_PACKAGE,
+							"image",
+							png_mime, G_N_ELEMENTS(png_mime),
+							png_exts, G_N_ELEMENTS(png_exts)));
+
+
+	static gchar *jpeg_mime[] = {"image/jpeg",NULL};
+	static gchar *jpeg_exts[] = {"jpeg","jpe","jpg",NULL};
+	formats = g_slist_append (formats,
+				  gnome_scan_format_new("jpeg",
+							N_("JPEG picture"),
+							GETTEXT_PACKAGE,
+							"image",
+							jpeg_mime, G_N_ELEMENTS(jpeg_mime),
+							jpeg_exts, G_N_ELEMENTS(jpeg_exts)));
+
+
+	option = gsfile_option_filenames_new("filenames", "Filenames", "Files to scan", GETTEXT_PACKAGE,
+					     GNOME_SCAN_OPTION_GROUP_SCANNER,
+					     formats,
+					     GNOME_SCAN_OPTION_HINT_PRIMARY);
+	g_signal_connect_swapped(option, "notify::value", G_CALLBACK(gsfile_scanner_on_filenames_modified), self);
+	gnome_scan_node_install_option((GnomeScanNode*) self, GNOME_SCAN_OPTION(option));
+
+	gnome_scan_node_update_status((GnomeScanNode*) self, GNOME_SCAN_STATUS_UNCONFIGURED, NULL);
+
+	/* construct gegl pipeline */
+	self->priv->load = gegl_node_new();
+	gegl_node_set(self->priv->load,
+		      "operation", "gegl:load",
+		      NULL);
+	gnome_scan_node_append_node(GNOME_SCAN_NODE(self), self->priv->load);
+
+	return object;
 }
 
-static gboolean
-gsf_work (GnomeScanPlugin *plugin, gdouble *progress)
+static void
+gsfile_scanner_class_init (GSFileScannerClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	GnomeScanNodeClass* node_class = GNOME_SCAN_NODE_CLASS(klass);
+
+	g_type_class_add_private (object_class, sizeof (GSFileScannerPrivate));
+
+	object_class->constructor	= gsfile_scanner_constructor;
+
+	node_class->start_scan	= gsfile_scanner_start_scan;
+	node_class->start_frame	= gsfile_scanner_start_frame;
+	node_class->end_frame	= gsfile_scanner_end_frame;
+}
+
+static void
+gsfile_scanner_init (GSFileScanner *self)
 {
-  *progress = 1.;
-  return FALSE;
+	self->priv = GSFILE_SCANNER_GET_PRIVATE(self);
+	self->priv->filenames = NULL;
+	self->priv->current = NULL;
 }

Modified: trunk/modules/gsfile-scanner.h
==============================================================================
--- trunk/modules/gsfile-scanner.h	(original)
+++ trunk/modules/gsfile-scanner.h	Sat Dec  6 17:38:48 2008
@@ -35,8 +35,9 @@
 #define GSFILE_IS_SCANNER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GSFILE_TYPE_SCANNER))
 #define GSFILE_SCANNER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GSFILE_TYPE_SCANNER, GSFileScannerClass))
 
-typedef struct _GSFileScannerClass GSFileScannerClass;
 typedef struct _GSFileScanner GSFileScanner;
+typedef struct _GSFileScannerClass GSFileScannerClass;
+typedef struct _GSFileScannerPrivate GSFileScannerPrivate;
 
 struct _GSFileScannerClass
 {
@@ -46,8 +47,7 @@
 struct _GSFileScanner
 {
 	GnomeScanScanner parent_instance;
-	GSList*	filenames;
-	GSList* current;
+	GSFileScannerPrivate* priv;
 };
 
 GType gsfile_scanner_get_type ();

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Sat Dec  6 17:38:48 2008
@@ -1,21 +1,13 @@
-lib/gnome-scan-acquisition-dialog.c
+flegita.desktop.in
 lib/gnome-scan-dialog.c
-lib/gnome-scan-init.c
-lib/gnome-scan-job.c
-lib/gnome-scan-paper-size-widget.c
-lib/gnome-scan-param-specs.c
-lib/gnome-scan-param-widget.c
-lib/gnome-scan-preview-plugin-area.c
-lib/gnome-scan-preview-plugin-rotation.c
-lib/gnome-scan-processor-common.c
-lib/gnome-scan-scanner.c
+lib/gnome-scan-node.c
+lib/gnome-scan-option-box.c
+lib/gnome-scan-scanner-selector.c
 modules/gsane-meta-param.c
 modules/gsfile-filenames-widget.c
 modules/gsfile-scanner.c
-src/flegita-action-selector.c
-src/flegita.c
 src/flegita-gimp.c
 src/flegita-gimp-sink.c
-src/flegita-output-filename-widget.c
+src/flegita-option-widgets.c
 src/flegita-sink.c
-flegita.desktop.in
+

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Sat Dec  6 17:38:48 2008
@@ -3,7 +3,8 @@
 	-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
 	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
 	$(GNOME_SCAN_CFLAGS) $(FLEGITA_CFLAGS) \
-	-I$(top_srcdir)/lib
+	-I$(top_srcdir)/lib \
+	-include ../config.h
 
 AM_CFLAGS = -Wall -g
 
@@ -12,77 +13,72 @@
 bin_PROGRAMS = \
 	flegita
 
-BUILT_HEADER = \
-	$(srcdir)/flegita-types.h
-
-BUILT_SOURCE = \
-	$(srcdir)/flegita-types.c
-
-types_deps = \
-	flegita.h \
+BUILT_SOURCES = \
+	flegita.vala.stamp	\
 	$(NULL)
 
-flegita-types.%: $(types_deps) Makefile flegita-types.%.tpl
-	test ! -e $@ && touch $@ || exit 0;
-	test -w $@ && glib-mkenums --template $(srcdir)/$  tpl $(types_deps) > $@ || exit 0
+flegita_VALASOURCES = \
+	flegita.vala			\
+	flegita-sink.vala		\
+	flegita-options.vala		\
+	flegita-option-widgets.vala	\
+	$(NULL)
 
+flegita_VALAPKGADD = \
+	--pkg=gtk+-2.0 \
+	--vapidir=$(top_srcdir)/ --pkg=config \
+	--vapidir=$(top_srcdir)/lib/ --pkg= VAPINAME@ \
+	$(NULL)
 
 flegita_SOURCES = \
-	$(BUILT_SOURCE) \
-	$(BUILT_HEADER) \
-	flegita.c				\
-	flegita.h				\
-	flegita-sink.h				\
-	flegita-sink.c				\
-	flegita-pspec.h				\
-	flegita-pspec.c				\
-	flegita-output-filename-widget.h	\
-	flegita-output-filename-widget.c        \
-	flegita-action-selector.h        \
-	flegita-action-selector.c 
+	flegita.vala.stamp \
+	$(flegita_VALASOURCES:.vala=.c) \
+	$(flegita_VALASOURCES:.vala=.h) \
+	$(NULL)
 
 flegita_LDFLAGS = \
 	$(GNOME_SCAN_LIBS) $(FLEGITA_LIBS) \
-	-L$(top_builddir)/lib -l SONAME@
+	-L$(top_builddir)/lib -l SONAME@ \
+	-export-dynamic
 
+flegita.vala.stamp: $(flegita_VALASOURCES)
+	$(VALAC) -C $(flegita_VALAPKGADD) --thread $^ && touch $@
 
 # FLEGITA-GIMP
 
-libgimpdir = $(GIMP_LIBDIR)/plug-ins
-libgimp_PROGRAMS = \
-	flegita-gimp 
-
-flegita_gimp_SOURCES = \
-	flegita-gimp.c\
-	flegita-gimp-sink.h                      \
-	flegita-gimp-sink.c 
-
-flegita_gimp_CFLAGS = \
-	-DPLUGIN_NAME=\""flegita-gimp"\" \
-	-DACTION_ICON_DIR=\""@ICON_DIR@/hicolor/scalable/actions"\" \
-	-DDATADIR=\""$(datadir)"\" \
-	$(FLEGITA_GIMP_CFLAGS)
-
-flegita_gimp_LDFLAGS = \
-	$(GNOME_SCAN_LIBS) \
-	$(FLEGITA_LIBS) \
-	$(FLEGITA_GIMP_LIBS) \
-	-L$(top_builddir)/lib -l SONAME@
-
-
-
-quick: $(libgimp_PROGRAMS)
-	mkdir -p ~/.gimp-2.3/plug-ins/.libs/
-	cp -r $(bin_PROGRAMS) ~/.gimp-2.2/plug-ins/
-	cp -r .libs/* ~/.gimp-2.3/plug-ins/.libs/
-
-
-EXTRA_DIST = \
-	flegita-types.h.tpl	\
-	flegita-types.c.tpl
+# libgimpdir = $(GIMP_LIBDIR)/plug-ins
+# libgimp_PROGRAMS = \
+# 	flegita-gimp 
+
+# flegita_gimp_SOURCES = \
+# 	flegita-gimp.c\
+# 	flegita-gimp-sink.h                      \
+# 	flegita-gimp-sink.c 
+
+# flegita_gimp_CFLAGS = \
+# 	-DPLUGIN_NAME=\""flegita-gimp"\" \
+# 	-DACTION_ICON_DIR=\""@ICON_DIR@/hicolor/scalable/actions"\" \
+# 	-DDATADIR=\""$(datadir)"\" \
+# 	$(FLEGITA_GIMP_CFLAGS)
+
+# flegita_gimp_LDFLAGS = \
+# 	$(GNOME_SCAN_LIBS) \
+# 	$(FLEGITA_LIBS) \
+# 	$(FLEGITA_GIMP_LIBS) \
+# 	-L$(top_builddir)/lib -l SONAME@
 
 
 
+# quick: $(libgimp_PROGRAMS)
+# 	mkdir -p ~/.gimp-2.3/plug-ins/.libs/
+# 	cp -r $(bin_PROGRAMS) ~/.gimp-2.2/plug-ins/
+# 	cp -r .libs/* ~/.gimp-2.3/plug-ins/.libs/
 
 
 
+EXTRA_DIST = \
+	flegita.vala.stamp	\
+	$(flegita_VALASOURCES)	\
+	$(wildcard flegita-gimp*.c)	\
+	$(wildcard flegita-gimp*.h)	\
+	$(NULL)

Added: trunk/src/flegita-option-widgets.vala
==============================================================================
--- (empty file)
+++ trunk/src/flegita-option-widgets.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,149 @@
+/* Flegita - Scanner utility
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * Flegita is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Flegita 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
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Flegita. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+
+using Config;
+using GLib;
+using Gtk;
+using Gdk;
+using Gnome.Scan;
+
+namespace Flegita {
+	enum FormatColumns {
+		ICON,
+		SUFFIX,
+		N
+	}
+
+	public class OutputFilenameWidget : OptionWidget {
+		private Entry entry;
+		private FileChooser filechooser;
+		private ListStore formats;
+		private ComboBox combobox;
+		private HashTable<string,string> format_paths;
+		private bool inhibit = false;
+
+		construct {
+			CellRenderer renderer;
+			OptionOutputFilename option = (OptionOutputFilename) this.option;
+			TreeIter iter;
+
+			this.no_label	= true;
+			this.expand		= false;
+			this.option.notify["value"] += this.parse_filename;
+			Box box = new HBox(false, 6);
+			this.pack_start(box, true, true, 0);
+
+			// directory selector
+			this.filechooser = new FileChooserButton(_("Select output directory"), FileChooserAction.SELECT_FOLDER);
+			box.pack_start(this.filechooser, true, true, 0);
+
+			// filename entry
+			this.entry = new Entry();
+			box.pack_start(this.entry, true, true, 0);
+
+			// format store
+			this.formats = new ListStore(FormatColumns.N, typeof(string), typeof(string));
+			this.format_paths = new HashTable<string,string>(GLib.str_hash, GLib.str_equal);
+			foreach(Gnome.Scan.Format format in option.list_formats()) {
+				this.formats.append(out iter);
+				this.formats.set(iter,
+								 FormatColumns.ICON, format.icon_name,
+								 FormatColumns.SUFFIX, format.suffixes[0]);
+				var path = this.formats.get_path(iter);
+				this.format_paths.insert(".%s".printf(format.suffixes[0]), path.to_string());
+			}
+
+			// format selector
+			this.combobox = new ComboBox.with_model(this.formats);
+			box.pack_start(this.combobox, false, false, 0);
+
+			renderer = new CellRendererPixbuf();
+			this.combobox.pack_start(renderer, false);
+			this.combobox.set_attributes(renderer, "icon-name", FormatColumns.ICON);
+
+			renderer = new CellRendererText();
+			this.combobox.pack_start(renderer, true);
+			this.combobox.set_attributes(renderer, "text", FormatColumns.SUFFIX);
+
+			this.filechooser.selection_changed += this.update_filename;
+			this.entry.changed += this.update_filename;
+			this.combobox.changed+= this.update_filename;
+			this.parse_filename();
+		}
+
+		private void update_filename()
+		{
+			if (this.inhibit)
+				return;
+
+			var option = this.option as OptionOutputFilename;
+			string suffix;
+			TreeIter iter;
+			bool format_selected = this.combobox.get_active_iter(out iter);
+			return_if_fail(format_selected);
+			this.formats.get(iter, FormatColumns.SUFFIX, out suffix);
+
+			this.inhibit = true;
+			option.value = "%s%c%s.%s".printf(this.filechooser.get_filename(),
+											  GLib.Path.DIR_SEPARATOR,
+											  this.entry.get_text(),
+											  suffix);
+			this.inhibit = false;
+		}
+
+		private void parse_filename()
+		{
+			if (this.inhibit)
+				return;
+
+			this.inhibit = true;
+			TreeIter iter;
+			var option = this.option as OptionOutputFilename;
+			string filename = option.value;
+			if (filename == null || filename.len() == 0)
+				return;
+
+			this.filechooser.set_current_folder(GLib.Path.get_dirname(filename));
+
+			string basename = GLib.Path.get_basename(filename);
+			string suffix = basename.rchr(-1, '.');
+			if (suffix == null) {
+				warning("unable to parse suffix in %s", basename);
+				return;
+			}
+
+			string path_string = this.format_paths.lookup(suffix);
+			if (!this.formats.get_iter_from_string(out iter, path_string)) {
+				warning("Invalid %s suffix", suffix);
+				return;
+			}
+			this.combobox.set_active_iter(iter);
+
+			var parts = basename.split(suffix, -1);
+			this.entry.set_text(parts[0]);
+
+			while(Gdk.events_pending())
+				Gtk.main_iteration();
+
+			this.inhibit = false;
+		}
+	}
+}
\ No newline at end of file

Added: trunk/src/flegita-options.vala
==============================================================================
--- (empty file)
+++ trunk/src/flegita-options.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,66 @@
+/* Flegita - Scanner utility
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * Flegita is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Flegita 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
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Flegita. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using Gnome.Scan;
+
+namespace Flegita {
+	public class OptionOutputFilename : Gnome.Scan.Option {
+		public string? value	{get; set;}
+
+		private string directory;
+		private string filename;
+		private Gnome.Scan.Format? format = null;
+
+		private SList<Gnome.Scan.Format> formats;
+
+		public OptionOutputFilename(string name, string title, string desc, string domain, string group, OptionHint hint)
+		{
+			this.name	= name;
+			this.title	= title;
+			this.desc	= desc;
+			this.domain	= domain;
+			this.group	= group;
+			this.hint	= hint;
+		}
+
+		public void install_format(Gnome.Scan.Format format)
+		{
+			this.formats.append(format);
+			if (this.format == null) {
+				this.format = this.formats.nth_data(0);
+				this.update_value();
+			}
+		}
+
+		public weak SList<Gnome.Scan.Format> list_formats()
+		{
+			return this.formats;
+		}
+
+		private void update_value()
+		{
+			if (this.directory.len() > 2 && this.filename.len() > 2 && this.format != null) 
+				this.value = this.directory.concat(GLib.Path.DIR_SEPARATOR_S, this.filename, ".", this.format.suffixes[0]);
+			else
+				this.value = null;
+		}
+	}
+}

Added: trunk/src/flegita-sink.vala
==============================================================================
--- (empty file)
+++ trunk/src/flegita-sink.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,103 @@
+/* Flegita - Scanner utility
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * Flegita is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Flegita 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
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Flegita. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using Config;
+using GLib;
+using Gegl;
+using Gnome.Scan;
+
+namespace Flegita {
+	public class Sink : Gnome.Scan.Sink {
+		private Gegl.Node _save;
+		private string directory;
+		private string basename;
+		private string suffix;
+		private int count = 0;
+
+		construct {
+			Gnome.Scan.Format format;
+			OptionOutputFilename option;
+			weak string gettext_package = GETTEXT_PACKAGE;
+
+			option = new OptionOutputFilename("output-filename", N_("Output Filename"), N_("Output filename"), GETTEXT_PACKAGE, OPTION_GROUP_SINK, OptionHint.PRIMARY);
+
+			format = new Gnome.Scan.Format("png", N_("PNG Picture"), GETTEXT_PACKAGE, "image",
+										   new string[] { "image/png" },
+										   new string[] { "png" });
+			option.install_format(format);
+			this.install_option(option);
+
+			option.value = "%s%c%s.%s".printf(GLib.Environment.get_user_special_dir(UserDirectory.PICTURES),
+											  GLib.Path.DIR_SEPARATOR,
+											  _("Scanned picture"),
+											  format.suffixes[0]);
+			option.notify["value"] += this.on_output_filename_changed;
+
+			// gegl pipeline
+			this._save = new Gegl.Node();
+			this._save.set("operation", "gegl:png-save",
+						   "compression", 9,
+						   "bitdepth", 8);
+			this.append_node(this._save);
+
+			this.update_status(Gnome.Scan.Status.READY, null);
+		}
+
+		public override bool start_frame()
+		{
+			string filename;
+			string number;
+			do {
+				if (count == 0)
+					number = "";
+				else
+					number = "-%d".printf(count);
+				filename = "%s%c%s%s%s".printf(directory,
+											   GLib.Path.DIR_SEPARATOR,
+											   basename,
+											   number,
+											   suffix);
+				count++;
+			} while(GLib.FileUtils.test(filename, FileTest.EXISTS));
+
+			debug("Saving to %s", filename);
+			this._save.set("path", filename);
+
+			return true;
+		}
+
+		private void on_output_filename_changed(OptionOutputFilename option, ParamSpec pspec)
+		{
+			// test directory existence?
+			count = 0;
+			directory = GLib.Path.get_dirname(option.value);
+			basename = GLib.Path.get_basename(option.value);
+			suffix = basename.rchr(-1, '.');
+			if (suffix != null)
+				basename = basename.replace(suffix, "");
+
+			if (GLib.FileUtils.test(directory, FileTest.IS_DIR|FileTest.EXISTS) && basename.len() > 0 && suffix != null)
+				this.update_status(Gnome.Scan.Status.READY, null);
+			else
+				this.update_status(Gnome.Scan.Status.UNCONFIGURED, null);
+		}
+	}
+}

Added: trunk/src/flegita.vala
==============================================================================
--- (empty file)
+++ trunk/src/flegita.vala	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,42 @@
+/* Flegita - Scanner utility
+ * Copyright  2006-2008  Ãtienne Bersac <bersace gnome org>
+ *
+ * Flegita is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Flegita 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
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Flegita. If not, write to:
+ *
+ *	the Free Software Foundation, Inc.
+ *	51 Franklin Street, Fifth Floor
+ *	Boston, MA 02110-1301, USA
+ */
+ 
+using Gtk;
+using Gnome.Scan;
+using Flegita;
+
+public int main(string[] args) {
+	Job job;
+	Gnome.Scan.Dialog dialog;
+	Flegita.Sink sink;
+
+	Gnome.Scan.init(ref args);
+	Gtk.init(ref args);
+
+	Gnome.Scan.option_manager.register_rule_by_type(typeof(Flegita.OptionOutputFilename), typeof(Flegita.OutputFilenameWidget));
+
+	sink = new Flegita.Sink();
+	job = new Gnome.Scan.Job(sink);
+	dialog = new Gnome.Scan.Dialog(null, job);
+	dialog.run();
+
+	return 0;
+}

Modified: trunk/tools/Makefile.am
==============================================================================
--- trunk/tools/Makefile.am	(original)
+++ trunk/tools/Makefile.am	Sat Dec  6 17:38:48 2008
@@ -1,24 +1,37 @@
+if ENABLE_TOOLS
 INCLUDES = \
 	$(GNOME_SCAN_CFLAGS)\
 	-DIMAGE_DIR="\"$(top_srcdir)/doc/ref/images\"" \
 	-I$(top_srcdir)/lib
 
 noinst_PROGRAMS = \
-	gs-scrot 
+	gs-test
 
-gs_scrot_SOURCES = \
-	gs-scrot.c 
+# gs_scrot_SOURCES = \
+# 	gs-scrot.c 
 
-gs_scrot_CFLAGS = \
-	$(GNOME_SCAN_CFLAGS) $(FLEGITA_CFLAGS) $(TOOLS_CFLAGS)
-
-gs_scrot_LDFLAGS = \
-	$(GNOME_SCAN_LIBS) $(FLEGITA_LIBS) $(TOOLS_LIBS) \
-	-L$(top_builddir)/lib -lgnomescan \
-	-export-dynamic
+# gs_scrot_CFLAGS = \
+# 	$(GNOME_SCAN_CFLAGS) $(FLEGITA_CFLAGS) $(TOOLS_CFLAGS)
 
-## File created by the gnome-build tools
+# gs_scrot_LDFLAGS = \
+# 	$(GNOME_SCAN_LIBS) $(FLEGITA_LIBS) $(TOOLS_LIBS) \
+# 	-L$(top_builddir)/lib -l SONAME@ \
+# 	-export-dynamic
 
+gs_test_SOURCES = \
+	gs-test.c 
 
+gs_test_CFLAGS = \
+	$(GNOME_SCAN_CFLAGS) $(FLEGITA_CFLAGS) $(TOOLS_CFLAGS)
 
+gs_test_LDFLAGS = \
+	$(GNOME_SCAN_LIBS) $(FLEGITA_LIBS) $(TOOLS_LIBS) \
+	-L$(top_builddir)/lib -l SONAME@ \
+	-export-dynamic
+else
+EXTRA_DIST = \
+	$(wildcard *.c)	\
+	$(wildcard *.h)	\
+	$(NULL)
 
+endif
\ No newline at end of file

Added: trunk/tools/gs-test.c
==============================================================================
--- (empty file)
+++ trunk/tools/gs-test.c	Sat Dec  6 17:38:48 2008
@@ -0,0 +1,38 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gegl.h>
+
+gint main(gint argc, gchar ** argv)
+{
+	g_type_init();
+	gegl_init(&argc, &argv);
+
+	GeglNode* load;
+	GeglNode* save;
+	GeglProcessor* proc;
+	gdouble progress;
+
+	load = gegl_node_new();
+	gegl_node_set(load,
+		      "operation", "gegl:load",
+		      "path", "/home/bersace/baussant.jpeg",
+		      NULL);
+	save = gegl_node_new();
+	gegl_node_set(save,
+		      "operation", "gegl:png-save",
+		      "path", "/home/bersace/Bureau/baussant.png",
+		      "compression", 9,
+		      NULL);
+	gegl_node_link(load, save);
+	proc = gegl_node_new_processor(save, NULL);
+	while(gegl_processor_work(proc, &progress))
+		g_debug("%.0f%%", progress*100.);
+	gegl_processor_destroy(proc);
+	g_object_unref(save);
+	g_object_unref(load);
+
+	gegl_exit();
+	return 0;
+}



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