diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 40 | ||||
| -rw-r--r-- | src/Makefile.in | 103 | ||||
| -rw-r--r-- | src/book-view.c | 2090 | ||||
| -rw-r--r-- | src/book-view.h | 59 | ||||
| -rw-r--r-- | src/book-view.vala | 594 | ||||
| -rw-r--r-- | src/book.c | 2925 | ||||
| -rw-r--r-- | src/book.h | 69 | ||||
| -rw-r--r-- | src/book.vala | 571 | ||||
| -rw-r--r-- | src/colord.vapi | 17 | ||||
| -rw-r--r-- | src/config.vapi | 10 | ||||
| -rw-r--r-- | src/jpeglib.vapi | 57 | ||||
| -rw-r--r-- | src/page-view.c | 3036 | ||||
| -rw-r--r-- | src/page-view.h | 79 | ||||
| -rw-r--r-- | src/page-view.vala | 1043 | ||||
| -rw-r--r-- | src/page.c | 2559 | ||||
| -rw-r--r-- | src/page.h | 126 | ||||
| -rw-r--r-- | src/page.vala | 735 | ||||
| -rw-r--r-- | src/sane.vapi | 757 | ||||
| -rw-r--r-- | src/scanner.c | 7763 | ||||
| -rw-r--r-- | src/scanner.h | 132 | ||||
| -rw-r--r-- | src/scanner.vala | 1472 | ||||
| -rw-r--r-- | src/simple-scan.c | 2006 | ||||
| -rw-r--r-- | src/simple-scan.vala | 516 | ||||
| -rw-r--r-- | src/simple_scan_vala.stamp | 0 | ||||
| -rw-r--r-- | src/ui.c | 5281 | ||||
| -rw-r--r-- | src/ui.h | 70 | ||||
| -rw-r--r-- | src/ui.vala | 1458 | 
27 files changed, 25582 insertions, 7986 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8a4f587..3fa8558 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,22 +1,31 @@  bin_PROGRAMS = simple-scan  simple_scan_SOURCES = \ -	book.c \ -	book.h \ -	book-view.c \ -	book-view.h \ -	page.c \ -	page.h \ -	page-view.c \ -	page-view.h \ -	simple-scan.c \ -	scanner.c \ -	scanner.h \ -	ui.c \ -	ui.h +	config.vapi \ +	book.vala \ +	book-view.vala \ +	colord.vapi \ +	jpeglib.vapi \ +	page.vala \ +	page-view.vala \ +	sane.vapi \ +	simple-scan.vala \ +	scanner.vala \ +	ui.vala + +simple_scan_VALAFLAGS = \ +	--pkg=zlib \ +	--pkg=gudev-1.0 \ +	--pkg=gio-2.0 \ +	--pkg=gtk+-3.0 + +if HAVE_COLORD +simple_scan_VALAFLAGS += -D HAVE_COLORD +endif  simple_scan_CFLAGS = \  	$(SIMPLE_SCAN_CFLAGS) \ +	$(COLORD_CFLAGS) \  	$(WARN_CFLAGS) \  	-DVERSION=\"$(VERSION)\" \  	-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ @@ -28,9 +37,14 @@ simple_scan_CFLAGS = \  simple_scan_LDADD = \  	$(SIMPLE_SCAN_LIBS) \ +	$(COLORD_LIBS) \  	-lsane \  	-ljpeg \  	-lm +CLEANFILES = \ +	$(patsubst %.vala,%.c,$(filter %.vala, $(SOURCES))) \ +	*_vala.stamp +  DISTCLEANFILES = \  	Makefile.in diff --git a/src/Makefile.in b/src/Makefile.in index 946fc6c..33521bc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -33,13 +33,17 @@ NORMAL_UNINSTALL = :  PRE_UNINSTALL = :  POST_UNINSTALL = :  bin_PROGRAMS = simple-scan$(EXEEXT) +@HAVE_COLORD_TRUE@am__append_1 = -D HAVE_COLORD  subdir = src -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in book-view.c \ +	book.c page-view.c page.c scanner.c simple-scan.c \ +	simple_scan_vala.stamp ui.c  ACLOCAL_M4 = $(top_srcdir)/aclocal.m4  am__aclocal_m4_deps = $(top_srcdir)/configure.ac  am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \  	$(ACLOCAL_M4)  mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h  CONFIG_CLEAN_FILES =  CONFIG_CLEAN_VPATH_FILES =  am__installdirs = "$(DESTDIR)$(bindir)" @@ -51,10 +55,10 @@ am_simple_scan_OBJECTS = simple_scan-book.$(OBJEXT) \  	simple_scan-scanner.$(OBJEXT) simple_scan-ui.$(OBJEXT)  simple_scan_OBJECTS = $(am_simple_scan_OBJECTS)  am__DEPENDENCIES_1 = -simple_scan_DEPENDENCIES = $(am__DEPENDENCIES_1) +simple_scan_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)  simple_scan_LINK = $(CCLD) $(simple_scan_CFLAGS) $(CFLAGS) \  	$(AM_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)  depcomp = $(SHELL) $(top_srcdir)/depcomp  am__depfiles_maybe = depfiles  am__mv = mv -f @@ -74,6 +78,10 @@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@  AM_V_CCLD = $(am__v_CCLD_$(V))  am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))  am__v_CCLD_0 = @echo "  CCLD  " $@; +VALACOMPILE = $(VALAC) $(AM_VALAFLAGS) $(VALAFLAGS) +AM_V_VALAC = $(am__v_VALAC_$(V)) +am__v_VALAC_ = $(am__v_VALAC_$(AM_DEFAULT_VERBOSITY)) +am__v_VALAC_0 = @echo "  VALAC " $@;  AM_V_GEN = $(am__v_GEN_$(V))  am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))  am__v_GEN_0 = @echo "  GEN   " $@; @@ -93,6 +101,8 @@ AWK = @AWK@  CC = @CC@  CCDEPMODE = @CCDEPMODE@  CFLAGS = @CFLAGS@ +COLORD_CFLAGS = @COLORD_CFLAGS@ +COLORD_LIBS = @COLORD_LIBS@  CPP = @CPP@  CPPFLAGS = @CPPFLAGS@  CYGPATH_W = @CYGPATH_W@ @@ -107,11 +117,11 @@ ECHO_N = @ECHO_N@  ECHO_T = @ECHO_T@  EGREP = @EGREP@  EXEEXT = @EXEEXT@ -GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@ -GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@  GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLIB_COMPILE_SCHEMAS = @GLIB_COMPILE_SCHEMAS@  GMSGFMT = @GMSGFMT@  GREP = @GREP@ +GSETTINGS_DISABLE_SCHEMAS_COMPILE = @GSETTINGS_DISABLE_SCHEMAS_COMPILE@  HELP_DIR = @HELP_DIR@  INSTALL = @INSTALL@  INSTALL_DATA = @INSTALL_DATA@ @@ -151,6 +161,7 @@ SIMPLE_SCAN_CFLAGS = @SIMPLE_SCAN_CFLAGS@  SIMPLE_SCAN_LIBS = @SIMPLE_SCAN_LIBS@  STRIP = @STRIP@  USE_NLS = @USE_NLS@ +VALAC = @VALAC@  VERSION = @VERSION@  WARN_CFLAGS = @WARN_CFLAGS@  XGETTEXT = @XGETTEXT@ @@ -172,6 +183,7 @@ datarootdir = @datarootdir@  docdir = @docdir@  dvidir = @dvidir@  exec_prefix = @exec_prefix@ +gsettingsschemadir = @gsettingsschemadir@  host_alias = @host_alias@  htmldir = @htmldir@  includedir = @includedir@ @@ -197,22 +209,23 @@ top_build_prefix = @top_build_prefix@  top_builddir = @top_builddir@  top_srcdir = @top_srcdir@  simple_scan_SOURCES = \ -	book.c \ -	book.h \ -	book-view.c \ -	book-view.h \ -	page.c \ -	page.h \ -	page-view.c \ -	page-view.h \ -	simple-scan.c \ -	scanner.c \ -	scanner.h \ -	ui.c \ -	ui.h - +	config.vapi \ +	book.vala \ +	book-view.vala \ +	colord.vapi \ +	jpeglib.vapi \ +	page.vala \ +	page-view.vala \ +	sane.vapi \ +	simple-scan.vala \ +	scanner.vala \ +	ui.vala + +simple_scan_VALAFLAGS = --pkg=zlib --pkg=gudev-1.0 --pkg=gio-2.0 \ +	--pkg=gtk+-3.0 $(am__append_1)  simple_scan_CFLAGS = \  	$(SIMPLE_SCAN_CFLAGS) \ +	$(COLORD_CFLAGS) \  	$(WARN_CFLAGS) \  	-DVERSION=\"$(VERSION)\" \  	-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ @@ -224,10 +237,15 @@ simple_scan_CFLAGS = \  simple_scan_LDADD = \  	$(SIMPLE_SCAN_LIBS) \ +	$(COLORD_LIBS) \  	-lsane \  	-ljpeg \  	-lm +CLEANFILES = \ +	$(patsubst %.vala,%.c,$(filter %.vala, $(SOURCES))) \ +	*_vala.stamp +  DISTCLEANFILES = \  	Makefile.in @@ -447,6 +465,44 @@ simple_scan-ui.obj: ui.c  @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ui.c' object='simple_scan-ui.obj' libtool=no @AMDEPBACKSLASH@  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@  @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simple_scan_CFLAGS) $(CFLAGS) -c -o simple_scan-ui.obj `if test -f 'ui.c'; then $(CYGPATH_W) 'ui.c'; else $(CYGPATH_W) '$(srcdir)/ui.c'; fi` +$(srcdir)/book.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +$(srcdir)/book-view.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +$(srcdir)/page.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +$(srcdir)/page-view.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +$(srcdir)/simple-scan.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +$(srcdir)/scanner.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +$(srcdir)/ui.c: $(srcdir)/simple_scan_vala.stamp +	@if test -f $@; then :; else \ +	  rm -f $(srcdir)/simple_scan_vala.stamp; \ +	  $(am__cd) $(srcdir) && $(MAKE) $(AM_MAKEFLAGS) simple_scan_vala.stamp; \ +	fi +simple_scan_vala.stamp: $(simple_scan_SOURCES) +	$(AM_V_VALAC)$(VALAC) $(simple_scan_VALAFLAGS) $(VALAFLAGS) -C $(simple_scan_SOURCES) +	$(AM_V_at)touch $@  ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)  	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -554,6 +610,7 @@ install-strip:  mostlyclean-generic:  clean-generic: +	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)  distclean-generic:  	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -563,6 +620,14 @@ distclean-generic:  maintainer-clean-generic:  	@echo "This command is intended for maintainers to use"  	@echo "it deletes files that may require special tools to rebuild." +	-rm -f book-view.c +	-rm -f book.c +	-rm -f page-view.c +	-rm -f page.c +	-rm -f scanner.c +	-rm -f simple-scan.c +	-rm -f simple_scan_vala.stamp +	-rm -f ui.c  clean: clean-am  clean-am: clean-binPROGRAMS clean-generic mostlyclean-am diff --git a/src/book-view.c b/src/book-view.c index ac6e32c..5d2e84d 100644 --- a/src/book-view.c +++ b/src/book-view.c @@ -1,806 +1,1554 @@ +/* book-view.c generated by valac 0.13.1, the Vala compiler + * generated from book-view.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later   * version. See http://www.gnu.org/copyleft/gpl.html the full text of the   * license.   */ +/* FIXME: When scrolling, copy existing render sideways?*/ +/* FIXME: Only render pages that change and only the part that changed*/ + +#include <glib.h> +#include <glib-object.h> +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <cairo.h> +#include <float.h> +#include <math.h> + + +#define TYPE_BOOK_VIEW (book_view_get_type ()) +#define BOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOOK_VIEW, BookView)) +#define BOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BOOK_VIEW, BookViewClass)) +#define IS_BOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOOK_VIEW)) +#define IS_BOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BOOK_VIEW)) +#define BOOK_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BOOK_VIEW, BookViewClass)) + +typedef struct _BookView BookView; +typedef struct _BookViewClass BookViewClass; +typedef struct _BookViewPrivate BookViewPrivate; + +#define TYPE_BOOK (book_get_type ()) +#define BOOK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOOK, Book)) +#define BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BOOK, BookClass)) +#define IS_BOOK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOOK)) +#define IS_BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BOOK)) +#define BOOK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BOOK, BookClass)) + +typedef struct _Book Book; +typedef struct _BookClass BookClass; + +#define TYPE_PAGE (page_get_type ()) +#define PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE, Page)) +#define PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE, PageClass)) +#define IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE)) +#define IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE)) +#define PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE, PageClass)) + +typedef struct _Page Page; +typedef struct _PageClass PageClass; + +#define TYPE_PAGE_VIEW (page_view_get_type ()) +#define PAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE_VIEW, PageView)) +#define PAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE_VIEW, PageViewClass)) +#define IS_PAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE_VIEW)) +#define IS_PAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE_VIEW)) +#define PAGE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE_VIEW, PageViewClass)) + +typedef struct _PageView PageView; +typedef struct _PageViewClass PageViewClass; +#define _book_unref0(var) ((var == NULL) ? NULL : (var = (book_unref (var), NULL))) +#define _g_hash_table_unref0(var) ((var == NULL) ? NULL : (var = (g_hash_table_unref (var), NULL))) +#define _page_view_unref0(var) ((var == NULL) ? NULL : (var = (page_view_unref (var), NULL))) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _page_unref0(var) ((var == NULL) ? NULL : (var = (page_unref (var), NULL))) + +struct _BookView { +	GtkVBox parent_instance; +	BookViewPrivate * priv; +}; -#include <gdk/gdkkeysyms.h> +struct _BookViewClass { +	GtkVBoxClass parent_class; +}; -#include "book-view.h" -#include "page-view.h" +struct _BookViewPrivate { +	Book* book; +	GHashTable* page_data; +	gboolean need_layout; +	gboolean laying_out; +	gboolean show_selected_page; +	PageView* selected_page; +	GtkWidget* drawing_area; +	GtkHScrollbar* scroll; +	GtkAdjustment* adjustment; +	GdkCursorType cursor; +}; -// FIXME: When scrolling, copy existing render sideways? -// FIXME: Only render pages that change and only the part that changed -enum { -    PROP_0, -    PROP_BOOK +static gpointer book_view_parent_class = NULL; + +GType book_view_get_type (void) G_GNUC_CONST; +gpointer book_ref (gpointer instance); +void book_unref (gpointer instance); +GParamSpec* param_spec_book (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_book (GValue* value, gpointer v_object); +void value_take_book (GValue* value, gpointer v_object); +gpointer value_get_book (const GValue* value); +GType book_get_type (void) G_GNUC_CONST; +gpointer page_ref (gpointer instance); +void page_unref (gpointer instance); +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page (GValue* value, gpointer v_object); +void value_take_page (GValue* value, gpointer v_object); +gpointer value_get_page (const GValue* value); +GType page_get_type (void) G_GNUC_CONST; +gpointer page_view_ref (gpointer instance); +void page_view_unref (gpointer instance); +GParamSpec* param_spec_page_view (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page_view (GValue* value, gpointer v_object); +void value_take_page_view (GValue* value, gpointer v_object); +gpointer value_get_page_view (const GValue* value); +GType page_view_get_type (void) G_GNUC_CONST; +#define BOOK_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_BOOK_VIEW, BookViewPrivate)) +enum  { +	BOOK_VIEW_DUMMY_PROPERTY  }; +BookView* book_view_new (Book* book); +BookView* book_view_construct (GType object_type, Book* book); +guint book_get_n_pages (Book* self); +Page* book_get_page (Book* self, gint page_number); +static void book_view_add_cb (BookView* self, Book* book, Page* page); +void book_view_select_page (BookView* self, Page* page); +static void _book_view_add_cb_book_page_added (Book* _sender, Page* page, gpointer self); +static void book_view_remove_cb (BookView* self, Book* book, Page* page); +static void _book_view_remove_cb_book_page_removed (Book* _sender, Page* page, gpointer self); +static void book_view_reorder_cb (BookView* self, Book* book); +static void _book_view_reorder_cb_book_reordered (Book* _sender, gpointer self); +static void book_view_clear_cb (BookView* self, Book* book); +static void _book_view_clear_cb_book_cleared (Book* _sender, gpointer self); +static void _page_unref0_ (gpointer var); +static void _page_view_unref0_ (gpointer var); +static gboolean book_view_configure_cb (BookView* self, GtkWidget* widget, GdkEventConfigure* event); +static gboolean _book_view_configure_cb_gtk_widget_configure_event (GtkWidget* _sender, GdkEventConfigure* event, gpointer self); +static gboolean book_view_draw_cb (BookView* self, GtkWidget* widget, cairo_t* context); +static gboolean _book_view_draw_cb_gtk_widget_draw (GtkWidget* _sender, cairo_t* cr, gpointer self); +static gboolean book_view_motion_cb (BookView* self, GtkWidget* widget, GdkEventMotion* event); +static gboolean _book_view_motion_cb_gtk_widget_motion_notify_event (GtkWidget* _sender, GdkEventMotion* event, gpointer self); +static gboolean book_view_key_cb (BookView* self, GtkWidget* widget, GdkEventKey* event); +static gboolean _book_view_key_cb_gtk_widget_key_press_event (GtkWidget* _sender, GdkEventKey* event, gpointer self); +static gboolean book_view_button_cb (BookView* self, GtkWidget* widget, GdkEventButton* event); +static gboolean _book_view_button_cb_gtk_widget_button_press_event (GtkWidget* _sender, GdkEventButton* event, gpointer self); +static gboolean _book_view_button_cb_gtk_widget_button_release_event (GtkWidget* _sender, GdkEventButton* event, gpointer self); +static gboolean book_view_focus_cb (BookView* self, GtkWidget* widget, GdkEventFocus* event); +static gboolean _book_view_focus_cb_gtk_widget_focus_in_event (GtkWidget* _sender, GdkEventFocus* event, gpointer self); +static gboolean _book_view_focus_cb_gtk_widget_focus_out_event (GtkWidget* _sender, GdkEventFocus* event, gpointer self); +static void book_view_scroll_cb (BookView* self, GtkAdjustment* adjustment); +static void _book_view_scroll_cb_gtk_adjustment_value_changed (GtkAdjustment* _sender, gpointer self); +static PageView* book_view_get_nth_page (BookView* self, gint n); +static PageView* book_view_get_next_page (BookView* self, PageView* page); +Page* page_view_get_page (PageView* self); +static PageView* book_view_get_prev_page (BookView* self, PageView* page); +static void book_view_page_view_changed_cb (BookView* self, PageView* page); +void book_view_redraw (BookView* self); +static void book_view_page_view_size_changed_cb (BookView* self, PageView* page); +PageView* page_view_new (Page* page); +PageView* page_view_construct (GType object_type, Page* page); +static void _book_view_page_view_changed_cb_page_view_changed (PageView* _sender, gpointer self); +static void _book_view_page_view_size_changed_cb_page_view_size_changed (PageView* _sender, gpointer self); +static void book_view_set_selected_page (BookView* self, PageView* page); +void page_view_set_selected (PageView* self, gboolean selected); +static void book_view_set_x_offset (BookView* self, gint offset); +static gint book_view_get_x_offset (BookView* self); +static void book_view_show_page_view (BookView* self, PageView* page); +gint page_view_get_x_offset (PageView* self); +gint page_view_get_width (PageView* self); +static void book_view_select_page_view (BookView* self, PageView* page); +Page* book_view_get_selected (BookView* self); +Book* book_view_get_book (BookView* self); +static void book_view_layout_into (BookView* self, gint width, gint height, gint* book_width, gint* book_height); +gint page_get_dpi (Page* self); +gint page_get_width (Page* self); +gint page_get_height (Page* self); +void page_view_set_width (PageView* self, gint width); +void page_view_set_height (PageView* self, gint height); +gint page_view_get_height (PageView* self); +void page_view_set_x_offset (PageView* self, gint offset); +void page_view_set_y_offset (PageView* self, gint offset); +static void book_view_layout (BookView* self); +void page_view_render (PageView* self, cairo_t* context); +gboolean page_view_get_selected (PageView* self); +gint page_view_get_y_offset (PageView* self); +static PageView* book_view_get_page_at (BookView* self, gint x, gint y, gint* x_, gint* y_); +void page_view_button_press (PageView* self, gint x, gint y); +void page_view_button_release (PageView* self, gint x, gint y); +static void book_view_set_cursor (BookView* self, GdkCursorType cursor); +void page_view_motion (PageView* self, gint x, gint y); +GdkCursorType page_view_get_cursor (PageView* self); +void book_view_select_next_page (BookView* self); +void book_view_select_prev_page (BookView* self); +static void g_cclosure_user_marshal_VOID__PAGE (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); +static void book_view_finalize (GObject* obj); + + +static gpointer _book_ref0 (gpointer self) { +	return self ? book_ref (self) : NULL; +} + + +static void _book_view_add_cb_book_page_added (Book* _sender, Page* page, gpointer self) { +	book_view_add_cb (self, _sender, page); +} + + +static void _book_view_remove_cb_book_page_removed (Book* _sender, Page* page, gpointer self) { +	book_view_remove_cb (self, _sender, page); +} + + +static void _book_view_reorder_cb_book_reordered (Book* _sender, gpointer self) { +	book_view_reorder_cb (self, _sender); +} + + +static void _book_view_clear_cb_book_cleared (Book* _sender, gpointer self) { +	book_view_clear_cb (self, _sender); +} + + +static void _page_unref0_ (gpointer var) { +	(var == NULL) ? NULL : (var = (page_unref (var), NULL)); +} + + +static void _page_view_unref0_ (gpointer var) { +	(var == NULL) ? NULL : (var = (page_view_unref (var), NULL)); +} + + +static gpointer _g_object_ref0 (gpointer self) { +	return self ? g_object_ref (self) : NULL; +} + + +static gboolean _book_view_configure_cb_gtk_widget_configure_event (GtkWidget* _sender, GdkEventConfigure* event, gpointer self) { +	gboolean result; +	result = book_view_configure_cb (self, _sender, event); +	return result; +} -enum { -    PAGE_SELECTED, -    SHOW_PAGE, -    SHOW_MENU, -    LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0, }; - -struct BookViewPrivate -{ -    /* Book being rendered */ -    Book *book; -    GHashTable *page_data; -     -    /* True if the view needs to be laid out again */ -    gboolean need_layout, laying_out, show_selected_page; - -    /* Currently selected page */ -    PageView *selected_page; -   -    /* Widget being rendered to */ -    GtkWidget *drawing_area; - -    /* Horizontal scrollbar */ -    GtkWidget *scroll; -    GtkAdjustment *adjustment; - -    gint cursor; -}; -G_DEFINE_TYPE (BookView, book_view, GTK_TYPE_VBOX); +static gboolean _book_view_draw_cb_gtk_widget_draw (GtkWidget* _sender, cairo_t* cr, gpointer self) { +	gboolean result; +	result = book_view_draw_cb (self, _sender, cr); +	return result; +} -BookView * -book_view_new (Book *book) -{ -    return g_object_new (BOOK_VIEW_TYPE, "book", book, NULL); +static gboolean _book_view_motion_cb_gtk_widget_motion_notify_event (GtkWidget* _sender, GdkEventMotion* event, gpointer self) { +	gboolean result; +	result = book_view_motion_cb (self, _sender, event); +	return result;  } -static PageView * -get_nth_page (BookView *view, gint n) -{ -    Page *page = book_get_page (view->priv->book, n); -    return g_hash_table_lookup (view->priv->page_data, page); +static gboolean _book_view_key_cb_gtk_widget_key_press_event (GtkWidget* _sender, GdkEventKey* event, gpointer self) { +	gboolean result; +	result = book_view_key_cb (self, _sender, event); +	return result;  } -static PageView * -get_next_page (BookView *view, PageView *page) -{ -    gint i; -     -    for (i = 0; ; i++) { -        Page *p; -        p = book_get_page (view->priv->book, i); -        if (!p) -            break; -        if (p == page_view_get_page (page)) { -            p = book_get_page (view->priv->book, i + 1); -            if (p) -                return g_hash_table_lookup (view->priv->page_data, p); -        } -    } -     -    return page; +static gboolean _book_view_button_cb_gtk_widget_button_press_event (GtkWidget* _sender, GdkEventButton* event, gpointer self) { +	gboolean result; +	result = book_view_button_cb (self, _sender, event); +	return result;  } -static PageView * -get_prev_page (BookView *view, PageView *page) -{ -    gint i; -    PageView *prev_page = page; +static gboolean _book_view_button_cb_gtk_widget_button_release_event (GtkWidget* _sender, GdkEventButton* event, gpointer self) { +	gboolean result; +	result = book_view_button_cb (self, _sender, event); +	return result; +} -    for (i = 0; ; i++) { -        Page *p; -        p = book_get_page (view->priv->book, i); -        if (!p) -            break; -        if (p == page_view_get_page (page)) -            return prev_page; -        prev_page = g_hash_table_lookup (view->priv->page_data, p); -    } -    return page; +static gboolean _book_view_focus_cb_gtk_widget_focus_in_event (GtkWidget* _sender, GdkEventFocus* event, gpointer self) { +	gboolean result; +	result = book_view_focus_cb (self, _sender, event); +	return result;  } -static void -page_view_changed_cb (PageView *page, BookView *view) -{ -    book_view_redraw (view); +static gboolean _book_view_focus_cb_gtk_widget_focus_out_event (GtkWidget* _sender, GdkEventFocus* event, gpointer self) { +	gboolean result; +	result = book_view_focus_cb (self, _sender, event); +	return result;  } -static void -page_view_size_changed_cb (PageView *page, BookView *view) -{ -    view->priv->need_layout = TRUE; -    book_view_redraw (view); +static void _book_view_scroll_cb_gtk_adjustment_value_changed (GtkAdjustment* _sender, gpointer self) { +	book_view_scroll_cb (self, _sender);  } -static void -add_cb (Book *book, Page *page, BookView *view) -{ -    PageView *page_view; -    page_view = page_view_new (page); -    g_signal_connect (page_view, "changed", G_CALLBACK (page_view_changed_cb), view); -    g_signal_connect (page_view, "size-changed", G_CALLBACK (page_view_size_changed_cb), view);   -    g_hash_table_insert (view->priv->page_data, page, page_view); -    view->priv->need_layout = TRUE; -    book_view_redraw (view); +BookView* book_view_construct (GType object_type, Book* book) { +	BookView * self = NULL; +	Book* _tmp0_; +	Page* _tmp4_ = NULL; +	Page* _tmp5_; +	GHashTable* _tmp6_ = NULL; +	GtkDrawingArea* _tmp7_ = NULL; +	GtkHScrollbar* _tmp8_ = NULL; +	GtkAdjustment* _tmp9_ = NULL; +	GtkAdjustment* _tmp10_; +	g_return_val_if_fail (book != NULL, NULL); +	self = (BookView*) g_object_new (object_type, NULL); +	_tmp0_ = _book_ref0 (book); +	_book_unref0 (self->priv->book); +	self->priv->book = _tmp0_; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp1_; +			_tmp1_ = TRUE; +			while (TRUE) { +				guint _tmp2_; +				Page* _tmp3_ = NULL; +				Page* page; +				if (!_tmp1_) { +					i++; +				} +				_tmp1_ = FALSE; +				_tmp2_ = book_get_n_pages (book); +				if (!(((guint) i) < _tmp2_)) { +					break; +				} +				_tmp3_ = book_get_page (book, i); +				page = _tmp3_; +				book_view_add_cb (self, book, page); +				_page_unref0 (page); +			} +		} +	} +	_tmp4_ = book_get_page (book, 0); +	_tmp5_ = _tmp4_; +	book_view_select_page (self, _tmp5_); +	_page_unref0 (_tmp5_); +	g_signal_connect_object (book, "page-added", (GCallback) _book_view_add_cb_book_page_added, self, 0); +	g_signal_connect_object (book, "page-removed", (GCallback) _book_view_remove_cb_book_page_removed, self, 0); +	g_signal_connect_object (book, "reordered", (GCallback) _book_view_reorder_cb_book_reordered, self, 0); +	g_signal_connect_object (book, "cleared", (GCallback) _book_view_clear_cb_book_cleared, self, 0); +	self->priv->need_layout = TRUE; +	_tmp6_ = g_hash_table_new_full (g_direct_hash, g_direct_equal, _page_unref0_, _page_view_unref0_); +	_g_hash_table_unref0 (self->priv->page_data); +	self->priv->page_data = _tmp6_; +	self->priv->cursor = GDK_ARROW; +	_tmp7_ = (GtkDrawingArea*) gtk_drawing_area_new (); +	_g_object_unref0 (self->priv->drawing_area); +	self->priv->drawing_area = (GtkWidget*) g_object_ref_sink (_tmp7_); +	gtk_widget_set_size_request (self->priv->drawing_area, 200, 100); +	gtk_widget_set_can_focus (self->priv->drawing_area, TRUE); +	gtk_widget_set_events (self->priv->drawing_area, (gint) (((((GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK) | GDK_BUTTON_RELEASE_MASK) | GDK_FOCUS_CHANGE_MASK) | GDK_STRUCTURE_MASK) | GDK_SCROLL_MASK)); +	gtk_box_pack_start ((GtkBox*) self, self->priv->drawing_area, TRUE, TRUE, (guint) 0); +	_tmp8_ = (GtkHScrollbar*) gtk_hscrollbar_new (NULL); +	_g_object_unref0 (self->priv->scroll); +	self->priv->scroll = g_object_ref_sink (_tmp8_); +	_tmp9_ = gtk_range_get_adjustment ((GtkRange*) self->priv->scroll); +	_tmp10_ = _g_object_ref0 (_tmp9_); +	_g_object_unref0 (self->priv->adjustment); +	self->priv->adjustment = _tmp10_; +	gtk_box_pack_start ((GtkBox*) self, (GtkWidget*) self->priv->scroll, FALSE, TRUE, (guint) 0); +	g_signal_connect_object (self->priv->drawing_area, "configure-event", (GCallback) _book_view_configure_cb_gtk_widget_configure_event, self, 0); +	g_signal_connect_object (self->priv->drawing_area, "draw", (GCallback) _book_view_draw_cb_gtk_widget_draw, self, 0); +	g_signal_connect_object (self->priv->drawing_area, "motion-notify-event", (GCallback) _book_view_motion_cb_gtk_widget_motion_notify_event, self, 0); +	g_signal_connect_object (self->priv->drawing_area, "key-press-event", (GCallback) _book_view_key_cb_gtk_widget_key_press_event, self, 0); +	g_signal_connect_object (self->priv->drawing_area, "button-press-event", (GCallback) _book_view_button_cb_gtk_widget_button_press_event, self, 0); +	g_signal_connect_object (self->priv->drawing_area, "button-release-event", (GCallback) _book_view_button_cb_gtk_widget_button_release_event, self, 0); +	g_signal_connect_object (self->priv->drawing_area, "focus-in-event", (GCallback) _book_view_focus_cb_gtk_widget_focus_in_event, self, G_CONNECT_AFTER); +	g_signal_connect_object (self->priv->drawing_area, "focus-out-event", (GCallback) _book_view_focus_cb_gtk_widget_focus_out_event, self, G_CONNECT_AFTER); +	g_signal_connect_object (self->priv->adjustment, "value-changed", (GCallback) _book_view_scroll_cb_gtk_adjustment_value_changed, self, 0); +	gtk_widget_show (self->priv->drawing_area); +	return self;  } -static void -set_selected_page (BookView *view, PageView *page) -{ -    /* Deselect existing page if changed */ -    if (view->priv->selected_page && page != view->priv->selected_page) -        page_view_set_selected (view->priv->selected_page, FALSE);   +BookView* book_view_new (Book* book) { +	return book_view_construct (TYPE_BOOK_VIEW, book); +} -    view->priv->selected_page = page; -    if (!view->priv->selected_page) -        return; -    /* Select new page if widget has focus */ -    if (!gtk_widget_has_focus (view->priv->drawing_area)) -        page_view_set_selected (view->priv->selected_page, FALSE); -    else -        page_view_set_selected (view->priv->selected_page, TRUE); +static gpointer _page_view_ref0 (gpointer self) { +	return self ? page_view_ref (self) : NULL;  } -static void -set_x_offset (BookView *view, gint offset) -{ -    gtk_adjustment_set_value (view->priv->adjustment, offset); +static PageView* book_view_get_nth_page (BookView* self, gint n) { +	PageView* result = NULL; +	Page* _tmp0_ = NULL; +	Page* page; +	gconstpointer _tmp1_ = NULL; +	PageView* _tmp2_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = book_get_page (self->priv->book, n); +	page = _tmp0_; +	_tmp1_ = g_hash_table_lookup (self->priv->page_data, page); +	_tmp2_ = _page_view_ref0 ((PageView*) _tmp1_); +	result = _tmp2_; +	_page_unref0 (page); +	return result;  } -static gint -get_x_offset (BookView *view) -{ -    return (gint) gtk_adjustment_get_value (view->priv->adjustment); +static PageView* book_view_get_next_page (BookView* self, PageView* page) { +	PageView* result = NULL; +	PageView* _tmp8_; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (page != NULL, NULL); +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp0_; +			_tmp0_ = TRUE; +			while (TRUE) { +				Page* _tmp1_ = NULL; +				Page* p; +				Page* _tmp2_ = NULL; +				Page* _tmp3_; +				gboolean _tmp4_; +				if (!_tmp0_) { +					i++; +				} +				_tmp0_ = FALSE; +				_tmp1_ = book_get_page (self->priv->book, i); +				p = _tmp1_; +				if (p == NULL) { +					_page_unref0 (p); +					break; +				} +				_tmp2_ = page_view_get_page (page); +				_tmp3_ = _tmp2_; +				_tmp4_ = p == _tmp3_; +				_page_unref0 (_tmp3_); +				if (_tmp4_) { +					Page* _tmp5_ = NULL; +					_tmp5_ = book_get_page (self->priv->book, i + 1); +					_page_unref0 (p); +					p = _tmp5_; +					if (p != NULL) { +						gconstpointer _tmp6_ = NULL; +						PageView* _tmp7_; +						_tmp6_ = g_hash_table_lookup (self->priv->page_data, p); +						_tmp7_ = _page_view_ref0 ((PageView*) _tmp6_); +						result = _tmp7_; +						_page_unref0 (p); +						return result; +					} +				} +				_page_unref0 (p); +			} +		} +	} +	_tmp8_ = _page_view_ref0 (page); +	result = _tmp8_; +	return result;  } -static void -show_page (BookView *view, PageView *page) -{ -    gint left_edge, right_edge; -    GtkAllocation allocation; +static PageView* book_view_get_prev_page (BookView* self, PageView* page) { +	PageView* result = NULL; +	PageView* _tmp0_; +	PageView* prev_page; +	PageView* _tmp8_; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (page != NULL, NULL); +	_tmp0_ = _page_view_ref0 (page); +	prev_page = _tmp0_; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp1_; +			_tmp1_ = TRUE; +			while (TRUE) { +				Page* _tmp2_ = NULL; +				Page* p; +				Page* _tmp3_ = NULL; +				Page* _tmp4_; +				gboolean _tmp5_; +				gconstpointer _tmp6_ = NULL; +				PageView* _tmp7_; +				if (!_tmp1_) { +					i++; +				} +				_tmp1_ = FALSE; +				_tmp2_ = book_get_page (self->priv->book, i); +				p = _tmp2_; +				if (p == NULL) { +					_page_unref0 (p); +					break; +				} +				_tmp3_ = page_view_get_page (page); +				_tmp4_ = _tmp3_; +				_tmp5_ = p == _tmp4_; +				_page_unref0 (_tmp4_); +				if (_tmp5_) { +					result = prev_page; +					_page_unref0 (p); +					return result; +				} +				_tmp6_ = g_hash_table_lookup (self->priv->page_data, p); +				_tmp7_ = _page_view_ref0 ((PageView*) _tmp6_); +				_page_view_unref0 (prev_page); +				prev_page = _tmp7_; +				_page_unref0 (p); +			} +		} +	} +	_tmp8_ = _page_view_ref0 (page); +	result = _tmp8_; +	_page_view_unref0 (prev_page); +	return result; +} + -    if (!page || !gtk_widget_get_visible (view->priv->scroll)) -        return; +static void book_view_page_view_changed_cb (BookView* self, PageView* page) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	book_view_redraw (self); +} -    gtk_widget_get_allocation(view->priv->drawing_area, &allocation); -    left_edge = page_view_get_x_offset (page); -    right_edge = page_view_get_x_offset (page) + page_view_get_width (page); -    if (left_edge - get_x_offset (view) < 0) -        set_x_offset(view, left_edge); -    else if (right_edge - get_x_offset (view) > allocation.width) -        set_x_offset(view, right_edge - allocation.width); +static void book_view_page_view_size_changed_cb (BookView* self, PageView* page) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	self->priv->need_layout = TRUE; +	book_view_redraw (self);  } -static void -select_page (BookView *view, PageView *page) -{ -    Page *p = NULL; -   -    if (view->priv->selected_page == page) -        return; +static void _book_view_page_view_changed_cb_page_view_changed (PageView* _sender, gpointer self) { +	book_view_page_view_changed_cb (self, _sender); +} + -    set_selected_page (view, page); +static void _book_view_page_view_size_changed_cb_page_view_size_changed (PageView* _sender, gpointer self) { +	book_view_page_view_size_changed_cb (self, _sender); +} -    if (view->priv->need_layout) -        view->priv->show_selected_page = TRUE; -    else -        show_page (view, page); -    if (page) -        p = page_view_get_page (page); -    g_signal_emit (view, signals[PAGE_SELECTED], 0, p); +static gpointer _page_ref0 (gpointer self) { +	return self ? page_ref (self) : NULL;  } -static void -remove_cb (Book *book, Page *page, BookView *view) -{ -    PageView *new_selection = view->priv->selected_page; +static void book_view_add_cb (BookView* self, Book* book, Page* page) { +	PageView* _tmp0_ = NULL; +	PageView* page_view; +	Page* _tmp1_; +	PageView* _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = page_view_new (page); +	page_view = _tmp0_; +	g_signal_connect_object (page_view, "changed", (GCallback) _book_view_page_view_changed_cb_page_view_changed, self, 0); +	g_signal_connect_object (page_view, "size-changed", (GCallback) _book_view_page_view_size_changed_cb_page_view_size_changed, self, 0); +	_tmp1_ = _page_ref0 (page); +	_tmp2_ = _page_view_ref0 (page_view); +	g_hash_table_insert (self->priv->page_data, _tmp1_, _tmp2_); +	self->priv->need_layout = TRUE; +	book_view_redraw (self); +	_page_view_unref0 (page_view); +} -    /* Select previous page or next if removing the selected page */ -    if (page == book_view_get_selected (view)) { -        new_selection = get_prev_page (view, view->priv->selected_page); -        if (new_selection == view->priv->selected_page) -            new_selection = get_next_page (view, view->priv->selected_page); -        view->priv->selected_page = NULL; -    } -    g_hash_table_remove (view->priv->page_data, page); +static void book_view_set_selected_page (BookView* self, PageView* page) { +	gboolean _tmp0_ = FALSE; +	PageView* _tmp1_; +	gboolean _tmp2_; +	g_return_if_fail (self != NULL); +	if (self->priv->selected_page != NULL) { +		_tmp0_ = page != self->priv->selected_page; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		page_view_set_selected (self->priv->selected_page, FALSE); +	} +	_tmp1_ = _page_view_ref0 (page); +	_page_view_unref0 (self->priv->selected_page); +	self->priv->selected_page = _tmp1_; +	if (self->priv->selected_page == NULL) { +		return; +	} +	g_object_get (self->priv->drawing_area, "has-focus", &_tmp2_, NULL); +	if (!_tmp2_) { +		page_view_set_selected (self->priv->selected_page, FALSE); +	} else { +		page_view_set_selected (self->priv->selected_page, TRUE); +	} +} -    select_page (view, new_selection); -    view->priv->need_layout = TRUE; -    book_view_redraw (view); +static void book_view_set_x_offset (BookView* self, gint offset) { +	g_return_if_fail (self != NULL); +	gtk_adjustment_set_value (self->priv->adjustment, (gdouble) offset);  } -static void -reorder_cb (Book *book, BookView *view) -{ -    view->priv->need_layout = TRUE; -    book_view_redraw (view); +static gint book_view_get_x_offset (BookView* self) { +	gint result = 0; +	gdouble _tmp0_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = gtk_adjustment_get_value (self->priv->adjustment); +	result = (gint) _tmp0_; +	return result;  } -static void -clear_cb (Book *book, BookView *view) -{ -    g_hash_table_remove_all (view->priv->page_data); -    view->priv->selected_page = NULL; -    g_signal_emit (view, signals[PAGE_SELECTED], 0, NULL); -    view->priv->need_layout = TRUE; -    book_view_redraw (view); +static void book_view_show_page_view (BookView* self, PageView* page) { +	gboolean _tmp0_ = FALSE; +	GtkAllocation allocation = {0}; +	GtkAllocation _tmp2_ = {0}; +	gint _tmp3_; +	gint left_edge; +	gint _tmp4_; +	gint _tmp5_; +	gint right_edge; +	gint _tmp6_; +	g_return_if_fail (self != NULL); +	if (page == NULL) { +		_tmp0_ = TRUE; +	} else { +		gboolean _tmp1_; +		_tmp1_ = gtk_widget_get_visible ((GtkWidget*) self->priv->scroll); +		_tmp0_ = !_tmp1_; +	} +	if (_tmp0_) { +		return; +	} +	gtk_widget_get_allocation (self->priv->drawing_area, &_tmp2_); +	allocation = _tmp2_; +	_tmp3_ = page_view_get_x_offset (page); +	left_edge = _tmp3_; +	_tmp4_ = page_view_get_x_offset (page); +	_tmp5_ = page_view_get_width (page); +	right_edge = _tmp4_ + _tmp5_; +	_tmp6_ = book_view_get_x_offset (self); +	if ((left_edge - _tmp6_) < 0) { +		book_view_set_x_offset (self, left_edge); +	} else { +		gint _tmp7_; +		_tmp7_ = book_view_get_x_offset (self); +		if ((right_edge - _tmp7_) > allocation.width) { +			book_view_set_x_offset (self, right_edge - allocation.width); +		} +	}  } -Book * -book_view_get_book (BookView *view) -{ -    g_return_val_if_fail (view != NULL, NULL); +static void book_view_select_page_view (BookView* self, PageView* page) { +	Page* p; +	g_return_if_fail (self != NULL); +	p = NULL; +	if (self->priv->selected_page == page) { +		_page_unref0 (p); +		return; +	} +	book_view_set_selected_page (self, page); +	if (self->priv->need_layout) { +		self->priv->show_selected_page = TRUE; +	} else { +		book_view_show_page_view (self, page); +	} +	if (page != NULL) { +		Page* _tmp0_ = NULL; +		_tmp0_ = page_view_get_page (page); +		_page_unref0 (p); +		p = _tmp0_; +	} +	g_signal_emit_by_name (self, "page-selected", p); +	_page_unref0 (p); +} + -    return view->priv->book; +static void book_view_remove_cb (BookView* self, Book* book, Page* page) { +	PageView* _tmp0_; +	PageView* new_selection; +	Page* _tmp1_ = NULL; +	Page* _tmp2_; +	gboolean _tmp3_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = _page_view_ref0 (self->priv->selected_page); +	new_selection = _tmp0_; +	_tmp1_ = book_view_get_selected (self); +	_tmp2_ = _tmp1_; +	_tmp3_ = page == _tmp2_; +	_page_unref0 (_tmp2_); +	if (_tmp3_) { +		PageView* _tmp4_ = NULL; +		_tmp4_ = book_view_get_prev_page (self, self->priv->selected_page); +		_page_view_unref0 (new_selection); +		new_selection = _tmp4_; +		if (new_selection == self->priv->selected_page) { +			PageView* _tmp5_ = NULL; +			_tmp5_ = book_view_get_next_page (self, self->priv->selected_page); +			_page_view_unref0 (new_selection); +			new_selection = _tmp5_; +		} +		_page_view_unref0 (self->priv->selected_page); +		self->priv->selected_page = NULL; +	} +	g_hash_table_remove (self->priv->page_data, page); +	book_view_select_page_view (self, new_selection); +	self->priv->need_layout = TRUE; +	book_view_redraw (self); +	_page_view_unref0 (new_selection);  } -static gboolean -configure_cb (GtkWidget *widget, GdkEventConfigure *event, BookView *view) -{ -    view->priv->need_layout = TRUE; -    return FALSE; +static void book_view_reorder_cb (BookView* self, Book* book) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	self->priv->need_layout = TRUE; +	book_view_redraw (self);  } -static void -layout_into (BookView *view, gint width, gint height, gint *book_width, gint *book_height) -{ -    gint spacing = 12; -    gint max_width = 0, max_height = 0; -    gdouble aspect, max_aspect; -    gint x_offset = 0; -    gint i, n_pages; -    gint max_dpi = 0; +static void book_view_clear_cb (BookView* self, Book* book) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	g_hash_table_remove_all (self->priv->page_data); +	_page_view_unref0 (self->priv->selected_page); +	self->priv->selected_page = NULL; +	g_signal_emit_by_name (self, "page-selected", NULL); +	self->priv->need_layout = TRUE; +	book_view_redraw (self); +} -    n_pages = book_get_n_pages (view->priv->book); -    /* Get maximum page resolution */ -    for (i = 0; i < n_pages; i++) { -        Page *page = book_get_page (view->priv->book, i); -        if (page_get_dpi (page) > max_dpi) -            max_dpi = page_get_dpi (page); -    } +Book* book_view_get_book (BookView* self) { +	Book* result = NULL; +	Book* _tmp0_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = _book_ref0 (self->priv->book); +	result = _tmp0_; +	return result; +} -    /* Get area required to fit all pages */ -    for (i = 0; i < n_pages; i++) { -        Page *page = book_get_page (view->priv->book, i); -        gint w, h; -        w = page_get_width (page); -        h = page_get_height (page); +static gboolean book_view_configure_cb (BookView* self, GtkWidget* widget, GdkEventConfigure* event) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	self->priv->need_layout = TRUE; +	result = FALSE; +	return result; +} -        /* Scale to the same DPI */ -        w = (double)w * max_dpi / page_get_dpi (page) + 0.5; -        h = (double)h * max_dpi / page_get_dpi (page) + 0.5; -        if (w > max_width) -            max_width = w; -        if (h > max_height) -            max_height = h; -    } - -    aspect = (double)width / height; -    max_aspect = (double)max_width / max_height; - -    /* Get total dimensions of all pages */ -    *book_width = 0; -    *book_height = 0; -    for (i = 0; i < n_pages; i++) { -        PageView *page = get_nth_page (view, i); -        Page *p = page_view_get_page (page); -        gint h; - -        /* NOTE: Using double to avoid overflow for large images */ -        if (max_aspect > aspect) { -            /* Set width scaled on DPI and maximum width */ -            gint w = (double)page_get_width (p) * max_dpi * width / (page_get_dpi (p) * max_width); -            page_view_set_width (page, w); -        } -        else { -            /* Set height scaled on DPI and maximum height */ -            gint h = (double)page_get_height (p) * max_dpi * height / (page_get_dpi (p) * max_height); -            page_view_set_height (page, h); -        } - -        h = page_view_get_height (page); -        if (h > *book_height) -            *book_height = h; -        *book_width += page_view_get_width (page); -        if (i != 0) -            *book_width += spacing; -    } - -    for (i = 0; i < n_pages; i++) { -        PageView *page = get_nth_page (view, i); - -        /* Layout pages left to right */ -        page_view_set_x_offset (page, x_offset); -        x_offset += page_view_get_width (page) + spacing; - -        /* Centre page vertically */ -        page_view_set_y_offset (page, (height - page_view_get_height (page)) / 2); -    } -} - - -static void -layout (BookView *view) -{ -    gint width, height, book_width, book_height; -    gboolean right_aligned = TRUE; -    GtkAllocation allocation, box_allocation; - -    if (!view->priv->need_layout) -        return; - -    view->priv->laying_out = TRUE; - -    gtk_widget_get_allocation(view->priv->drawing_area, &allocation); -    gtk_widget_get_allocation(GTK_WIDGET(view), &box_allocation); - -    /* If scroll is right aligned then keep that after layout */ -    if (gtk_adjustment_get_value (view->priv->adjustment) < gtk_adjustment_get_upper (view->priv->adjustment) - gtk_adjustment_get_page_size (view->priv->adjustment)) -        right_aligned = FALSE; - -    /* Try and fit without scrollbar */ -    width = allocation.width; -    height = box_allocation.height - gtk_container_get_border_width (GTK_CONTAINER (view)) * 2; -    layout_into (view, width, height, &book_width, &book_height); - -    /* Relayout with scrollbar */ -    if (book_width > allocation.width) { -        gint max_offset; -       -        /* Re-layout leaving space for scrollbar */ -        height = allocation.height; -        layout_into (view, width, height, &book_width, &book_height); - -        /* Set scrollbar limits */ -        gtk_adjustment_set_lower (view->priv->adjustment, 0); -        gtk_adjustment_set_upper (view->priv->adjustment, book_width); -        gtk_adjustment_set_page_size (view->priv->adjustment, allocation.width); - -        /* Keep right-aligned */ -        max_offset = book_width - allocation.width; -        if (right_aligned || get_x_offset (view) > max_offset) -            set_x_offset(view, max_offset); - -        gtk_widget_show (view->priv->scroll); -    } else { -        gint offset; -        gtk_widget_hide (view->priv->scroll); -        offset = (book_width - allocation.width) / 2; -        gtk_adjustment_set_lower (view->priv->adjustment, offset); -        gtk_adjustment_set_upper (view->priv->adjustment, offset); -        gtk_adjustment_set_page_size (view->priv->adjustment, 0); -        set_x_offset(view, offset); -    } -   -    if (view->priv->show_selected_page) -       show_page (view, view->priv->selected_page); - -    view->priv->need_layout = FALSE; -    view->priv->show_selected_page = FALSE; -    view->priv->laying_out = FALSE; -} - - -static gboolean -expose_cb (GtkWidget *widget, GdkEventExpose *event, BookView *view) -{ -    gint i, n_pages; -    cairo_t *context; - -    n_pages = book_get_n_pages (view->priv->book); -    if (n_pages == 0) -        return FALSE; - -    layout (view); - -    context = gdk_cairo_create (gtk_widget_get_window(widget)); - -    /* Render each page */ -    for (i = 0; i < n_pages; i++) { -        PageView *page = get_nth_page (view, i); -        gint left_edge, right_edge; -       -        left_edge = page_view_get_x_offset (page) - get_x_offset (view); -        right_edge = page_view_get_x_offset (page) + page_view_get_width (page) - get_x_offset (view); -       -        /* Page not visible, don't render */ -        if (right_edge < event->area.x || left_edge > event->area.x + event->area.width) -            continue; - -        cairo_save (context); -        cairo_translate (context, -get_x_offset (view), 0); -        page_view_render (page, context); -        cairo_restore (context); - -        if (page_view_get_selected (page)) -            gtk_paint_focus (gtk_widget_get_style (view->priv->drawing_area), -                             gtk_widget_get_window (view->priv->drawing_area), -                             GTK_STATE_SELECTED, -                             &event->area, -                             NULL, -                             NULL, -                             page_view_get_x_offset (page) - get_x_offset (view), -                             page_view_get_y_offset (page), -                             page_view_get_width (page), -                             page_view_get_height (page)); -    } - -    cairo_destroy (context); - -    return FALSE; -} - - -static PageView * -get_page_at (BookView *view, gint x, gint y, gint *x_, gint *y_) -{ -    gint i, n_pages; - -    n_pages = book_get_n_pages (view->priv->book); -    for (i = 0; i < n_pages; i++) { -        PageView *page; -        gint left, right, top, bottom; - -        page = get_nth_page (view, i); -        left = page_view_get_x_offset (page); -        right = left + page_view_get_width (page); -        top = page_view_get_y_offset (page); -        bottom = top + page_view_get_height (page); -        if (x >= left && x <= right && y >= top && y <= bottom)  -        { -            *x_ = x - left; -            *y_ = y - top; -            return page; -        } -    } - -    return NULL; -} - - -static gboolean -button_cb (GtkWidget *widget, GdkEventButton *event, BookView *view) -{ -    gint x, y; - -    layout (view); - -    gtk_widget_grab_focus (view->priv->drawing_area); - -    if (event->type == GDK_BUTTON_PRESS) -        select_page (view, get_page_at (view, event->x + get_x_offset (view), event->y, &x, &y)); - -    if (!view->priv->selected_page) -        return FALSE; +static void book_view_layout_into (BookView* self, gint width, gint height, gint* book_width, gint* book_height) { +	gint _book_width = 0; +	gint _book_height = 0; +	gint max_dpi; +	gint max_width; +	gint max_height; +	gdouble aspect; +	gdouble max_aspect; +	gint spacing; +	gint x_offset; +	g_return_if_fail (self != NULL); +	max_dpi = 0; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp0_; +			_tmp0_ = TRUE; +			while (TRUE) { +				guint _tmp1_; +				Page* _tmp2_ = NULL; +				Page* page; +				gint _tmp3_; +				if (!_tmp0_) { +					i++; +				} +				_tmp0_ = FALSE; +				_tmp1_ = book_get_n_pages (self->priv->book); +				if (!(((guint) i) < _tmp1_)) { +					break; +				} +				_tmp2_ = book_get_page (self->priv->book, i); +				page = _tmp2_; +				_tmp3_ = page_get_dpi (page); +				if (_tmp3_ > max_dpi) { +					gint _tmp4_; +					_tmp4_ = page_get_dpi (page); +					max_dpi = _tmp4_; +				} +				_page_unref0 (page); +			} +		} +	} +	max_width = 0; +	max_height = 0; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp5_; +			_tmp5_ = TRUE; +			while (TRUE) { +				guint _tmp6_; +				Page* _tmp7_ = NULL; +				Page* page; +				gint _tmp8_; +				gint w; +				gint _tmp9_; +				gint h; +				gint _tmp10_; +				gint _tmp11_; +				if (!_tmp5_) { +					i++; +				} +				_tmp5_ = FALSE; +				_tmp6_ = book_get_n_pages (self->priv->book); +				if (!(((guint) i) < _tmp6_)) { +					break; +				} +				_tmp7_ = book_get_page (self->priv->book, i); +				page = _tmp7_; +				_tmp8_ = page_get_width (page); +				w = _tmp8_; +				_tmp9_ = page_get_height (page); +				h = _tmp9_; +				_tmp10_ = page_get_dpi (page); +				w = (gint) (((((gdouble) w) * max_dpi) / _tmp10_) + 0.5); +				_tmp11_ = page_get_dpi (page); +				h = (gint) (((((gdouble) h) * max_dpi) / _tmp11_) + 0.5); +				if (w > max_width) { +					max_width = w; +				} +				if (h > max_height) { +					max_height = h; +				} +				_page_unref0 (page); +			} +		} +	} +	aspect = ((gdouble) width) / height; +	max_aspect = ((gdouble) max_width) / max_height; +	spacing = 12; +	_book_width = 0; +	_book_height = 0; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp12_; +			_tmp12_ = TRUE; +			while (TRUE) { +				guint _tmp13_; +				PageView* _tmp14_ = NULL; +				PageView* page; +				Page* _tmp15_ = NULL; +				Page* p; +				gint _tmp20_; +				gint h; +				gint _tmp21_; +				if (!_tmp12_) { +					i++; +				} +				_tmp12_ = FALSE; +				_tmp13_ = book_get_n_pages (self->priv->book); +				if (!(((guint) i) < _tmp13_)) { +					break; +				} +				_tmp14_ = book_view_get_nth_page (self, i); +				page = _tmp14_; +				_tmp15_ = page_view_get_page (page); +				p = _tmp15_; +				if (max_aspect > aspect) { +					gint _tmp16_; +					gint _tmp17_; +					gint w; +					_tmp16_ = page_get_width (p); +					_tmp17_ = page_get_dpi (p); +					w = (gint) (((((gdouble) _tmp16_) * max_dpi) * width) / (_tmp17_ * max_width)); +					page_view_set_width (page, w); +				} else { +					gint _tmp18_; +					gint _tmp19_; +					gint h; +					_tmp18_ = page_get_height (p); +					_tmp19_ = page_get_dpi (p); +					h = (gint) (((((gdouble) _tmp18_) * max_dpi) * height) / (_tmp19_ * max_height)); +					page_view_set_height (page, h); +				} +				_tmp20_ = page_view_get_height (page); +				h = _tmp20_; +				if (h > _book_height) { +					_book_height = h; +				} +				_tmp21_ = page_view_get_width (page); +				_book_width = _book_width + _tmp21_; +				if (i != 0) { +					_book_width = _book_width + spacing; +				} +				_page_unref0 (p); +				_page_view_unref0 (page); +			} +		} +	} +	x_offset = 0; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp22_; +			_tmp22_ = TRUE; +			while (TRUE) { +				guint _tmp23_; +				PageView* _tmp24_ = NULL; +				PageView* page; +				gint _tmp25_; +				gint _tmp26_; +				if (!_tmp22_) { +					i++; +				} +				_tmp22_ = FALSE; +				_tmp23_ = book_get_n_pages (self->priv->book); +				if (!(((guint) i) < _tmp23_)) { +					break; +				} +				_tmp24_ = book_view_get_nth_page (self, i); +				page = _tmp24_; +				page_view_set_x_offset (page, x_offset); +				_tmp25_ = page_view_get_width (page); +				x_offset = x_offset + (_tmp25_ + spacing); +				_tmp26_ = page_view_get_height (page); +				page_view_set_y_offset (page, (height - _tmp26_) / 2); +				_page_view_unref0 (page); +			} +		} +	} +	if (book_width) { +		*book_width = _book_width; +	} +	if (book_height) { +		*book_height = _book_height; +	} +} -    /* Modify page */ -    if (event->button == 1) { -        if (event->type == GDK_BUTTON_PRESS) -            page_view_button_press (view->priv->selected_page, x, y); -        else if (event->type == GDK_BUTTON_RELEASE) -            page_view_button_release (view->priv->selected_page, x, y); -        else if (event->type == GDK_2BUTTON_PRESS) -            g_signal_emit (view, signals[SHOW_PAGE], 0, book_view_get_selected (view)); -    } - -    /* Show pop-up menu on right click */ -    if (event->button == 3) -        g_signal_emit (view, signals[SHOW_MENU], 0); -    return FALSE; +static void book_view_layout (BookView* self) { +	GtkAllocation allocation = {0}; +	GtkAllocation _tmp0_ = {0}; +	GtkAllocation box_allocation = {0}; +	GtkAllocation _tmp1_ = {0}; +	gboolean right_aligned; +	gdouble _tmp2_; +	gdouble _tmp3_; +	gdouble _tmp4_; +	gint width; +	guint _tmp5_; +	gint height; +	gint book_width = 0; +	gint book_height = 0; +	gint _tmp6_; +	gint _tmp7_; +	g_return_if_fail (self != NULL); +	if (!self->priv->need_layout) { +		return; +	} +	self->priv->laying_out = TRUE; +	gtk_widget_get_allocation (self->priv->drawing_area, &_tmp0_); +	allocation = _tmp0_; +	gtk_widget_get_allocation ((GtkWidget*) self, &_tmp1_); +	box_allocation = _tmp1_; +	right_aligned = TRUE; +	_tmp2_ = gtk_adjustment_get_value (self->priv->adjustment); +	_tmp3_ = gtk_adjustment_get_upper (self->priv->adjustment); +	_tmp4_ = gtk_adjustment_get_page_size (self->priv->adjustment); +	if (_tmp2_ < (_tmp3_ - _tmp4_)) { +		right_aligned = FALSE; +	} +	width = (gint) allocation.width; +	_tmp5_ = gtk_container_get_border_width ((GtkContainer*) self); +	height = (gint) (box_allocation.height - (_tmp5_ * 2)); +	book_view_layout_into (self, width, height, &_tmp6_, &_tmp7_); +	book_width = _tmp6_; +	book_height = _tmp7_; +	if (book_width > allocation.width) { +		gint _tmp8_; +		gint _tmp9_; +		gint max_offset; +		gboolean _tmp10_ = FALSE; +		height = allocation.height; +		book_view_layout_into (self, width, height, &_tmp8_, &_tmp9_); +		book_width = _tmp8_; +		book_height = _tmp9_; +		gtk_adjustment_set_lower (self->priv->adjustment, (gdouble) 0); +		gtk_adjustment_set_upper (self->priv->adjustment, (gdouble) book_width); +		gtk_adjustment_set_page_size (self->priv->adjustment, (gdouble) allocation.width); +		max_offset = book_width - allocation.width; +		if (right_aligned) { +			_tmp10_ = TRUE; +		} else { +			gint _tmp11_; +			_tmp11_ = book_view_get_x_offset (self); +			_tmp10_ = _tmp11_ > max_offset; +		} +		if (_tmp10_) { +			book_view_set_x_offset (self, max_offset); +		} +		gtk_widget_show ((GtkWidget*) self->priv->scroll); +	} else { +		gint offset; +		gtk_widget_hide ((GtkWidget*) self->priv->scroll); +		offset = (book_width - allocation.width) / 2; +		gtk_adjustment_set_lower (self->priv->adjustment, (gdouble) offset); +		gtk_adjustment_set_upper (self->priv->adjustment, (gdouble) offset); +		gtk_adjustment_set_page_size (self->priv->adjustment, (gdouble) 0); +		book_view_set_x_offset (self, offset); +	} +	if (self->priv->show_selected_page) { +		book_view_show_page_view (self, self->priv->selected_page); +	} +	self->priv->need_layout = FALSE; +	self->priv->show_selected_page = FALSE; +	self->priv->laying_out = FALSE;  } -static void -set_cursor (BookView *view, gint cursor) -{ -    GdkCursor *c; -   -    if (view->priv->cursor == cursor) -        return; -    view->priv->cursor = cursor; +static gboolean book_view_draw_cb (BookView* self, GtkWidget* widget, cairo_t* context) { +	gboolean result = FALSE; +	guint _tmp0_; +	gdouble left = 0.0; +	gdouble top = 0.0; +	gdouble right = 0.0; +	gdouble bottom = 0.0; +	gdouble _tmp1_; +	gdouble _tmp2_; +	gdouble _tmp3_; +	gdouble _tmp4_; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	g_return_val_if_fail (context != NULL, FALSE); +	_tmp0_ = book_get_n_pages (self->priv->book); +	if (_tmp0_ == ((guint) 0)) { +		result = FALSE; +		return result; +	} +	book_view_layout (self); +	cairo_clip_extents (context, &_tmp1_, &_tmp2_, &_tmp3_, &_tmp4_); +	left = _tmp1_; +	top = _tmp2_; +	right = _tmp3_; +	bottom = _tmp4_; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp5_; +			_tmp5_ = TRUE; +			while (TRUE) { +				guint _tmp6_; +				PageView* _tmp7_ = NULL; +				PageView* page; +				gint _tmp8_; +				gint _tmp9_; +				gint left_edge; +				gint _tmp10_; +				gint _tmp11_; +				gint _tmp12_; +				gint right_edge; +				gboolean _tmp13_ = FALSE; +				gint _tmp14_; +				gboolean _tmp15_; +				if (!_tmp5_) { +					i++; +				} +				_tmp5_ = FALSE; +				_tmp6_ = book_get_n_pages (self->priv->book); +				if (!(((guint) i) < _tmp6_)) { +					break; +				} +				_tmp7_ = book_view_get_nth_page (self, i); +				page = _tmp7_; +				_tmp8_ = page_view_get_x_offset (page); +				_tmp9_ = book_view_get_x_offset (self); +				left_edge = _tmp8_ - _tmp9_; +				_tmp10_ = page_view_get_x_offset (page); +				_tmp11_ = page_view_get_width (page); +				_tmp12_ = book_view_get_x_offset (self); +				right_edge = (_tmp10_ + _tmp11_) - _tmp12_; +				if (((gdouble) right_edge) < left) { +					_tmp13_ = TRUE; +				} else { +					_tmp13_ = ((gdouble) left_edge) > right; +				} +				if (_tmp13_) { +					_page_view_unref0 (page); +					continue; +				} +				cairo_save (context); +				_tmp14_ = book_view_get_x_offset (self); +				cairo_translate (context, (gdouble) (-_tmp14_), (gdouble) 0); +				page_view_render (page, context); +				cairo_restore (context); +				_tmp15_ = page_view_get_selected (page); +				if (_tmp15_) { +					GtkStyle* _tmp16_ = NULL; +					gint _tmp17_; +					gint _tmp18_; +					gint _tmp19_; +					gint _tmp20_; +					gint _tmp21_; +					_tmp16_ = gtk_widget_get_style (self->priv->drawing_area); +					_tmp17_ = page_view_get_x_offset (page); +					_tmp18_ = book_view_get_x_offset (self); +					_tmp19_ = page_view_get_y_offset (page); +					_tmp20_ = page_view_get_width (page); +					_tmp21_ = page_view_get_height (page); +					gtk_paint_focus (_tmp16_, context, GTK_STATE_SELECTED, NULL, NULL, _tmp17_ - _tmp18_, _tmp19_, _tmp20_, _tmp21_); +				} +				_page_view_unref0 (page); +			} +		} +	} +	result = FALSE; +	return result; +} + -    c = gdk_cursor_new (cursor); -    gdk_window_set_cursor (gtk_widget_get_window (view->priv->drawing_area), c); -    gdk_cursor_destroy (c); +static PageView* book_view_get_page_at (BookView* self, gint x, gint y, gint* x_, gint* y_) { +	gint _x_ = 0; +	gint _y_ = 0; +	PageView* result = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp0_; +			_tmp0_ = TRUE; +			while (TRUE) { +				guint _tmp1_; +				PageView* _tmp2_ = NULL; +				PageView* page; +				gint _tmp3_; +				gint left; +				gint _tmp4_; +				gint right; +				gint _tmp5_; +				gint top; +				gint _tmp6_; +				gint bottom; +				gboolean _tmp7_ = FALSE; +				gboolean _tmp8_ = FALSE; +				gboolean _tmp9_ = FALSE; +				if (!_tmp0_) { +					i++; +				} +				_tmp0_ = FALSE; +				_tmp1_ = book_get_n_pages (self->priv->book); +				if (!(((guint) i) < _tmp1_)) { +					break; +				} +				_tmp2_ = book_view_get_nth_page (self, i); +				page = _tmp2_; +				_tmp3_ = page_view_get_x_offset (page); +				left = _tmp3_; +				_tmp4_ = page_view_get_width (page); +				right = left + _tmp4_; +				_tmp5_ = page_view_get_y_offset (page); +				top = _tmp5_; +				_tmp6_ = page_view_get_height (page); +				bottom = top + _tmp6_; +				if (x >= left) { +					_tmp9_ = x <= right; +				} else { +					_tmp9_ = FALSE; +				} +				if (_tmp9_) { +					_tmp8_ = y >= top; +				} else { +					_tmp8_ = FALSE; +				} +				if (_tmp8_) { +					_tmp7_ = y <= bottom; +				} else { +					_tmp7_ = FALSE; +				} +				if (_tmp7_) { +					_x_ = x - left; +					_y_ = y - top; +					result = page; +					if (x_) { +						*x_ = _x_; +					} +					if (y_) { +						*y_ = _y_; +					} +					return result; +				} +				_page_view_unref0 (page); +			} +		} +	} +	result = NULL; +	if (x_) { +		*x_ = _x_; +	} +	if (y_) { +		*y_ = _y_; +	} +	return result;  } -static gboolean -motion_cb (GtkWidget *widget, GdkEventMotion *event, BookView *view) -{ -    gint x, y; -    gint cursor = GDK_ARROW; -  -    /* Dragging */ -    if (view->priv->selected_page && (event->state & GDK_BUTTON1_MASK) != 0) { -        x = event->x + get_x_offset (view) - page_view_get_x_offset (view->priv->selected_page); -        y = event->y - page_view_get_y_offset (view->priv->selected_page); -        page_view_motion (view->priv->selected_page, x, y); -        cursor = page_view_get_cursor (view->priv->selected_page); -    } -    else { -        PageView *over_page; -        over_page = get_page_at (view, event->x + get_x_offset (view), event->y, &x, &y); -        if (over_page) { -            page_view_motion (over_page, x, y); -            cursor = page_view_get_cursor (over_page); -        } -    } +static gboolean book_view_button_cb (BookView* self, GtkWidget* widget, GdkEventButton* event) { +	gboolean result = FALSE; +	gint x; +	gint y; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	book_view_layout (self); +	gtk_widget_grab_focus (self->priv->drawing_area); +	x = 0; +	y = 0; +	if ((*event).type == GDK_BUTTON_PRESS) { +		gint _tmp0_; +		gint _tmp1_; +		gint _tmp2_; +		PageView* _tmp3_ = NULL; +		PageView* _tmp4_; +		_tmp0_ = book_view_get_x_offset (self); +		_tmp3_ = book_view_get_page_at (self, (gint) ((*event).x + _tmp0_), (gint) (*event).y, &_tmp1_, &_tmp2_); +		x = _tmp1_; +		y = _tmp2_; +		_tmp4_ = _tmp3_; +		book_view_select_page_view (self, _tmp4_); +		_page_view_unref0 (_tmp4_); +	} +	if (self->priv->selected_page == NULL) { +		result = FALSE; +		return result; +	} +	if ((*event).button == ((guint) 1)) { +		if ((*event).type == GDK_BUTTON_PRESS) { +			page_view_button_press (self->priv->selected_page, x, y); +		} else { +			if ((*event).type == GDK_BUTTON_RELEASE) { +				page_view_button_release (self->priv->selected_page, x, y); +			} else { +				if ((*event).type == GDK_2BUTTON_PRESS) { +					Page* _tmp5_ = NULL; +					Page* _tmp6_; +					_tmp5_ = book_view_get_selected (self); +					_tmp6_ = _tmp5_; +					g_signal_emit_by_name (self, "show-page", _tmp6_); +					_page_unref0 (_tmp6_); +				} +			} +		} +	} +	if ((*event).button == ((guint) 3)) { +		g_signal_emit_by_name (self, "show-menu"); +	} +	result = FALSE; +	return result; +} -    set_cursor (view, cursor); -    return FALSE; +static void book_view_set_cursor (BookView* self, GdkCursorType cursor) { +	GdkCursor* c = NULL; +	GdkCursor* _tmp0_ = NULL; +	GdkWindow* _tmp1_ = NULL; +	g_return_if_fail (self != NULL); +	if (self->priv->cursor == cursor) { +		_g_object_unref0 (c); +		return; +	} +	self->priv->cursor = cursor; +	_tmp0_ = gdk_cursor_new (cursor); +	_g_object_unref0 (c); +	c = _tmp0_; +	_tmp1_ = gtk_widget_get_window (self->priv->drawing_area); +	gdk_window_set_cursor (_tmp1_, c); +	_g_object_unref0 (c);  } -static gboolean -key_cb (GtkWidget *widget, GdkEventKey *event, BookView *view) -{ -    switch (event->keyval) { -    case GDK_Home: -        book_view_select_page (view, book_get_page (view->priv->book, 0)); -        return TRUE; -    case GDK_Left: -        select_page (view, get_prev_page (view, view->priv->selected_page)); -        return TRUE; -    case GDK_Right: -        select_page (view, get_next_page (view, view->priv->selected_page)); -        return TRUE; -    case GDK_End: -        book_view_select_page (view, book_get_page (view->priv->book, book_get_n_pages (view->priv->book) - 1)); -        return TRUE; +static gboolean book_view_motion_cb (BookView* self, GtkWidget* widget, GdkEventMotion* event) { +	gboolean result = FALSE; +	GdkCursorType cursor; +	gboolean _tmp0_ = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	cursor = GDK_ARROW; +	if (self->priv->selected_page != NULL) { +		_tmp0_ = ((*event).state & GDK_BUTTON1_MASK) != 0; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		gint _tmp1_; +		gint _tmp2_; +		gint x; +		gint _tmp3_; +		gint y; +		GdkCursorType _tmp4_; +		_tmp1_ = book_view_get_x_offset (self); +		_tmp2_ = page_view_get_x_offset (self->priv->selected_page); +		x = (gint) (((*event).x + _tmp1_) - _tmp2_); +		_tmp3_ = page_view_get_y_offset (self->priv->selected_page); +		y = (gint) ((*event).y - _tmp3_); +		page_view_motion (self->priv->selected_page, x, y); +		_tmp4_ = page_view_get_cursor (self->priv->selected_page); +		cursor = _tmp4_; +	} else { +		gint x = 0; +		gint y = 0; +		gint _tmp5_; +		gint _tmp6_; +		gint _tmp7_; +		PageView* _tmp8_ = NULL; +		PageView* over_page; +		_tmp5_ = book_view_get_x_offset (self); +		_tmp8_ = book_view_get_page_at (self, (gint) ((*event).x + _tmp5_), (gint) (*event).y, &_tmp6_, &_tmp7_); +		x = _tmp6_; +		y = _tmp7_; +		over_page = _tmp8_; +		if (over_page != NULL) { +			GdkCursorType _tmp9_; +			page_view_motion (over_page, x, y); +			_tmp9_ = page_view_get_cursor (over_page); +			cursor = _tmp9_; +		} +		_page_view_unref0 (over_page); +	} +	book_view_set_cursor (self, cursor); +	result = FALSE; +	return result; +} + -    default: -        return FALSE; -    } +static gboolean book_view_key_cb (BookView* self, GtkWidget* widget, GdkEventKey* event) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	switch ((*event).keyval) { +		case 0xff50: +		{ +			Page* _tmp0_ = NULL; +			Page* _tmp1_; +			_tmp0_ = book_get_page (self->priv->book, 0); +			_tmp1_ = _tmp0_; +			book_view_select_page (self, _tmp1_); +			_page_unref0 (_tmp1_); +			result = TRUE; +			return result; +		} +		case 0xff51: +		{ +			PageView* _tmp2_ = NULL; +			PageView* _tmp3_; +			_tmp2_ = book_view_get_prev_page (self, self->priv->selected_page); +			_tmp3_ = _tmp2_; +			book_view_select_page_view (self, _tmp3_); +			_page_view_unref0 (_tmp3_); +			result = TRUE; +			return result; +		} +		case 0xff53: +		{ +			PageView* _tmp4_ = NULL; +			PageView* _tmp5_; +			_tmp4_ = book_view_get_next_page (self, self->priv->selected_page); +			_tmp5_ = _tmp4_; +			book_view_select_page_view (self, _tmp5_); +			_page_view_unref0 (_tmp5_); +			result = TRUE; +			return result; +		} +		case 0xFF57: +		{ +			guint _tmp6_; +			Page* _tmp7_ = NULL; +			Page* _tmp8_; +			_tmp6_ = book_get_n_pages (self->priv->book); +			_tmp7_ = book_get_page (self->priv->book, ((gint) _tmp6_) - 1); +			_tmp8_ = _tmp7_; +			book_view_select_page (self, _tmp8_); +			_page_unref0 (_tmp8_); +			result = TRUE; +			return result; +		} +		default: +		{ +			result = FALSE; +			return result; +		} +	}  } -static gboolean -focus_cb (GtkWidget *widget, GdkEventFocus *event, BookView *view) -{ -    set_selected_page (view, view->priv->selected_page); -    return FALSE; +static gboolean book_view_focus_cb (BookView* self, GtkWidget* widget, GdkEventFocus* event) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	book_view_set_selected_page (self, self->priv->selected_page); +	result = FALSE; +	return result;  } -static void -scroll_cb (GtkAdjustment *adjustment, BookView *view) -{ -   if (!view->priv->laying_out) -       book_view_redraw (view); +static void book_view_scroll_cb (BookView* self, GtkAdjustment* adjustment) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (adjustment != NULL); +	if (!self->priv->laying_out) { +		book_view_redraw (self); +	}  } -void -book_view_redraw (BookView *view) -{ -    g_return_if_fail (view != NULL); -    gtk_widget_queue_draw (view->priv->drawing_area);   +void book_view_redraw (BookView* self) { +	g_return_if_fail (self != NULL); +	gtk_widget_queue_draw (self->priv->drawing_area);  } -void -book_view_select_page (BookView *view, Page *page) -{ -    g_return_if_fail (view != NULL); +void book_view_select_page (BookView* self, Page* page) { +	Page* _tmp0_ = NULL; +	Page* _tmp1_; +	gboolean _tmp2_; +	g_return_if_fail (self != NULL); +	_tmp0_ = book_view_get_selected (self); +	_tmp1_ = _tmp0_; +	_tmp2_ = _tmp1_ == page; +	_page_unref0 (_tmp1_); +	if (_tmp2_) { +		return; +	} +	if (page != NULL) { +		gconstpointer _tmp3_ = NULL; +		_tmp3_ = g_hash_table_lookup (self->priv->page_data, page); +		book_view_select_page_view (self, (PageView*) _tmp3_); +	} else { +		book_view_select_page_view (self, NULL); +	} +} -    if (book_view_get_selected (view) == page) -        return; -    if (page) -        select_page (view, g_hash_table_lookup (view->priv->page_data, page)); -    else -        select_page (view, NULL); +void book_view_select_next_page (BookView* self) { +	PageView* _tmp0_ = NULL; +	PageView* _tmp1_; +	g_return_if_fail (self != NULL); +	_tmp0_ = book_view_get_next_page (self, self->priv->selected_page); +	_tmp1_ = _tmp0_; +	book_view_select_page_view (self, _tmp1_); +	_page_view_unref0 (_tmp1_);  } -void -book_view_select_next_page (BookView *view) -{ -    g_return_if_fail (view != NULL); -    select_page (view, get_next_page (view, view->priv->selected_page)); +void book_view_select_prev_page (BookView* self) { +	PageView* _tmp0_ = NULL; +	PageView* _tmp1_; +	g_return_if_fail (self != NULL); +	_tmp0_ = book_view_get_prev_page (self, self->priv->selected_page); +	_tmp1_ = _tmp0_; +	book_view_select_page_view (self, _tmp1_); +	_page_view_unref0 (_tmp1_);  } -void -book_view_select_prev_page (BookView *view) -{ -    g_return_if_fail (view != NULL); -    select_page (view, get_prev_page (view, view->priv->selected_page)); +Page* book_view_get_selected (BookView* self) { +	Page* result = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	if (self->priv->selected_page != NULL) { +		Page* _tmp0_ = NULL; +		_tmp0_ = page_view_get_page (self->priv->selected_page); +		result = _tmp0_; +		return result; +	} else { +		result = NULL; +		return result; +	}  } -Page * -book_view_get_selected (BookView *view) -{ -    g_return_val_if_fail (view != NULL, NULL); +static void g_cclosure_user_marshal_VOID__PAGE (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { +	typedef void (*GMarshalFunc_VOID__PAGE) (gpointer data1, gpointer arg_1, gpointer data2); +	register GMarshalFunc_VOID__PAGE callback; +	register GCClosure * cc; +	register gpointer data1; +	register gpointer data2; +	cc = (GCClosure *) closure; +	g_return_if_fail (n_param_values == 2); +	if (G_CCLOSURE_SWAP_DATA (closure)) { +		data1 = closure->data; +		data2 = param_values->data[0].v_pointer; +	} else { +		data1 = param_values->data[0].v_pointer; +		data2 = closure->data; +	} +	callback = (GMarshalFunc_VOID__PAGE) (marshal_data ? marshal_data : cc->callback); +	callback (data1, value_get_page (param_values + 1), data2); +} -    if (view->priv->selected_page) -        return page_view_get_page (view->priv->selected_page); -    else -        return NULL; + +static void book_view_class_init (BookViewClass * klass) { +	book_view_parent_class = g_type_class_peek_parent (klass); +	g_type_class_add_private (klass, sizeof (BookViewPrivate)); +	G_OBJECT_CLASS (klass)->finalize = book_view_finalize; +	g_signal_new ("page_selected", TYPE_BOOK_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__PAGE, G_TYPE_NONE, 1, TYPE_PAGE); +	g_signal_new ("show_page", TYPE_BOOK_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__PAGE, G_TYPE_NONE, 1, TYPE_PAGE); +	g_signal_new ("show_menu", TYPE_BOOK_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);  } -static void -book_view_set_property(GObject      *object, -                       guint         prop_id, -                       const GValue *value, -                       GParamSpec   *pspec) -{ -    BookView *self; -    gint i, n_pages; - -    self = BOOK_VIEW (object); - -    switch (prop_id) { -    case PROP_BOOK: -        self->priv->book = g_object_ref (g_value_get_object (value)); +static void book_view_instance_init (BookView * self) { +	self->priv = BOOK_VIEW_GET_PRIVATE (self); +	self->priv->selected_page = NULL; +} + -        /* Load existing pages */ -        n_pages = book_get_n_pages (self->priv->book); -        for (i = 0; i < n_pages; i++) { -            Page *page = book_get_page (self->priv->book, i); -            add_cb (self->priv->book, page, self); -        } +static void book_view_finalize (GObject* obj) { +	BookView * self; +	self = BOOK_VIEW (obj); +	_book_unref0 (self->priv->book); +	_g_hash_table_unref0 (self->priv->page_data); +	_page_view_unref0 (self->priv->selected_page); +	_g_object_unref0 (self->priv->drawing_area); +	_g_object_unref0 (self->priv->scroll); +	_g_object_unref0 (self->priv->adjustment); +	G_OBJECT_CLASS (book_view_parent_class)->finalize (obj); +} -        book_view_select_page (self, book_get_page (self->priv->book, 0)); -        /* Watch for new pages */ -        g_signal_connect (self->priv->book, "page-added", G_CALLBACK (add_cb), self); -        g_signal_connect (self->priv->book, "page-removed", G_CALLBACK (remove_cb), self); -        g_signal_connect (self->priv->book, "reordered", G_CALLBACK (reorder_cb), self); -        g_signal_connect (self->priv->book, "cleared", G_CALLBACK (clear_cb), self); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } -} - - -static void -book_view_get_property(GObject    *object, -                       guint       prop_id, -                       GValue     *value, -                       GParamSpec *pspec) -{ -    BookView *self; - -    self = BOOK_VIEW (object); - -    switch (prop_id) { -    case PROP_BOOK: -        g_value_set_object (value, self->priv->book); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } -} - - -static void -book_view_finalize (GObject *object) -{ -    BookView *view = BOOK_VIEW (object); -    g_object_unref (view->priv->book); -    view->priv->book = NULL; -    g_hash_table_unref (view->priv->page_data); -    view->priv->page_data = NULL; -    G_OBJECT_CLASS (book_view_parent_class)->finalize (object); -} - - -static void -book_view_class_init (BookViewClass *klass) -{ -    GObjectClass *object_class = G_OBJECT_CLASS (klass); - -    object_class->finalize = book_view_finalize; -    object_class->set_property = book_view_set_property; -    object_class->get_property = book_view_get_property; - -    signals[PAGE_SELECTED] = -        g_signal_new ("page-selected", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookViewClass, page_selected), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__OBJECT, -                      G_TYPE_NONE, 1, page_get_type ()); -    signals[SHOW_PAGE] = -        g_signal_new ("show-page", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookViewClass, show_page), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__OBJECT, -                      G_TYPE_NONE, 1, page_get_type ()); -    signals[SHOW_MENU] = -        g_signal_new ("show-menu", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookViewClass, show_page), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); - -    g_object_class_install_property(object_class, -                                    PROP_BOOK, -                                    g_param_spec_object("book", -                                                        "book", -                                                        "Book being shown", -                                                        book_get_type(), -                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - -    g_type_class_add_private (klass, sizeof (BookViewPrivate)); -} - - -static void -book_view_init (BookView *view) -{ -    view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, BOOK_VIEW_TYPE, BookViewPrivate); -    view->priv->need_layout = TRUE; -    view->priv->page_data = g_hash_table_new_full (g_direct_hash, g_direct_equal, -                                                   NULL, (GDestroyNotify) g_object_unref); -    view->priv->cursor = GDK_ARROW; -   -    view->priv->drawing_area = gtk_drawing_area_new (); -    gtk_widget_set_size_request (view->priv->drawing_area, 200, 100); -    gtk_widget_set_can_focus (view->priv->drawing_area, TRUE); -    gtk_widget_set_events (view->priv->drawing_area, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK); -    gtk_box_pack_start (GTK_BOX (view), view->priv->drawing_area, TRUE, TRUE, 0); - -    view->priv->scroll = gtk_hscrollbar_new (NULL); -    view->priv->adjustment = gtk_range_get_adjustment (GTK_RANGE (view->priv->scroll)); -    gtk_box_pack_start (GTK_BOX (view), view->priv->scroll, FALSE, TRUE, 0); - -    g_signal_connect (view->priv->drawing_area, "configure-event", G_CALLBACK (configure_cb), view); -    g_signal_connect (view->priv->drawing_area, "expose-event", G_CALLBACK (expose_cb), view); -    g_signal_connect (view->priv->drawing_area, "motion-notify-event", G_CALLBACK (motion_cb), view); -    g_signal_connect (view->priv->drawing_area, "key-press-event", G_CALLBACK (key_cb), view); -    g_signal_connect (view->priv->drawing_area, "button-press-event", G_CALLBACK (button_cb), view); -    g_signal_connect (view->priv->drawing_area, "button-release-event", G_CALLBACK (button_cb), view); -    g_signal_connect_after (view->priv->drawing_area, "focus-in-event", G_CALLBACK (focus_cb), view); -    g_signal_connect_after (view->priv->drawing_area, "focus-out-event", G_CALLBACK (focus_cb), view); -    g_signal_connect (view->priv->adjustment, "value-changed", G_CALLBACK (scroll_cb), view); - -    gtk_widget_show (view->priv->drawing_area); +GType book_view_get_type (void) { +	static volatile gsize book_view_type_id__volatile = 0; +	if (g_once_init_enter (&book_view_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (BookViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) book_view_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (BookView), 0, (GInstanceInitFunc) book_view_instance_init, NULL }; +		GType book_view_type_id; +		book_view_type_id = g_type_register_static (GTK_TYPE_VBOX, "BookView", &g_define_type_info, 0); +		g_once_init_leave (&book_view_type_id__volatile, book_view_type_id); +	} +	return book_view_type_id__volatile;  } + + + diff --git a/src/book-view.h b/src/book-view.h deleted file mode 100644 index 5b5e2a6..0000000 --- a/src/book-view.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2009 Canonical Ltd. - * Author: Robert Ancell <robert.ancell@canonical.com> - *  - * This program 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 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _BOOK_VIEW_H_ -#define _BOOK_VIEW_H_ - -#include <gtk/gtk.h> -#include <cairo.h> -#include "book.h" - -G_BEGIN_DECLS - -#define BOOK_VIEW_TYPE  (book_view_get_type ()) -#define BOOK_VIEW(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), BOOK_VIEW_TYPE, BookView)) - - -typedef struct BookViewPrivate BookViewPrivate; - -typedef struct -{ -    GtkVBox parent_instance; -    BookViewPrivate *priv; -} BookView; - -typedef struct -{ -    GtkVBoxClass parent_class; - -    void (*page_selected) (BookView *view, Page *page); -    void (*show_page) (BookView *view, Page *page); -    void (*show_menu) (BookView *view, Page *page); -} BookViewClass; - - -GType book_view_get_type (void); - -BookView *book_view_new (Book *book); - -void book_view_redraw (BookView *view); - -Book *book_view_get_book (BookView *view); - -void book_view_select_page (BookView *view, Page *page); - -void book_view_select_next_page (BookView *view); - -void book_view_select_prev_page (BookView *view); - -Page *book_view_get_selected (BookView *view); - -#endif /* _BOOK_VIEW_H_ */ diff --git a/src/book-view.vala b/src/book-view.vala new file mode 100644 index 0000000..9dfd361 --- /dev/null +++ b/src/book-view.vala @@ -0,0 +1,594 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +// FIXME: When scrolling, copy existing render sideways? +// FIXME: Only render pages that change and only the part that changed + +public class BookView : Gtk.VBox +{ +    /* Book being rendered */ +    private Book book; +    private HashTable<Page, PageView> page_data; + +    /* True if the view needs to be laid out again */ +    private bool need_layout; +    private bool laying_out; +    private bool show_selected_page; + +    /* Currently selected page */ +    private PageView? selected_page = null; + +    /* Widget being rendered to */ +    private Gtk.Widget drawing_area; + +    /* Horizontal scrollbar */ +    private Gtk.HScrollbar scroll; +    private Gtk.Adjustment adjustment; + +    private Gdk.CursorType cursor; +     +    public signal void page_selected (Page? page); +    public signal void show_page (Page page); +    public signal void show_menu (); + +    public BookView (Book book) +    { +        this.book = book; + +        /* Load existing pages */ +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            Page page = book.get_page (i); +            add_cb (book, page); +        } + +        select_page (book.get_page (0)); + +        /* Watch for new pages */ +        book.page_added.connect (add_cb); +        book.page_removed.connect (remove_cb); +        book.reordered.connect (reorder_cb); +        book.cleared.connect (clear_cb); + +        need_layout = true; +        page_data = new HashTable<Page, PageView> (direct_hash, direct_equal); +        cursor = Gdk.CursorType.ARROW; + +        drawing_area = new Gtk.DrawingArea (); +        drawing_area.set_size_request (200, 100); +        drawing_area.set_can_focus (true); +        drawing_area.set_events (Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.FOCUS_CHANGE_MASK | Gdk.EventMask.STRUCTURE_MASK | Gdk.EventMask.SCROLL_MASK); +        pack_start (drawing_area, true, true, 0); + +        scroll = new Gtk.HScrollbar (null); +        adjustment = scroll.get_adjustment (); +        pack_start (scroll, false, true, 0); + +        drawing_area.configure_event.connect (configure_cb); +        drawing_area.draw.connect (draw_cb); +        drawing_area.motion_notify_event.connect (motion_cb); +        drawing_area.key_press_event.connect (key_cb); +        drawing_area.button_press_event.connect (button_cb); +        drawing_area.button_release_event.connect (button_cb); +        drawing_area.focus_in_event.connect_after (focus_cb); +        drawing_area.focus_out_event.connect_after (focus_cb); +        adjustment.value_changed.connect (scroll_cb); + +        drawing_area.show (); +    } + +    private PageView get_nth_page (int n) +    { +        Page page = book.get_page (n); +        return page_data.lookup (page); +    } + +    private PageView get_next_page (PageView page) +    { +        for (var i = 0; ; i++) +        { +            var p = book.get_page (i); +            if (p == null) +                break; +            if (p == page.get_page ()) +            { +                p = book.get_page (i + 1); +                if (p != null) +                    return page_data.lookup (p); +            } +        } + +        return page; +    } + +    private PageView get_prev_page (PageView page) +    { +        var prev_page = page; +        for (var i = 0; ; i++) +        { +            var p = book.get_page (i); +            if (p == null) +                break; +            if (p == page.get_page ()) +                return prev_page; +            prev_page = page_data.lookup (p); +        } + +        return page; +    } + +    private void page_view_changed_cb (PageView page) +    { +        redraw (); +    } + +    private void page_view_size_changed_cb (PageView page) +    { +        need_layout = true; +        redraw (); +    } + +    private void add_cb (Book book, Page page) +    { +        var page_view = new PageView (page); +        page_view.changed.connect (page_view_changed_cb); +        page_view.size_changed.connect (page_view_size_changed_cb); +        page_data.insert (page, page_view); +        need_layout = true; +        redraw (); +    } + +    private void set_selected_page (PageView? page) +    { +        /* Deselect existing page if changed */ +        if (selected_page != null && page != selected_page) +            selected_page.set_selected (false); + +        selected_page = page; +        if (selected_page == null) +            return; + +        /* Select new page if widget has focus */ +        if (!drawing_area.has_focus) +            selected_page.set_selected (false); +        else +            selected_page.set_selected (true); +    } + +    private void set_x_offset (int offset) +    { +        adjustment.set_value (offset); +    } + +    private int get_x_offset () +    { +        return (int) adjustment.get_value (); +    } + +    private void show_page_view (PageView? page) +    { +        if (page == null || !scroll.get_visible ()) +            return; + +        Gtk.Allocation allocation; +        drawing_area.get_allocation (out allocation); +        var left_edge = page.get_x_offset (); +        var right_edge = page.get_x_offset () + page.get_width (); + +        if (left_edge - get_x_offset () < 0) +            set_x_offset (left_edge); +        else if (right_edge - get_x_offset () > allocation.width) +            set_x_offset (right_edge - allocation.width); +    } + +    private void select_page_view (PageView? page) +    { +        Page? p = null; + +        if (selected_page == page) +            return; + +        set_selected_page (page); + +        if (need_layout) +            show_selected_page = true; +        else +            show_page_view (page); + +        if (page != null) +            p = page.get_page (); +        page_selected (p); +    } + +    private void remove_cb (Book book, Page page) +    { +        PageView new_selection = selected_page; + +        /* Select previous page or next if removing the selected page */ +        if (page == get_selected ()) +        { +            new_selection = get_prev_page (selected_page); +            if (new_selection == selected_page) +                new_selection = get_next_page (selected_page); +            selected_page = null; +        } + +        page_data.remove (page); + +        select_page_view (new_selection); + +        need_layout = true; +        redraw (); +    } + +    private void reorder_cb (Book book) +    { +        need_layout = true; +        redraw (); +    } + +    private void clear_cb (Book book) +    { +        page_data.remove_all (); +        selected_page = null; +        page_selected (null); +        need_layout = true; +        redraw (); +    } + +    public Book get_book () +    { +        return book; +    } + +    private bool configure_cb (Gtk.Widget widget, Gdk.EventConfigure event) +    { +        need_layout = true; +        return false; +    } + +    private void layout_into (int width, int height, out int book_width, out int book_height) +    { +        /* Get maximum page resolution */ +        int max_dpi = 0; +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            var page = book.get_page (i); +            if (page.get_dpi () > max_dpi) +                max_dpi = page.get_dpi (); +        } + +        /* Get area required to fit all pages */ +        int max_width = 0, max_height = 0; +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            var page = book.get_page (i); +            var w = page.get_width (); +            var h = page.get_height (); + +            /* Scale to the same DPI */ +            w = (int) ((double)w * max_dpi / page.get_dpi () + 0.5); +            h = (int) ((double)h * max_dpi / page.get_dpi () + 0.5); + +            if (w > max_width) +                max_width = w; +            if (h > max_height) +                max_height = h; +        } + +        var aspect = (double)width / height; +        var max_aspect = (double)max_width / max_height; + +        /* Get total dimensions of all pages */ +        int spacing = 12; +        book_width = 0; +        book_height = 0; +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            var page = get_nth_page (i); +            var p = page.get_page (); + +            /* NOTE: Using double to avoid overflow for large images */ +            if (max_aspect > aspect) +            { +                /* Set width scaled on DPI and maximum width */ +                int w = (int) ((double)p.get_width () * max_dpi * width / (p.get_dpi () * max_width)); +                page.set_width (w); +            } +            else +            { +                /* Set height scaled on DPI and maximum height */ +                int h = (int) ((double)p.get_height () * max_dpi * height / (p.get_dpi () * max_height)); +                page.set_height (h); +            } + +            var h = page.get_height (); +            if (h > book_height) +                book_height = h; +            book_width += page.get_width (); +            if (i != 0) +                book_width += spacing; +        } + +        int x_offset = 0; +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            var page = get_nth_page (i); + +            /* Layout pages left to right */ +            page.set_x_offset (x_offset); +            x_offset += page.get_width () + spacing; + +            /* Centre page vertically */ +            page.set_y_offset ((height - page.get_height ()) / 2); +        } +    } + +    private void layout () +    { +        if (!need_layout) +            return; + +        laying_out = true; + +        Gtk.Allocation allocation; +        drawing_area.get_allocation(out allocation); +        Gtk.Allocation box_allocation; +        get_allocation(out box_allocation); + +        /* If scroll is right aligned then keep that after layout */ +        bool right_aligned = true; +        if (adjustment.get_value () < adjustment.get_upper () - adjustment.get_page_size ()) +            right_aligned = false; + +        /* Try and fit without scrollbar */ +        var width = (int) allocation.width; +        var height = (int) (box_allocation.height - get_border_width () * 2); +        int book_width, book_height; +        layout_into (width, height, out book_width, out book_height); + +        /* Relayout with scrollbar */ +        if (book_width > allocation.width) +        { +            /* Re-layout leaving space for scrollbar */ +            height = allocation.height; +            layout_into (width, height, out book_width, out book_height); + +            /* Set scrollbar limits */ +            adjustment.set_lower (0); +            adjustment.set_upper (book_width); +            adjustment.set_page_size (allocation.width); + +            /* Keep right-aligned */ +            var max_offset = book_width - allocation.width; +            if (right_aligned || get_x_offset () > max_offset) +                set_x_offset(max_offset); + +            scroll.show (); +        } +        else +        { +            scroll.hide (); +            var offset = (book_width - allocation.width) / 2; +            adjustment.set_lower (offset); +            adjustment.set_upper (offset); +            adjustment.set_page_size (0); +            set_x_offset (offset); +        } + +        if (show_selected_page) +           show_page_view (selected_page); + +        need_layout = false; +        show_selected_page = false; +        laying_out = false; +    } + +    private bool draw_cb (Gtk.Widget widget, Cairo.Context context) +    { +        if (book.get_n_pages () == 0) +            return false; + +        layout (); + +        double left, top, right, bottom; +        context.clip_extents (out left, out top, out right, out bottom); + +        /* Render each page */ +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            var page = get_nth_page (i); +            var left_edge = page.get_x_offset () - get_x_offset (); +            var right_edge = page.get_x_offset () + page.get_width () - get_x_offset (); + +            /* Page not visible, don't render */ +            if (right_edge < left || left_edge > right) +                continue; + +            context.save (); +            context.translate (-get_x_offset (), 0); +            page.render (context); +            context.restore (); + +            if (page.get_selected ()) +                Gtk.paint_focus (drawing_area.get_style (), +                                 context, +                                 Gtk.StateType.SELECTED, +                                 null, +                                 null, +                                 page.get_x_offset () - get_x_offset (), +                                 page.get_y_offset (), +                                 page.get_width (), +                                 page.get_height ()); +        } + +        return false; +    } + +    private PageView? get_page_at (int x, int y, out int x_, out int y_) +    { +        for (var i = 0; i < book.get_n_pages (); i++) +        { +            var page = get_nth_page (i); +            var left = page.get_x_offset (); +            var right = left + page.get_width (); +            var top = page.get_y_offset (); +            var bottom = top + page.get_height (); +            if (x >= left && x <= right && y >= top && y <= bottom) +            { +                x_ = x - left; +                y_ = y - top; +                return page; +            } +        } + +        return null; +    } + +    private bool button_cb (Gtk.Widget widget, Gdk.EventButton event) +    { +        layout (); + +        drawing_area.grab_focus (); + +        int x = 0, y = 0; +        if (event.type == Gdk.EventType.BUTTON_PRESS) +            select_page_view (get_page_at ((int) (event.x + get_x_offset ()), (int) event.y, out x, out y)); + +        if (selected_page == null) +            return false; + +        /* Modify page */ +        if (event.button == 1) +        { +            if (event.type == Gdk.EventType.BUTTON_PRESS) +                selected_page.button_press (x, y); +            else if (event.type == Gdk.EventType.BUTTON_RELEASE) +                selected_page.button_release (x, y); +            else if (event.type == Gdk.EventType.2BUTTON_PRESS) +                show_page (get_selected ()); +        } + +        /* Show pop-up menu on right click */ +        if (event.button == 3) +            show_menu (); + +        return false; +    } + +    private void set_cursor (Gdk.CursorType cursor) +    { +        Gdk.Cursor c; + +        if (this.cursor == cursor) +            return; +        this.cursor = cursor; + +        c = new Gdk.Cursor (cursor); +        drawing_area.get_window ().set_cursor (c); +    } + +    private bool motion_cb (Gtk.Widget widget, Gdk.EventMotion event) +    { +        Gdk.CursorType cursor = Gdk.CursorType.ARROW; + +        /* Dragging */ +        if (selected_page != null && (event.state & Gdk.ModifierType.BUTTON1_MASK) != 0) +        { +            var x = (int) (event.x + get_x_offset () - selected_page.get_x_offset ()); +            var y = (int) (event.y - selected_page.get_y_offset ()); +            selected_page.motion (x, y); +            cursor = selected_page.get_cursor (); +        } +        else +        { +            int x, y; +            var over_page = get_page_at ((int) (event.x + get_x_offset ()), (int) event.y, out x, out y); +            if (over_page != null) +            { +                over_page.motion (x, y); +                cursor = over_page.get_cursor (); +            } +        } + +        set_cursor (cursor); + +        return false; +    } + +    private bool key_cb (Gtk.Widget widget, Gdk.EventKey event) +    { +        switch (event.keyval) +        { +        case 0xff50: /* FIXME: GDK_Home */ +            select_page (book.get_page (0)); +            return true; +        case 0xff51: /* FIXME: GDK_Left */ +            select_page_view (get_prev_page (selected_page)); +            return true; +        case 0xff53: /* FIXME: GDK_Right */ +            select_page_view (get_next_page (selected_page)); +            return true; +        case 0xFF57: /* FIXME: GDK_End */ +            select_page (book.get_page ((int) book.get_n_pages () - 1)); +            return true; + +        default: +            return false; +        } +    } + +    private bool focus_cb (Gtk.Widget widget, Gdk.EventFocus event) +    { +        set_selected_page (selected_page); +        return false; +    } + +    private void scroll_cb (Gtk.Adjustment adjustment) +    { +       if (!laying_out) +           redraw (); +    } + +    public void redraw () +    { +        drawing_area.queue_draw (); +    } + +    public void select_page (Page? page) +    { +        if (get_selected () == page) +            return; + +        if (page != null) +            select_page_view (page_data.lookup (page)); +        else +            select_page_view (null); +    } + +    public void select_next_page () +    { +        select_page_view (get_next_page (selected_page)); +    } + +    public void select_prev_page () +    { +        select_page_view (get_prev_page (selected_page)); +    } + +    public Page? get_selected () +    { +        if (selected_page != null) +            return selected_page.get_page (); +        else +            return null; +    } +} @@ -1,7 +1,10 @@ +/* book.c generated by valac 0.13.1, the Vala compiler + * generated from book.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later @@ -9,870 +12,2278 @@   * license.   */ -#include <stdio.h> +#include <glib.h> +#include <glib-object.h> +#include <stdlib.h>  #include <string.h> +#include <gio/gio.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixdata.h> +#include <float.h>  #include <math.h> +#include <gdk/gdk.h> +#include <cairo-ps.h>  #include <zlib.h>  #include <jpeglib.h> -#include <gdk/gdk.h> -#include <gdk-pixbuf/gdk-pixbuf.h> -#include <cairo/cairo-pdf.h> -#include <cairo/cairo-ps.h> +#include <config.h> +#include <gobject/gvaluecollector.h> + + +#define TYPE_BOOK (book_get_type ()) +#define BOOK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOOK, Book)) +#define BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BOOK, BookClass)) +#define IS_BOOK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOOK)) +#define IS_BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BOOK)) +#define BOOK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BOOK, BookClass)) + +typedef struct _Book Book; +typedef struct _BookClass BookClass; +typedef struct _BookPrivate BookPrivate; + +#define TYPE_PAGE (page_get_type ()) +#define PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE, Page)) +#define PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE, PageClass)) +#define IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE)) +#define IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE)) +#define PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE, PageClass)) + +typedef struct _Page Page; +typedef struct _PageClass PageClass; +#define __g_list_free__page_unref0_0(var) ((var == NULL) ? NULL : (var = (_g_list_free__page_unref0_ (var), NULL))) + +#define TYPE_SCAN_DIRECTION (scan_direction_get_type ()) +#define _page_unref0(var) ((var == NULL) ? NULL : (var = (page_unref (var), NULL))) +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _cairo_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_destroy (var), NULL))) + +#define TYPE_PS_WRITER (ps_writer_get_type ()) +#define PS_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PS_WRITER, PsWriter)) +#define PS_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PS_WRITER, PsWriterClass)) +#define IS_PS_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PS_WRITER)) +#define IS_PS_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PS_WRITER)) +#define PS_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PS_WRITER, PsWriterClass)) + +typedef struct _PsWriter PsWriter; +typedef struct _PsWriterClass PsWriterClass; +typedef struct _PsWriterPrivate PsWriterPrivate; +#define _cairo_surface_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_surface_destroy (var), NULL))) +#define _ps_writer_unref0(var) ((var == NULL) ? NULL : (var = (ps_writer_unref (var), NULL))) + +#define TYPE_PDF_WRITER (pdf_writer_get_type ()) +#define PDF_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PDF_WRITER, PDFWriter)) +#define PDF_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PDF_WRITER, PDFWriterClass)) +#define IS_PDF_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PDF_WRITER)) +#define IS_PDF_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PDF_WRITER)) +#define PDF_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PDF_WRITER, PDFWriterClass)) + +typedef struct _PDFWriter PDFWriter; +typedef struct _PDFWriterClass PDFWriterClass; +typedef struct _PDFWriterPrivate PDFWriterPrivate; +#define _pdf_writer_unref0(var) ((var == NULL) ? NULL : (var = (pdf_writer_unref (var), NULL))) +typedef struct _ParamSpecBook ParamSpecBook; +#define _g_list_free0(var) ((var == NULL) ? NULL : (var = (g_list_free (var), NULL))) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) +typedef struct _ParamSpecPDFWriter ParamSpecPDFWriter; +typedef struct _ParamSpecPsWriter ParamSpecPsWriter; + +struct _Book { +	GTypeInstance parent_instance; +	volatile int ref_count; +	BookPrivate * priv; +}; + +struct _BookClass { +	GTypeClass parent_class; +	void (*finalize) (Book *self); +}; + +struct _BookPrivate { +	GList* pages; +	gboolean needs_saving; +}; + +typedef enum  { +	SCAN_DIRECTION_TOP_TO_BOTTOM, +	SCAN_DIRECTION_LEFT_TO_RIGHT, +	SCAN_DIRECTION_BOTTOM_TO_TOP, +	SCAN_DIRECTION_RIGHT_TO_LEFT +} ScanDirection; + +struct _PsWriter { +	GTypeInstance parent_instance; +	volatile int ref_count; +	PsWriterPrivate * priv; +	cairo_surface_t* surface; +	GFileOutputStream* stream; +}; -#include "book.h" +struct _PsWriterClass { +	GTypeClass parent_class; +	void (*finalize) (PsWriter *self); +}; -enum { -    PROP_0, -    PROP_NEEDS_SAVING +struct _PDFWriter { +	GTypeInstance parent_instance; +	volatile int ref_count; +	PDFWriterPrivate * priv; +	gsize offset; +	GList* object_offsets;  }; -enum { -    PAGE_ADDED, -    PAGE_REMOVED, -    REORDERED, -    CLEARED, -    LAST_SIGNAL +struct _PDFWriterClass { +	GTypeClass parent_class; +	void (*finalize) (PDFWriter *self);  }; -static guint signals[LAST_SIGNAL] = { 0, }; -struct BookPrivate -{ -    GList *pages; -   -    gboolean needs_saving; +struct _ParamSpecBook { +	GParamSpec parent_instance;  }; -G_DEFINE_TYPE (Book, book, G_TYPE_OBJECT); +struct _PDFWriterPrivate { +	GFileOutputStream* stream; +}; + +struct _ParamSpecPDFWriter { +	GParamSpec parent_instance; +}; + +struct _ParamSpecPsWriter { +	GParamSpec parent_instance; +}; + + +static gpointer book_parent_class = NULL; +static gpointer pdf_writer_parent_class = NULL; +static gpointer ps_writer_parent_class = NULL; + +gpointer book_ref (gpointer instance); +void book_unref (gpointer instance); +GParamSpec* param_spec_book (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_book (GValue* value, gpointer v_object); +void value_take_book (GValue* value, gpointer v_object); +gpointer value_get_book (const GValue* value); +GType book_get_type (void) G_GNUC_CONST; +gpointer page_ref (gpointer instance); +void page_unref (gpointer instance); +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page (GValue* value, gpointer v_object); +void value_take_page (GValue* value, gpointer v_object); +gpointer value_get_page (const GValue* value); +GType page_get_type (void) G_GNUC_CONST; +#define BOOK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_BOOK, BookPrivate)) +enum  { +	BOOK_DUMMY_PROPERTY +}; +static void _page_unref0_ (gpointer var); +static void _g_list_free__page_unref0_ (GList* self); +Book* book_new (void); +Book* book_construct (GType object_type); +void book_clear (Book* self); +static void book_page_changed_cb (Book* self, Page* page); +void book_set_needs_saving (Book* self, gboolean needs_saving); +GType scan_direction_get_type (void) G_GNUC_CONST; +Page* book_append_page (Book* self, gint width, gint height, gint dpi, ScanDirection scan_direction); +Page* page_new (gint width, gint height, gint dpi, ScanDirection scan_direction); +Page* page_construct (GType object_type, gint width, gint height, gint dpi, ScanDirection scan_direction); +static void _book_page_changed_cb_page_pixels_changed (Page* _sender, gpointer self); +static void _book_page_changed_cb_page_crop_changed (Page* _sender, gpointer self); +void book_move_page (Book* self, Page* page, guint location); +void book_delete_page (Book* self, Page* page); +guint book_get_n_pages (Book* self); +Page* book_get_page (Book* self, gint page_number); +guint book_get_page_index (Book* self, Page* page); +static GFile* book_make_indexed_file (Book* self, const gchar* uri, gint i); +static void book_save_multi_file (Book* self, const gchar* type, GFile* file, GError** error); +void page_save (Page* self, const gchar* type, GFile* file, GError** error); +static void book_save_ps_pdf_surface (Book* self, cairo_surface_t* surface, GdkPixbuf* image, gdouble dpi); +static void book_save_ps (Book* self, GFile* file, GError** error); +PsWriter* ps_writer_new (GFileOutputStream* stream); +PsWriter* ps_writer_construct (GType object_type, GFileOutputStream* stream); +gpointer ps_writer_ref (gpointer instance); +void ps_writer_unref (gpointer instance); +GParamSpec* param_spec_ps_writer (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_ps_writer (GValue* value, gpointer v_object); +void value_take_ps_writer (GValue* value, gpointer v_object); +gpointer value_get_ps_writer (const GValue* value); +GType ps_writer_get_type (void) G_GNUC_CONST; +GdkPixbuf* page_get_image (Page* self, gboolean apply_crop); +gint page_get_dpi (Page* self); +static guint8* book_compress_zlib (Book* self, guint8* data, int data_length1, int* result_length1); +static void book_jpeg_init_cb (struct jpeg_compress_struct* info); +static gboolean book_jpeg_empty_cb (struct jpeg_compress_struct* info); +static void book_jpeg_term_cb (struct jpeg_compress_struct* info); +static guint8* book_compress_jpeg (Book* self, GdkPixbuf* image, gsize* n_written, int* result_length1); +static void _book_jpeg_init_cb_jpeg_initdestinationfunc (struct jpeg_compress_struct* cinfo); +static gboolean _book_jpeg_empty_cb_jpeg_emptyoutputbufferfunc (struct jpeg_compress_struct* cinfo); +static void _book_jpeg_term_cb_jpeg_termdestinationfunc (struct jpeg_compress_struct* cinfo); +static void book_save_pdf (Book* self, GFile* file, GError** error); +PDFWriter* pdf_writer_new (GFileOutputStream* stream); +PDFWriter* pdf_writer_construct (GType object_type, GFileOutputStream* stream); +gpointer pdf_writer_ref (gpointer instance); +void pdf_writer_unref (gpointer instance); +GParamSpec* param_spec_pdf_writer (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_pdf_writer (GValue* value, gpointer v_object); +void value_take_pdf_writer (GValue* value, gpointer v_object); +gpointer value_get_pdf_writer (const GValue* value); +GType pdf_writer_get_type (void) G_GNUC_CONST; +void pdf_writer_write_string (PDFWriter* self, const gchar* text); +guint pdf_writer_start_object (PDFWriter* self); +gboolean page_is_color (Page* self); +gint page_get_depth (Page* self); +static guint8* _vala_array_dup1 (guint8* self, int length); +static guint8* _vala_array_dup2 (guint8* self, int length); +void pdf_writer_write (PDFWriter* self, guint8* data, int data_length1); +void book_save (Book* self, const gchar* type, GFile* file, GError** error); +gboolean book_get_needs_saving (Book* self); +static void g_cclosure_user_marshal_VOID__PAGE (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); +static void book_finalize (Book* obj); +#define PDF_WRITER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_PDF_WRITER, PDFWriterPrivate)) +enum  { +	PDF_WRITER_DUMMY_PROPERTY +}; +static void pdf_writer_finalize (PDFWriter* obj); +enum  { +	PS_WRITER_DUMMY_PROPERTY +}; +static cairo_status_t ps_writer_write_cairo_data (PsWriter* self, guint8* data, int data_length1); +static cairo_status_t _ps_writer_write_cairo_data_cairo_write_func_t (gpointer self, guchar* data, int data_length1); +static void ps_writer_finalize (PsWriter* obj); + + +static void _page_unref0_ (gpointer var) { +	(var == NULL) ? NULL : (var = (page_unref (var), NULL)); +} + + +static void _g_list_free__page_unref0_ (GList* self) { +	g_list_foreach (self, (GFunc) _page_unref0_, NULL); +	g_list_free (self); +} + + +Book* book_construct (GType object_type) { +	Book* self = NULL; +	self = (Book*) g_type_create_instance (object_type); +	return self; +} + + +Book* book_new (void) { +	return book_construct (TYPE_BOOK); +} + + +void book_clear (Book* self) { +	g_return_if_fail (self != NULL); +	__g_list_free__page_unref0_0 (self->priv->pages); +	self->priv->pages = NULL; +	g_signal_emit_by_name (self, "cleared"); +} + + +static void book_page_changed_cb (Book* self, Page* page) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	book_set_needs_saving (self, TRUE); +} + + +static void _book_page_changed_cb_page_pixels_changed (Page* _sender, gpointer self) { +	book_page_changed_cb (self, _sender); +} + + +static void _book_page_changed_cb_page_crop_changed (Page* _sender, gpointer self) { +	book_page_changed_cb (self, _sender); +} + + +static gpointer _page_ref0 (gpointer self) { +	return self ? page_ref (self) : NULL; +} + + +Page* book_append_page (Book* self, gint width, gint height, gint dpi, ScanDirection scan_direction) { +	Page* result = NULL; +	Page* _tmp0_ = NULL; +	Page* page; +	Page* _tmp1_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = page_new (width, height, dpi, scan_direction); +	page = _tmp0_; +	g_signal_connect (page, "pixels-changed", (GCallback) _book_page_changed_cb_page_pixels_changed, self); +	g_signal_connect (page, "crop-changed", (GCallback) _book_page_changed_cb_page_crop_changed, self); +	_tmp1_ = _page_ref0 (page); +	self->priv->pages = g_list_append (self->priv->pages, _tmp1_); +	g_signal_emit_by_name (self, "page-added", page); +	book_set_needs_saving (self, TRUE); +	result = page; +	return result; +} + + +void book_move_page (Book* self, Page* page, guint location) { +	Page* _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	self->priv->pages = g_list_remove (self->priv->pages, page); +	_tmp0_ = _page_ref0 (page); +	self->priv->pages = g_list_insert (self->priv->pages, _tmp0_, (gint) location); +	g_signal_emit_by_name (self, "reordered"); +	book_set_needs_saving (self, TRUE); +} + + +void book_delete_page (Book* self, Page* page) { +	guint _tmp0_; +	guint _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	g_signal_parse_name ("pixels-changed", TYPE_PAGE, &_tmp0_, NULL, FALSE); +	g_signal_handlers_disconnect_matched (page, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp0_, 0, NULL, (GCallback) _book_page_changed_cb_page_pixels_changed, self); +	g_signal_parse_name ("crop-changed", TYPE_PAGE, &_tmp1_, NULL, FALSE); +	g_signal_handlers_disconnect_matched (page, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp1_, 0, NULL, (GCallback) _book_page_changed_cb_page_crop_changed, self); +	g_signal_emit_by_name (self, "page-removed", page); +	self->priv->pages = g_list_remove (self->priv->pages, page); +	book_set_needs_saving (self, TRUE); +} + + +guint book_get_n_pages (Book* self) { +	guint result = 0U; +	guint _tmp0_; +	g_return_val_if_fail (self != NULL, 0U); +	_tmp0_ = g_list_length (self->priv->pages); +	result = _tmp0_; +	return result; +} + + +Page* book_get_page (Book* self, gint page_number) { +	Page* result = NULL; +	gconstpointer _tmp1_ = NULL; +	Page* _tmp2_; +	g_return_val_if_fail (self != NULL, NULL); +	if (page_number < 0) { +		guint _tmp0_; +		_tmp0_ = g_list_length (self->priv->pages); +		page_number = ((gint) _tmp0_) + page_number; +	} +	_tmp1_ = g_list_nth_data (self->priv->pages, (guint) page_number); +	_tmp2_ = _page_ref0 ((Page*) _tmp1_); +	result = _tmp2_; +	return result; +} + + +guint book_get_page_index (Book* self, Page* page) { +	guint result = 0U; +	gint _tmp0_; +	g_return_val_if_fail (self != NULL, 0U); +	g_return_val_if_fail (page != NULL, 0U); +	_tmp0_ = g_list_index (self->priv->pages, page); +	result = (guint) _tmp0_; +	return result; +} + + +static gint string_last_index_of_char (const gchar* self, gunichar c, gint start_index) { +	gint result = 0; +	gchar* _tmp0_ = NULL; +	gchar* _result_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = g_utf8_strrchr (((gchar*) self) + start_index, (gssize) (-1), c); +	_result_ = _tmp0_; +	if (_result_ != NULL) { +		result = (gint) (_result_ - ((gchar*) self)); +		return result; +	} else { +		result = -1; +		return result; +	} +} + + +static gchar* string_slice (const gchar* self, glong start, glong end) { +	gchar* result = NULL; +	gint _tmp0_; +	glong string_length; +	gboolean _tmp1_ = FALSE; +	gboolean _tmp2_ = FALSE; +	gchar* _tmp3_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = strlen (self); +	string_length = (glong) _tmp0_; +	if (start < ((glong) 0)) { +		start = string_length + start; +	} +	if (end < ((glong) 0)) { +		end = string_length + end; +	} +	if (start >= ((glong) 0)) { +		_tmp1_ = start <= string_length; +	} else { +		_tmp1_ = FALSE; +	} +	g_return_val_if_fail (_tmp1_, NULL); +	if (end >= ((glong) 0)) { +		_tmp2_ = end <= string_length; +	} else { +		_tmp2_ = FALSE; +	} +	g_return_val_if_fail (_tmp2_, NULL); +	g_return_val_if_fail (start <= end, NULL); +	_tmp3_ = g_strndup (((gchar*) self) + start, (gsize) (end - start)); +	result = _tmp3_; +	return result; +} + + +static GFile* book_make_indexed_file (Book* self, const gchar* uri, gint i) { +	GFile* result = NULL; +	gchar* _tmp1_ = NULL; +	gchar* basename; +	gchar* _tmp2_; +	gchar* prefix; +	gchar* _tmp3_; +	gchar* suffix; +	gint _tmp4_; +	gint extension_index; +	gchar* _tmp10_ = NULL; +	gchar* _tmp11_; +	GFile* _tmp12_ = NULL; +	GFile* _tmp13_; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (uri != NULL, NULL); +	if (i == 0) { +		GFile* _tmp0_ = NULL; +		_tmp0_ = g_file_new_for_uri (uri); +		result = _tmp0_; +		return result; +	} +	_tmp1_ = g_path_get_basename (uri); +	basename = _tmp1_; +	_tmp2_ = g_strdup (uri); +	prefix = _tmp2_; +	_tmp3_ = g_strdup (""); +	suffix = _tmp3_; +	_tmp4_ = string_last_index_of_char (basename, (gunichar) '.', 0); +	extension_index = _tmp4_; +	if (extension_index >= 0) { +		gint _tmp5_; +		gchar* _tmp6_ = NULL; +		gint _tmp7_; +		gint _tmp8_; +		gchar* _tmp9_ = NULL; +		_tmp5_ = strlen (basename); +		_tmp6_ = string_slice (basename, (glong) extension_index, (glong) _tmp5_); +		_g_free0 (suffix); +		suffix = _tmp6_; +		_tmp7_ = strlen (uri); +		_tmp8_ = strlen (suffix); +		_tmp9_ = string_slice (uri, (glong) 0, (glong) (_tmp7_ - _tmp8_)); +		_g_free0 (prefix); +		prefix = _tmp9_; +	} +	_tmp10_ = g_strdup_printf ("%s-%d%s", prefix, i, suffix); +	_tmp11_ = _tmp10_; +	_tmp12_ = g_file_new_for_uri (_tmp11_); +	_tmp13_ = _tmp12_; +	_g_free0 (_tmp11_); +	result = _tmp13_; +	_g_free0 (suffix); +	_g_free0 (prefix); +	_g_free0 (basename); +	return result; +} + + +static void book_save_multi_file (Book* self, const gchar* type, GFile* file, GError** error) { +	gint i; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (type != NULL); +	g_return_if_fail (file != NULL); +	i = 0; +	{ +		GList* page_collection = NULL; +		GList* page_it = NULL; +		page_collection = self->priv->pages; +		for (page_it = page_collection; page_it != NULL; page_it = page_it->next) { +			Page* _tmp0_; +			Page* page = NULL; +			_tmp0_ = _page_ref0 ((Page*) page_it->data); +			page = _tmp0_; +			{ +				gchar* _tmp1_ = NULL; +				gchar* _tmp2_; +				GFile* _tmp3_ = NULL; +				GFile* _tmp4_; +				_tmp1_ = g_file_get_uri (file); +				_tmp2_ = _tmp1_; +				_tmp3_ = book_make_indexed_file (self, _tmp2_, i); +				_tmp4_ = _tmp3_; +				page_save (page, type, _tmp4_, &_inner_error_); +				_g_object_unref0 (_tmp4_); +				_g_free0 (_tmp2_); +				if (_inner_error_ != NULL) { +					g_propagate_error (error, _inner_error_); +					_page_unref0 (page); +					return; +				} +				i++; +				_page_unref0 (page); +			} +		} +	} +} + + +static void book_save_ps_pdf_surface (Book* self, cairo_surface_t* surface, GdkPixbuf* image, gdouble dpi) { +	cairo_t* _tmp0_ = NULL; +	cairo_t* context; +	cairo_pattern_t* _tmp1_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (surface != NULL); +	g_return_if_fail (image != NULL); +	_tmp0_ = cairo_create (surface); +	context = _tmp0_; +	cairo_scale (context, 72.0 / dpi, 72.0 / dpi); +	gdk_cairo_set_source_pixbuf (context, image, (gdouble) 0, (gdouble) 0); +	_tmp1_ = cairo_get_source (context); +	cairo_pattern_set_filter (_tmp1_, CAIRO_FILTER_BEST); +	cairo_paint (context); +	_cairo_destroy0 (context); +} + + +static gpointer _cairo_surface_reference0 (gpointer self) { +	return self ? cairo_surface_reference (self) : NULL; +} + + +static void book_save_ps (Book* self, GFile* file, GError** error) { +	GFileOutputStream* _tmp0_ = NULL; +	GFileOutputStream* stream; +	PsWriter* _tmp1_ = NULL; +	PsWriter* writer; +	cairo_surface_t* _tmp2_; +	cairo_surface_t* surface; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (file != NULL); +	_tmp0_ = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &_inner_error_); +	stream = _tmp0_; +	if (_inner_error_ != NULL) { +		g_propagate_error (error, _inner_error_); +		return; +	} +	_tmp1_ = ps_writer_new (stream); +	writer = _tmp1_; +	_tmp2_ = _cairo_surface_reference0 (writer->surface); +	surface = _tmp2_; +	{ +		GList* page_collection = NULL; +		GList* page_it = NULL; +		page_collection = self->priv->pages; +		for (page_it = page_collection; page_it != NULL; page_it = page_it->next) { +			Page* _tmp3_; +			Page* page = NULL; +			_tmp3_ = _page_ref0 ((Page*) page_it->data); +			page = _tmp3_; +			{ +				GdkPixbuf* _tmp4_ = NULL; +				GdkPixbuf* image; +				gint _tmp5_; +				gint _tmp6_; +				gdouble width; +				gint _tmp7_; +				gint _tmp8_; +				gdouble height; +				gint _tmp9_; +				_tmp4_ = page_get_image (page, TRUE); +				image = _tmp4_; +				_tmp5_ = gdk_pixbuf_get_width (image); +				_tmp6_ = page_get_dpi (page); +				width = (_tmp5_ * 72.0) / _tmp6_; +				_tmp7_ = gdk_pixbuf_get_height (image); +				_tmp8_ = page_get_dpi (page); +				height = (_tmp7_ * 72.0) / _tmp8_; +				cairo_ps_surface_set_size (surface, width, height); +				_tmp9_ = page_get_dpi (page); +				book_save_ps_pdf_surface (self, surface, image, (gdouble) _tmp9_); +				cairo_surface_show_page (surface); +				_g_object_unref0 (image); +				_page_unref0 (page); +			} +		} +	} +	_cairo_surface_destroy0 (surface); +	_ps_writer_unref0 (writer); +	_g_object_unref0 (stream); +} + + +static guint8* book_compress_zlib (Book* self, guint8* data, int data_length1, int* result_length1) { +	guint8* result = NULL; +	z_stream stream = {0}; +	guint8* _tmp0_ = NULL; +	guint8* out_data; +	gint out_data_length1; +	gint _out_data_size_; +	guint n_written; +	gint _tmp3_; +	guint8* _tmp4_; +	g_return_val_if_fail (self != NULL, NULL); +	deflateInit (&stream, (gint) Z_BEST_COMPRESSION); +	_tmp0_ = g_new0 (guint8, data_length1); +	out_data = _tmp0_; +	out_data_length1 = data_length1; +	_out_data_size_ = out_data_length1; +	stream.next_in = data; +	stream.avail_in = data_length1; +	stream.next_out = out_data; +	stream.avail_out = out_data_length1; +	while (TRUE) { +		gint _tmp1_; +		if (!(stream.avail_in > ((guint) 0))) { +			break; +		} +		_tmp1_ = deflate (&stream, (gint) Z_FINISH); +		if (_tmp1_ == ((gint) Z_STREAM_ERROR)) { +			break; +		} +	} +	if (stream.avail_in > ((guint) 0)) { +		guint8* _tmp2_; +		_tmp2_ = NULL; +		if (result_length1) { +			*result_length1 = 0; +		} +		result = _tmp2_; +		out_data = (g_free (out_data), NULL); +		deflateEnd (&stream); +		return result; +	} +	n_written = data_length1 - stream.avail_out; +	_tmp3_ = (gint) n_written; +	out_data = g_renew (guint8, out_data, (gint) n_written); +	(_tmp3_ > out_data_length1) ? memset (out_data + out_data_length1, 0, sizeof (guint8) * (_tmp3_ - out_data_length1)) : NULL; +	out_data_length1 = _tmp3_; +	_out_data_size_ = _tmp3_; +	_tmp4_ = out_data; +	if (result_length1) { +		*result_length1 = out_data_length1; +	} +	result = _tmp4_; +	deflateEnd (&stream); +	return result; +} + + +static void book_jpeg_init_cb (struct jpeg_compress_struct* info) { +} + + +static gboolean book_jpeg_empty_cb (struct jpeg_compress_struct* info) { +	gboolean result = FALSE; +	result = TRUE; +	return result; +} + + +static void book_jpeg_term_cb (struct jpeg_compress_struct* info) { +} + + +static void _book_jpeg_init_cb_jpeg_initdestinationfunc (struct jpeg_compress_struct* cinfo) { +	book_jpeg_init_cb (cinfo); +} + + +static gboolean _book_jpeg_empty_cb_jpeg_emptyoutputbufferfunc (struct jpeg_compress_struct* cinfo) { +	gboolean result; +	result = book_jpeg_empty_cb (cinfo); +	return result; +} + + +static void _book_jpeg_term_cb_jpeg_termdestinationfunc (struct jpeg_compress_struct* cinfo) { +	book_jpeg_term_cb (cinfo); +} + + +static guint8* book_compress_jpeg (Book* self, GdkPixbuf* image, gsize* n_written, int* result_length1) { +	gsize _n_written = 0UL; +	guint8* result = NULL; +	struct jpeg_compress_struct info = {0}; +	struct jpeg_error_mgr jerr = {0}; +	struct jpeg_destination_mgr dest_mgr = {0}; +	struct jpeg_error_mgr* _tmp0_ = NULL; +	gint _tmp1_; +	gint _tmp2_; +	gint max_length; +	guint8* _tmp3_ = NULL; +	guint8* data; +	gint data_length1; +	gint _data_size_; +	guint8* _tmp4_ = NULL; +	guint8* pixels; +	gint pixels_length1; +	gint _pixels_size_; +	guint8* _tmp7_; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (image != NULL, NULL); +	memset (&info, 0, sizeof (struct jpeg_compress_struct)); +	memset (&jerr, 0, sizeof (struct jpeg_error_mgr)); +	memset (&dest_mgr, 0, sizeof (struct jpeg_destination_mgr)); +	_tmp0_ = jpeg_std_error (&jerr); +	info.err = _tmp0_; +	jpeg_create_compress (&info); +	_tmp1_ = gdk_pixbuf_get_width (image); +	info.image_width = _tmp1_; +	_tmp2_ = gdk_pixbuf_get_height (image); +	info.image_height = _tmp2_; +	info.input_components = 3; +	info.in_color_space = JCS_RGB; +	jpeg_set_defaults (&info); +	max_length = (info.image_width * info.image_height) * info.input_components; +	_tmp3_ = g_new0 (guint8, max_length); +	data = _tmp3_; +	data_length1 = max_length; +	_data_size_ = data_length1; +	dest_mgr.next_output_byte = data; +	dest_mgr.free_in_buffer = max_length; +	dest_mgr.init_destination = _book_jpeg_init_cb_jpeg_initdestinationfunc; +	dest_mgr.empty_output_buffer = _book_jpeg_empty_cb_jpeg_emptyoutputbufferfunc; +	dest_mgr.term_destination = _book_jpeg_term_cb_jpeg_termdestinationfunc; +	info.dest = &dest_mgr; +	jpeg_start_compress (&info, TRUE); +	_tmp4_ = gdk_pixbuf_get_pixels (image); +	pixels = _tmp4_; +	pixels_length1 = -1; +	_pixels_size_ = pixels_length1; +	{ +		gint r; +		r = 0; +		{ +			gboolean _tmp5_; +			_tmp5_ = TRUE; +			while (TRUE) { +				guint8* row[1] = {0}; +				gint _tmp6_; +				if (!_tmp5_) { +					r++; +				} +				_tmp5_ = FALSE; +				if (!(r < info.image_height)) { +					break; +				} +				_tmp6_ = gdk_pixbuf_get_rowstride (image); +				row[0] = ((guint8*) pixels) + (r * _tmp6_); +				jpeg_write_scanlines (&info, row, 1); +			} +		} +	} +	jpeg_finish_compress (&info); +	_n_written = (gsize) (max_length - dest_mgr.free_in_buffer); +	_tmp7_ = data; +	if (result_length1) { +		*result_length1 = data_length1; +	} +	result = _tmp7_; +	jpeg_destroy_compress (&info); +	if (n_written) { +		*n_written = _n_written; +	} +	return result; +} + + +static guint8* _vala_array_dup1 (guint8* self, int length) { +	return g_memdup (self, length * sizeof (guint8)); +} + + +static guint8* _vala_array_dup2 (guint8* self, int length) { +	return g_memdup (self, length * sizeof (guint8)); +} + + +static void book_save_pdf (Book* self, GFile* file, GError** error) { +	GFileOutputStream* _tmp0_ = NULL; +	GFileOutputStream* stream; +	PDFWriter* _tmp1_ = NULL; +	PDFWriter* writer; +	guint _tmp2_; +	guint catalog_number; +	gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	gchar* _tmp5_ = NULL; +	gchar* _tmp6_; +	guint _tmp7_; +	guint pages_number; +	gchar* _tmp8_ = NULL; +	gchar* _tmp9_; +	guint _tmp14_; +	gchar* _tmp15_ = NULL; +	gchar* _tmp16_; +	guint _tmp100_; +	guint info_number; +	gchar* _tmp101_ = NULL; +	gchar* _tmp102_; +	gchar* _tmp103_ = NULL; +	gchar* _tmp104_; +	gsize xref_offset; +	guint _tmp105_; +	gchar* _tmp106_ = NULL; +	gchar* _tmp107_; +	guint _tmp110_; +	gchar* _tmp111_ = NULL; +	gchar* _tmp112_; +	gchar* _tmp113_ = NULL; +	gchar* _tmp114_; +	gchar* _tmp115_ = NULL; +	gchar* _tmp116_; +	gchar* _tmp117_ = NULL; +	gchar* _tmp118_; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (file != NULL); +	_tmp0_ = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &_inner_error_); +	stream = _tmp0_; +	if (_inner_error_ != NULL) { +		g_propagate_error (error, _inner_error_); +		return; +	} +	_tmp1_ = pdf_writer_new (stream); +	writer = _tmp1_; +	pdf_writer_write_string (writer, "%%PDF-1.3\n"); +	pdf_writer_write_string (writer, "%%\xe2\xe3\xcf\xd3\n"); +	_tmp2_ = pdf_writer_start_object (writer); +	catalog_number = _tmp2_; +	_tmp3_ = g_strdup_printf ("%u 0 obj\n", catalog_number); +	_tmp4_ = _tmp3_; +	pdf_writer_write_string (writer, _tmp4_); +	_g_free0 (_tmp4_); +	pdf_writer_write_string (writer, "<<\n"); +	pdf_writer_write_string (writer, "/Type /Catalog\n"); +	_tmp5_ = g_strdup_printf ("/Pages %u 0 R\n", catalog_number + 1); +	_tmp6_ = _tmp5_; +	pdf_writer_write_string (writer, _tmp6_); +	_g_free0 (_tmp6_); +	pdf_writer_write_string (writer, ">>\n"); +	pdf_writer_write_string (writer, "endobj\n"); +	pdf_writer_write_string (writer, "\n"); +	_tmp7_ = pdf_writer_start_object (writer); +	pages_number = _tmp7_; +	_tmp8_ = g_strdup_printf ("%u 0 obj\n", pages_number); +	_tmp9_ = _tmp8_; +	pdf_writer_write_string (writer, _tmp9_); +	_g_free0 (_tmp9_); +	pdf_writer_write_string (writer, "<<\n"); +	pdf_writer_write_string (writer, "/Type /Pages\n"); +	pdf_writer_write_string (writer, "/Kids ["); +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp10_; +			_tmp10_ = TRUE; +			while (TRUE) { +				guint _tmp11_; +				gchar* _tmp12_ = NULL; +				gchar* _tmp13_; +				if (!_tmp10_) { +					i++; +				} +				_tmp10_ = FALSE; +				_tmp11_ = book_get_n_pages (self); +				if (!(((guint) i) < _tmp11_)) { +					break; +				} +				_tmp12_ = g_strdup_printf (" %u 0 R", (pages_number + 1) + (i * 3)); +				_tmp13_ = _tmp12_; +				pdf_writer_write_string (writer, _tmp13_); +				_g_free0 (_tmp13_); +			} +		} +	} +	pdf_writer_write_string (writer, " ]\n"); +	_tmp14_ = book_get_n_pages (self); +	_tmp15_ = g_strdup_printf ("/Count %u\n", _tmp14_); +	_tmp16_ = _tmp15_; +	pdf_writer_write_string (writer, _tmp16_); +	_g_free0 (_tmp16_); +	pdf_writer_write_string (writer, ">>\n"); +	pdf_writer_write_string (writer, "endobj\n"); +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp17_; +			_tmp17_ = TRUE; +			while (TRUE) { +				guint _tmp18_; +				Page* _tmp19_ = NULL; +				Page* page; +				GdkPixbuf* _tmp20_ = NULL; +				GdkPixbuf* image; +				gint _tmp21_; +				gint width; +				gint _tmp22_; +				gint height; +				guint8* _tmp23_ = NULL; +				guint8* pixels; +				gint pixels_length1; +				gint _pixels_size_; +				gint _tmp24_; +				gdouble page_width; +				gint _tmp25_; +				gdouble page_height; +				gint depth; +				gchar* _tmp26_; +				gchar* color_space; +				gchar* filter; +				gchar* _tmp27_ = NULL; +				gchar* width_buffer; +				gint width_buffer_length1; +				gint _width_buffer_size_; +				gchar* _tmp28_ = NULL; +				gchar* height_buffer; +				gint height_buffer_length1; +				gint _height_buffer_size_; +				guint8* data = NULL; +				gint data_length1 = 0; +				gint _data_size_ = 0; +				gboolean _tmp29_; +				gint _tmp52_; +				guint8* _tmp53_ = NULL; +				guint8* compressed_data; +				gint compressed_data_length1; +				gint _compressed_data_size_; +				guint _tmp63_; +				guint number; +				gchar* _tmp64_ = NULL; +				gchar* _tmp65_; +				gchar* _tmp66_ = NULL; +				gchar* _tmp67_; +				gchar* _tmp68_ = NULL; +				gchar* _tmp69_; +				const gchar* _tmp70_ = NULL; +				const gchar* _tmp71_ = NULL; +				gchar* _tmp72_ = NULL; +				gchar* _tmp73_; +				gchar* _tmp74_ = NULL; +				gchar* _tmp75_; +				guint _tmp76_; +				gchar* _tmp77_ = NULL; +				gchar* _tmp78_; +				gchar* _tmp79_ = NULL; +				gchar* _tmp80_; +				gchar* _tmp81_ = NULL; +				gchar* _tmp82_; +				gchar* _tmp83_ = NULL; +				gchar* _tmp84_; +				gchar* _tmp85_ = NULL; +				gchar* _tmp86_; +				gchar* _tmp87_ = NULL; +				gchar* _tmp88_; +				const gchar* _tmp91_ = NULL; +				const gchar* _tmp92_ = NULL; +				gchar* _tmp93_ = NULL; +				gchar* command; +				guint _tmp94_; +				gchar* _tmp95_ = NULL; +				gchar* _tmp96_; +				gint _tmp97_; +				gchar* _tmp98_ = NULL; +				gchar* _tmp99_; +				if (!_tmp17_) { +					i++; +				} +				_tmp17_ = FALSE; +				_tmp18_ = book_get_n_pages (self); +				if (!(((guint) i) < _tmp18_)) { +					break; +				} +				_tmp19_ = book_get_page (self, i); +				page = _tmp19_; +				_tmp20_ = page_get_image (page, TRUE); +				image = _tmp20_; +				_tmp21_ = gdk_pixbuf_get_width (image); +				width = _tmp21_; +				_tmp22_ = gdk_pixbuf_get_height (image); +				height = _tmp22_; +				_tmp23_ = gdk_pixbuf_get_pixels (image); +				pixels = _tmp23_; +				pixels_length1 = -1; +				_pixels_size_ = pixels_length1; +				_tmp24_ = page_get_dpi (page); +				page_width = (width * 72.0) / _tmp24_; +				_tmp25_ = page_get_dpi (page); +				page_height = (height * 72.0) / _tmp25_; +				depth = 8; +				_tmp26_ = g_strdup ("DeviceRGB"); +				color_space = _tmp26_; +				filter = NULL; +				_tmp27_ = g_new0 (gchar, G_ASCII_DTOSTR_BUF_SIZE); +				width_buffer = _tmp27_; +				width_buffer_length1 = G_ASCII_DTOSTR_BUF_SIZE; +				_width_buffer_size_ = width_buffer_length1; +				_tmp28_ = g_new0 (gchar, G_ASCII_DTOSTR_BUF_SIZE); +				height_buffer = _tmp28_; +				height_buffer_length1 = G_ASCII_DTOSTR_BUF_SIZE; +				_height_buffer_size_ = height_buffer_length1; +				_tmp29_ = page_is_color (page); +				if (_tmp29_) { +					gchar* _tmp30_; +					gint data_length; +					guint8* _tmp31_ = NULL; +					depth = 8; +					_tmp30_ = g_strdup ("DeviceRGB"); +					_g_free0 (color_space); +					color_space = _tmp30_; +					data_length = ((height * width) * 3) + 1; +					_tmp31_ = g_new0 (guint8, data_length); +					data = (g_free (data), NULL); +					data = _tmp31_; +					data_length1 = data_length; +					_data_size_ = data_length1; +					{ +						gint row; +						row = 0; +						{ +							gboolean _tmp32_; +							_tmp32_ = TRUE; +							while (TRUE) { +								gint _tmp33_; +								gint in_offset; +								gint out_offset; +								if (!_tmp32_) { +									row++; +								} +								_tmp32_ = FALSE; +								if (!(row < height)) { +									break; +								} +								_tmp33_ = gdk_pixbuf_get_rowstride (image); +								in_offset = row * _tmp33_; +								out_offset = (row * width) * 3; +								{ +									gint x; +									x = 0; +									{ +										gboolean _tmp34_; +										_tmp34_ = TRUE; +										while (TRUE) { +											gint in_o; +											gint out_o; +											if (!_tmp34_) { +												x++; +											} +											_tmp34_ = FALSE; +											if (!(x < width)) { +												break; +											} +											in_o = in_offset + (x * 3); +											out_o = out_offset + (x * 3); +											data[out_o] = pixels[in_o]; +											data[out_o + 1] = pixels[in_o + 1]; +											data[out_o + 2] = pixels[in_o + 2]; +										} +									} +								} +							} +						} +					} +				} else { +					gint _tmp35_; +					_tmp35_ = page_get_depth (page); +					if (_tmp35_ == 2) { +						gint shift_count; +						gchar* _tmp36_; +						gint data_length; +						guint8* _tmp37_ = NULL; +						gint offset; +						shift_count = 6; +						depth = 2; +						_tmp36_ = g_strdup ("DeviceGray"); +						_g_free0 (color_space); +						color_space = _tmp36_; +						data_length = height * (((width * 2) + 7) / 8); +						_tmp37_ = g_new0 (guint8, data_length); +						data = (g_free (data), NULL); +						data = _tmp37_; +						data_length1 = data_length; +						_data_size_ = data_length1; +						offset = 0; +						data[offset] = (guint8) 0; +						{ +							gint row; +							row = 0; +							{ +								gboolean _tmp38_; +								_tmp38_ = TRUE; +								while (TRUE) { +									gint _tmp39_; +									gint in_offset; +									if (!_tmp38_) { +										row++; +									} +									_tmp38_ = FALSE; +									if (!(row < height)) { +										break; +									} +									if (shift_count != 6) { +										offset++; +										data[offset] = (guint8) 0; +										shift_count = 6; +									} +									_tmp39_ = gdk_pixbuf_get_rowstride (image); +									in_offset = row * _tmp39_; +									{ +										gint x; +										x = 0; +										{ +											gboolean _tmp40_; +											_tmp40_ = TRUE; +											while (TRUE) { +												guint8 p; +												if (!_tmp40_) { +													x++; +												} +												_tmp40_ = FALSE; +												if (!(x < width)) { +													break; +												} +												p = pixels[in_offset + (x * 3)]; +												if (((gint) p) >= 192) { +													data[offset] |= (guint8) (3 << shift_count); +												} else { +													if (((gint) p) >= 128) { +														data[offset] |= (guint8) (2 << shift_count); +													} else { +														if (((gint) p) >= 64) { +															data[offset] |= (guint8) (1 << shift_count); +														} +													} +												} +												if (shift_count == 0) { +													offset++; +													data[offset] = (guint8) 0; +													shift_count = 6; +												} else { +													shift_count = shift_count - 2; +												} +											} +										} +									} +								} +							} +						} +					} else { +						gint _tmp41_; +						_tmp41_ = page_get_depth (page); +						if (_tmp41_ == 1) { +							gint mask; +							gchar* _tmp42_; +							gint data_length; +							guint8* _tmp43_ = NULL; +							gint offset; +							mask = 0x80; +							depth = 1; +							_tmp42_ = g_strdup ("DeviceGray"); +							_g_free0 (color_space); +							color_space = _tmp42_; +							data_length = height * ((width + 7) / 8); +							_tmp43_ = g_new0 (guint8, data_length); +							data = (g_free (data), NULL); +							data = _tmp43_; +							data_length1 = data_length; +							_data_size_ = data_length1; +							offset = 0; +							data[offset] = (guint8) 0; +							{ +								gint row; +								row = 0; +								{ +									gboolean _tmp44_; +									_tmp44_ = TRUE; +									while (TRUE) { +										gint _tmp45_; +										gint in_offset; +										if (!_tmp44_) { +											row++; +										} +										_tmp44_ = FALSE; +										if (!(row < height)) { +											break; +										} +										if (mask != 0x80) { +											offset++; +											data[offset] = (guint8) 0; +											mask = 0x80; +										} +										_tmp45_ = gdk_pixbuf_get_rowstride (image); +										in_offset = row * _tmp45_; +										{ +											gint x; +											x = 0; +											{ +												gboolean _tmp46_; +												_tmp46_ = TRUE; +												while (TRUE) { +													if (!_tmp46_) { +														x++; +													} +													_tmp46_ = FALSE; +													if (!(x < width)) { +														break; +													} +													if (((gint) pixels[in_offset + (x * 3)]) != 0) { +														data[offset] |= (guint8) mask; +													} +													mask = mask >> 1; +													if (mask == 0) { +														offset++; +														data[offset] = (guint8) 0; +														mask = 0x80; +													} +												} +											} +										} +									} +								} +							} +						} else { +							gchar* _tmp47_; +							gint data_length; +							guint8* _tmp48_ = NULL; +							depth = 8; +							_tmp47_ = g_strdup ("DeviceGray"); +							_g_free0 (color_space); +							color_space = _tmp47_; +							data_length = (height * width) + 1; +							_tmp48_ = g_new0 (guint8, data_length); +							data = (g_free (data), NULL); +							data = _tmp48_; +							data_length1 = data_length; +							_data_size_ = data_length1; +							{ +								gint row; +								row = 0; +								{ +									gboolean _tmp49_; +									_tmp49_ = TRUE; +									while (TRUE) { +										gint _tmp50_; +										gint in_offset; +										gint out_offset; +										if (!_tmp49_) { +											row++; +										} +										_tmp49_ = FALSE; +										if (!(row < height)) { +											break; +										} +										_tmp50_ = gdk_pixbuf_get_rowstride (image); +										in_offset = row * _tmp50_; +										out_offset = row * width; +										{ +											gint x; +											x = 0; +											{ +												gboolean _tmp51_; +												_tmp51_ = TRUE; +												while (TRUE) { +													if (!_tmp51_) { +														x++; +													} +													_tmp51_ = FALSE; +													if (!(x < width)) { +														break; +													} +													data[out_offset + x] = pixels[in_offset + (x * 3)]; +												} +											} +										} +									} +								} +							} +						} +					} +				} +				_tmp53_ = book_compress_zlib (self, data, data_length1, &_tmp52_); +				compressed_data = _tmp53_; +				compressed_data_length1 = _tmp52_; +				_compressed_data_size_ = compressed_data_length1; +				if (compressed_data != NULL) { +					if (depth > 1) { +						gsize jpeg_length = 0UL; +						gsize _tmp54_; +						gint _tmp55_; +						guint8* _tmp56_ = NULL; +						guint8* jpeg_data; +						gint jpeg_data_length1; +						gint _jpeg_data_size_; +						_tmp56_ = book_compress_jpeg (self, image, &_tmp54_, &_tmp55_); +						jpeg_length = _tmp54_; +						jpeg_data = _tmp56_; +						jpeg_data_length1 = _tmp55_; +						_jpeg_data_size_ = jpeg_data_length1; +						if (jpeg_length < ((gsize) compressed_data_length1)) { +							gchar* _tmp57_; +							guint8* _tmp58_; +							guint8* _tmp59_; +							_tmp57_ = g_strdup ("DCTDecode"); +							_g_free0 (filter); +							filter = _tmp57_; +							_tmp59_ = (_tmp58_ = jpeg_data, (_tmp58_ == NULL) ? ((gpointer) _tmp58_) : _vala_array_dup1 (_tmp58_, jpeg_data_length1)); +							data = (g_free (data), NULL); +							data = _tmp59_; +							data_length1 = jpeg_data_length1; +							_data_size_ = data_length1; +						} +						jpeg_data = (g_free (jpeg_data), NULL); +					} +					if (filter == NULL) { +						gchar* _tmp60_; +						guint8* _tmp61_; +						guint8* _tmp62_; +						_tmp60_ = g_strdup ("FlateDecode"); +						_g_free0 (filter); +						filter = _tmp60_; +						_tmp62_ = (_tmp61_ = compressed_data, (_tmp61_ == NULL) ? ((gpointer) _tmp61_) : _vala_array_dup2 (_tmp61_, compressed_data_length1)); +						data = (g_free (data), NULL); +						data = _tmp62_; +						data_length1 = compressed_data_length1; +						_data_size_ = data_length1; +					} +				} +				pdf_writer_write_string (writer, "\n"); +				_tmp63_ = pdf_writer_start_object (writer); +				number = _tmp63_; +				_tmp64_ = g_strdup_printf ("%u 0 obj\n", number); +				_tmp65_ = _tmp64_; +				pdf_writer_write_string (writer, _tmp65_); +				_g_free0 (_tmp65_); +				pdf_writer_write_string (writer, "<<\n"); +				pdf_writer_write_string (writer, "/Type /Page\n"); +				_tmp66_ = g_strdup_printf ("/Parent %u 0 R\n", pages_number); +				_tmp67_ = _tmp66_; +				pdf_writer_write_string (writer, _tmp67_); +				_g_free0 (_tmp67_); +				_tmp68_ = g_strdup_printf ("/Resources << /XObject << /Im%d %u 0 R >> >>\n", i, number + 1); +				_tmp69_ = _tmp68_; +				pdf_writer_write_string (writer, _tmp69_); +				_g_free0 (_tmp69_); +				_tmp70_ = g_ascii_formatd (width_buffer, width_buffer_length1, "%.2f", page_width); +				_tmp71_ = g_ascii_formatd (height_buffer, height_buffer_length1, "%.2f", page_height); +				_tmp72_ = g_strdup_printf ("/MediaBox [ 0 0 %s %s ]\n", _tmp70_, _tmp71_); +				_tmp73_ = _tmp72_; +				pdf_writer_write_string (writer, _tmp73_); +				_g_free0 (_tmp73_); +				_tmp74_ = g_strdup_printf ("/Contents %u 0 R\n", number + 2); +				_tmp75_ = _tmp74_; +				pdf_writer_write_string (writer, _tmp75_); +				_g_free0 (_tmp75_); +				pdf_writer_write_string (writer, ">>\n"); +				pdf_writer_write_string (writer, "endobj\n"); +				pdf_writer_write_string (writer, "\n"); +				_tmp76_ = pdf_writer_start_object (writer); +				number = _tmp76_; +				_tmp77_ = g_strdup_printf ("%u 0 obj\n", number); +				_tmp78_ = _tmp77_; +				pdf_writer_write_string (writer, _tmp78_); +				_g_free0 (_tmp78_); +				pdf_writer_write_string (writer, "<<\n"); +				pdf_writer_write_string (writer, "/Type /XObject\n"); +				pdf_writer_write_string (writer, "/Subtype /Image\n"); +				_tmp79_ = g_strdup_printf ("/Width %d\n", width); +				_tmp80_ = _tmp79_; +				pdf_writer_write_string (writer, _tmp80_); +				_g_free0 (_tmp80_); +				_tmp81_ = g_strdup_printf ("/Height %d\n", height); +				_tmp82_ = _tmp81_; +				pdf_writer_write_string (writer, _tmp82_); +				_g_free0 (_tmp82_); +				_tmp83_ = g_strdup_printf ("/ColorSpace /%s\n", color_space); +				_tmp84_ = _tmp83_; +				pdf_writer_write_string (writer, _tmp84_); +				_g_free0 (_tmp84_); +				_tmp85_ = g_strdup_printf ("/BitsPerComponent %d\n", depth); +				_tmp86_ = _tmp85_; +				pdf_writer_write_string (writer, _tmp86_); +				_g_free0 (_tmp86_); +				_tmp87_ = g_strdup_printf ("/Length %d\n", data_length1); +				_tmp88_ = _tmp87_; +				pdf_writer_write_string (writer, _tmp88_); +				_g_free0 (_tmp88_); +				if (filter != NULL) { +					gchar* _tmp89_ = NULL; +					gchar* _tmp90_; +					_tmp89_ = g_strdup_printf ("/Filter /%s\n", filter); +					_tmp90_ = _tmp89_; +					pdf_writer_write_string (writer, _tmp90_); +					_g_free0 (_tmp90_); +				} +				pdf_writer_write_string (writer, ">>\n"); +				pdf_writer_write_string (writer, "stream\n"); +				pdf_writer_write (writer, data, data_length1); +				pdf_writer_write_string (writer, "\n"); +				pdf_writer_write_string (writer, "endstream\n"); +				pdf_writer_write_string (writer, "endobj\n"); +				_tmp91_ = g_ascii_formatd (width_buffer, width_buffer_length1, "%f", page_width); +				_tmp92_ = g_ascii_formatd (height_buffer, height_buffer_length1, "%f", page_height); +				_tmp93_ = g_strdup_printf ("q\n%s 0 0 %s 0 0 cm\n/Im%d Do\nQ", _tmp91_, _tmp92_, i); +				command = _tmp93_; +				pdf_writer_write_string (writer, "\n"); +				_tmp94_ = pdf_writer_start_object (writer); +				number = _tmp94_; +				_tmp95_ = g_strdup_printf ("%u 0 obj\n", number); +				_tmp96_ = _tmp95_; +				pdf_writer_write_string (writer, _tmp96_); +				_g_free0 (_tmp96_); +				pdf_writer_write_string (writer, "<<\n"); +				_tmp97_ = strlen (command); +				_tmp98_ = g_strdup_printf ("/Length %d\n", _tmp97_ + 1); +				_tmp99_ = _tmp98_; +				pdf_writer_write_string (writer, _tmp99_); +				_g_free0 (_tmp99_); +				pdf_writer_write_string (writer, ">>\n"); +				pdf_writer_write_string (writer, "stream\n"); +				pdf_writer_write_string (writer, command); +				pdf_writer_write_string (writer, "\n"); +				pdf_writer_write_string (writer, "endstream\n"); +				pdf_writer_write_string (writer, "endobj\n"); +				_g_free0 (command); +				compressed_data = (g_free (compressed_data), NULL); +				data = (g_free (data), NULL); +				height_buffer = (g_free (height_buffer), NULL); +				width_buffer = (g_free (width_buffer), NULL); +				_g_free0 (filter); +				_g_free0 (color_space); +				_g_object_unref0 (image); +				_page_unref0 (page); +			} +		} +	} +	pdf_writer_write_string (writer, "\n"); +	_tmp100_ = pdf_writer_start_object (writer); +	info_number = _tmp100_; +	_tmp101_ = g_strdup_printf ("%u 0 obj\n", info_number); +	_tmp102_ = _tmp101_; +	pdf_writer_write_string (writer, _tmp102_); +	_g_free0 (_tmp102_); +	pdf_writer_write_string (writer, "<<\n"); +	_tmp103_ = g_strdup_printf ("/Creator (Simple Scan %s)\n", VERSION); +	_tmp104_ = _tmp103_; +	pdf_writer_write_string (writer, _tmp104_); +	_g_free0 (_tmp104_); +	pdf_writer_write_string (writer, ">>\n"); +	pdf_writer_write_string (writer, "endobj\n"); +	xref_offset = writer->offset; +	pdf_writer_write_string (writer, "xref\n"); +	_tmp105_ = g_list_length (writer->object_offsets); +	_tmp106_ = g_strdup_printf ("1 %zu\n", (gsize) _tmp105_); +	_tmp107_ = _tmp106_; +	pdf_writer_write_string (writer, _tmp107_); +	_g_free0 (_tmp107_); +	{ +		GList* offset_collection = NULL; +		GList* offset_it = NULL; +		offset_collection = writer->object_offsets; +		for (offset_it = offset_collection; offset_it != NULL; offset_it = offset_it->next) { +			guint offset = 0U; +			offset = GPOINTER_TO_UINT (offset_it->data); +			{ +				gchar* _tmp108_ = NULL; +				gchar* _tmp109_; +				_tmp108_ = g_strdup_printf ("%010zu 0000 n\n", (gsize) offset); +				_tmp109_ = _tmp108_; +				pdf_writer_write_string (writer, _tmp109_); +				_g_free0 (_tmp109_); +			} +		} +	} +	pdf_writer_write_string (writer, "trailer\n"); +	pdf_writer_write_string (writer, "<<\n"); +	_tmp110_ = g_list_length (writer->object_offsets); +	_tmp111_ = g_strdup_printf ("/Size %zu\n", (gsize) _tmp110_); +	_tmp112_ = _tmp111_; +	pdf_writer_write_string (writer, _tmp112_); +	_g_free0 (_tmp112_); +	_tmp113_ = g_strdup_printf ("/Info %u 0 R\n", info_number); +	_tmp114_ = _tmp113_; +	pdf_writer_write_string (writer, _tmp114_); +	_g_free0 (_tmp114_); +	_tmp115_ = g_strdup_printf ("/Root %u 0 R\n", catalog_number); +	_tmp116_ = _tmp115_; +	pdf_writer_write_string (writer, _tmp116_); +	_g_free0 (_tmp116_); +	pdf_writer_write_string (writer, ">>\n"); +	pdf_writer_write_string (writer, "startxref\n"); +	_tmp117_ = g_strdup_printf ("%zu\n", xref_offset); +	_tmp118_ = _tmp117_; +	pdf_writer_write_string (writer, _tmp118_); +	_g_free0 (_tmp118_); +	pdf_writer_write_string (writer, "%%%%EOF\n"); +	_pdf_writer_unref0 (writer); +	_g_object_unref0 (stream); +} + + +void book_save (Book* self, const gchar* type, GFile* file, GError** error) { +	gint _tmp0_; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (type != NULL); +	g_return_if_fail (file != NULL); +	_tmp0_ = g_strcmp0 (type, "jpeg"); +	if (_tmp0_ == 0) { +		book_save_multi_file (self, "jpeg", file, &_inner_error_); +		if (_inner_error_ != NULL) { +			g_propagate_error (error, _inner_error_); +			return; +		} +	} else { +		gint _tmp1_; +		_tmp1_ = g_strcmp0 (type, "png"); +		if (_tmp1_ == 0) { +			book_save_multi_file (self, "png", file, &_inner_error_); +			if (_inner_error_ != NULL) { +				g_propagate_error (error, _inner_error_); +				return; +			} +		} else { +			gint _tmp2_; +			_tmp2_ = g_strcmp0 (type, "tiff"); +			if (_tmp2_ == 0) { +				book_save_multi_file (self, "tiff", file, &_inner_error_); +				if (_inner_error_ != NULL) { +					g_propagate_error (error, _inner_error_); +					return; +				} +			} else { +				gint _tmp3_; +				_tmp3_ = g_strcmp0 (type, "ps"); +				if (_tmp3_ == 0) { +					book_save_ps (self, file, &_inner_error_); +					if (_inner_error_ != NULL) { +						g_propagate_error (error, _inner_error_); +						return; +					} +				} else { +					gint _tmp4_; +					_tmp4_ = g_strcmp0 (type, "pdf"); +					if (_tmp4_ == 0) { +						book_save_pdf (self, file, &_inner_error_); +						if (_inner_error_ != NULL) { +							g_propagate_error (error, _inner_error_); +							return; +						} +					} +				} +			} +		} +	} +} + + +void book_set_needs_saving (Book* self, gboolean needs_saving) { +	gboolean needed_saving; +	g_return_if_fail (self != NULL); +	needed_saving = self->priv->needs_saving; +	self->priv->needs_saving = needs_saving; +	if (needed_saving != needs_saving) { +		g_signal_emit_by_name (self, "needs-saving-changed"); +	} +} + + +gboolean book_get_needs_saving (Book* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->needs_saving; +	return result; +} + + +static void g_cclosure_user_marshal_VOID__PAGE (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { +	typedef void (*GMarshalFunc_VOID__PAGE) (gpointer data1, gpointer arg_1, gpointer data2); +	register GMarshalFunc_VOID__PAGE callback; +	register GCClosure * cc; +	register gpointer data1; +	register gpointer data2; +	cc = (GCClosure *) closure; +	g_return_if_fail (n_param_values == 2); +	if (G_CCLOSURE_SWAP_DATA (closure)) { +		data1 = closure->data; +		data2 = param_values->data[0].v_pointer; +	} else { +		data1 = param_values->data[0].v_pointer; +		data2 = closure->data; +	} +	callback = (GMarshalFunc_VOID__PAGE) (marshal_data ? marshal_data : cc->callback); +	callback (data1, value_get_page (param_values + 1), data2); +} + + +static void value_book_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_book_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		book_unref (value->data[0].v_pointer); +	} +} + + +static void value_book_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = book_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_book_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_book_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Book* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = book_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_book_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Book** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = book_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_book (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecBook* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_BOOK), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_book (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_BOOK), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_book (GValue* value, gpointer v_object) { +	Book* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_BOOK)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_BOOK)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		book_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		book_unref (old); +	} +} -Book * -book_new () -{ -    return g_object_new (BOOK_TYPE, NULL); +void value_take_book (GValue* value, gpointer v_object) { +	Book* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_BOOK)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_BOOK)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		book_unref (old); +	}  } -void -book_clear (Book *book) -{ -    GList *iter; -    for (iter = book->priv->pages; iter; iter = iter->next) { -        Page *page = iter->data; -        g_object_unref (page); -    } -    g_list_free (book->priv->pages); -    book->priv->pages = NULL; -    g_signal_emit (book, signals[CLEARED], 0); +static void book_class_init (BookClass * klass) { +	book_parent_class = g_type_class_peek_parent (klass); +	BOOK_CLASS (klass)->finalize = book_finalize; +	g_type_class_add_private (klass, sizeof (BookPrivate)); +	g_signal_new ("page_added", TYPE_BOOK, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__PAGE, G_TYPE_NONE, 1, TYPE_PAGE); +	g_signal_new ("page_removed", TYPE_BOOK, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__PAGE, G_TYPE_NONE, 1, TYPE_PAGE); +	g_signal_new ("reordered", TYPE_BOOK, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("cleared", TYPE_BOOK, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("needs_saving_changed", TYPE_BOOK, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);  } -static void -page_changed_cb (Page *page, Book *book) -{ -    book_set_needs_saving (book, TRUE); +static void book_instance_init (Book * self) { +	self->priv = BOOK_GET_PRIVATE (self); +	self->ref_count = 1;  } -Page * -book_append_page (Book *book, gint width, gint height, gint dpi, ScanDirection scan_direction) -{ -    Page *page; +static void book_finalize (Book* obj) { +	Book * self; +	self = BOOK (obj); +	__g_list_free__page_unref0_0 (self->priv->pages); +} -    page = page_new (width, height, dpi, scan_direction); -    g_signal_connect (page, "pixels-changed", G_CALLBACK (page_changed_cb), book); -    g_signal_connect (page, "crop-changed", G_CALLBACK (page_changed_cb), book); -    book->priv->pages = g_list_append (book->priv->pages, page); +GType book_get_type (void) { +	static volatile gsize book_type_id__volatile = 0; +	if (g_once_init_enter (&book_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_book_init, value_book_free_value, value_book_copy_value, value_book_peek_pointer, "p", value_book_collect_value, "p", value_book_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (BookClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) book_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Book), 0, (GInstanceInitFunc) book_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType book_type_id; +		book_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Book", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&book_type_id__volatile, book_type_id); +	} +	return book_type_id__volatile; +} -    g_signal_emit (book, signals[PAGE_ADDED], 0, page); -   -    book_set_needs_saving (book, TRUE); -    return page; +gpointer book_ref (gpointer instance) { +	Book* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance;  } -void -book_move_page (Book *book, Page *page, gint location) -{ -    book->priv->pages = g_list_remove (book->priv->pages, page); -    book->priv->pages = g_list_insert (book->priv->pages, page, location); +void book_unref (gpointer instance) { +	Book* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		BOOK_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} -    g_signal_emit (book, signals[REORDERED], 0, page); -    book_set_needs_saving (book, TRUE); +static gpointer _g_object_ref0 (gpointer self) { +	return self ? g_object_ref (self) : NULL;  } -void -book_delete_page (Book *book, Page *page) -{ -    g_signal_handlers_disconnect_by_func (page, page_changed_cb, book); +PDFWriter* pdf_writer_construct (GType object_type, GFileOutputStream* stream) { +	PDFWriter* self = NULL; +	GFileOutputStream* _tmp0_; +	g_return_val_if_fail (stream != NULL, NULL); +	self = (PDFWriter*) g_type_create_instance (object_type); +	_tmp0_ = _g_object_ref0 (stream); +	_g_object_unref0 (self->priv->stream); +	self->priv->stream = _tmp0_; +	return self; +} -    g_signal_emit (book, signals[PAGE_REMOVED], 0, page); -    book->priv->pages = g_list_remove (book->priv->pages, page); -    g_object_unref (page); +PDFWriter* pdf_writer_new (GFileOutputStream* stream) { +	return pdf_writer_construct (TYPE_PDF_WRITER, stream); +} + -    book_set_needs_saving (book, TRUE); +void pdf_writer_write (PDFWriter* self, guint8* data, int data_length1) { +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	{ +		g_output_stream_write_all ((GOutputStream*) self->priv->stream, data, (gsize) data_length1, NULL, NULL, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch0_g_error; +		} +	} +	goto __finally0; +	__catch0_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("book.vala:529: Error writing PDF: %s", e->message); +		_g_error_free0 (e); +	} +	__finally0: +	if (_inner_error_ != NULL) { +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +	self->offset = self->offset + data_length1;  } -gint -book_get_n_pages (Book *book) -{ -    return g_list_length (book->priv->pages);     +static gchar* string_to_utf8 (const gchar* self, int* result_length1) { +	gchar* result = NULL; +	gint _tmp0_; +	gchar* _tmp1_ = NULL; +	gchar* _result_; +	gint _result__length1; +	gint __result__size_; +	gint _tmp2_; +	gchar* _tmp3_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = strlen (self); +	_tmp1_ = g_new0 (gchar, _tmp0_ + 1); +	_result_ = _tmp1_; +	_result__length1 = _tmp0_ + 1; +	__result__size_ = _result__length1; +	_result__length1--; +	_tmp2_ = strlen (self); +	memcpy (_result_, self, (gsize) _tmp2_); +	_tmp3_ = _result_; +	if (result_length1) { +		*result_length1 = _result__length1; +	} +	result = _tmp3_; +	return result;  } -Page * -book_get_page (Book *book, gint page_number) -{ -    if (page_number < 0) -        page_number = g_list_length (book->priv->pages) + page_number; -    return g_list_nth_data (book->priv->pages, page_number); +void pdf_writer_write_string (PDFWriter* self, const gchar* text) { +	gint _tmp0_; +	gchar* _tmp1_ = NULL; +	guint8* _tmp2_; +	gint _tmp2__length1; +	g_return_if_fail (self != NULL); +	g_return_if_fail (text != NULL); +	_tmp1_ = string_to_utf8 (text, &_tmp0_); +	_tmp2_ = (guint8*) _tmp1_; +	_tmp2__length1 = _tmp0_; +	pdf_writer_write (self, _tmp2_, _tmp0_); +	_tmp2_ = (g_free (_tmp2_), NULL);  } -gint -book_get_page_index (Book *book, Page *page) -{ -     return g_list_index (book->priv->pages, page); +guint pdf_writer_start_object (PDFWriter* self) { +	guint result = 0U; +	guint _tmp0_; +	g_return_val_if_fail (self != NULL, 0U); +	self->object_offsets = g_list_append (self->object_offsets, GUINT_TO_POINTER ((guint) self->offset)); +	_tmp0_ = g_list_length (self->object_offsets); +	result = _tmp0_; +	return result;  } -static GFile * -make_indexed_file (const gchar *uri, gint i) -{ -    gchar *basename, *suffix, *indexed_uri; -    GFile *file; +static void value_pdf_writer_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + -    if (i == 0) -        return g_file_new_for_uri (uri); +static void value_pdf_writer_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		pdf_writer_unref (value->data[0].v_pointer); +	} +} -    basename = g_path_get_basename (uri); -    suffix = g_strrstr (basename, "."); -    if (suffix) -        indexed_uri = g_strdup_printf ("%.*s-%d%s", (int) (strlen (uri) - strlen (suffix)), uri, i, suffix); -    else -        indexed_uri = g_strdup_printf ("%s-%d", uri, i); -    g_free (basename); +static void value_pdf_writer_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = pdf_writer_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} -    file = g_file_new_for_uri (indexed_uri); -    g_free (indexed_uri); -    return file; +static gpointer value_pdf_writer_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer;  } -static gboolean -book_save_multi_file (Book *book, const gchar *type, GFile *file, GError **error) -{ -    GList *iter; -    gboolean result = TRUE; -    gint i; -    gchar *uri; +static gchar* value_pdf_writer_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		PDFWriter* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = pdf_writer_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} -    uri = g_file_get_uri (file); -    for (iter = book->priv->pages, i = 0; iter && result; iter = iter->next, i++) { -        Page *page = iter->data; -        GFile *file; -        file = make_indexed_file (uri, i); -        result = page_save (page, type, file, error); -        g_object_unref (file); -    } -    g_free (uri); -    -    return result; +static gchar* value_pdf_writer_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	PDFWriter** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = pdf_writer_ref (value->data[0].v_pointer); +	} +	return NULL;  } -static void -save_ps_pdf_surface (cairo_surface_t *surface, GdkPixbuf *image, gdouble dpi) -{ -    cairo_t *context; -     -    context = cairo_create (surface); +GParamSpec* param_spec_pdf_writer (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecPDFWriter* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_PDF_WRITER), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} -    cairo_scale (context, 72.0 / dpi, 72.0 / dpi); -    gdk_cairo_set_source_pixbuf (context, image, 0, 0); -    cairo_pattern_set_filter (cairo_get_source (context), CAIRO_FILTER_BEST); -    cairo_paint (context); -    cairo_destroy (context); +gpointer value_get_pdf_writer (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PDF_WRITER), NULL); +	return value->data[0].v_pointer;  } -static cairo_status_t -write_cairo_data (GFileOutputStream *stream, unsigned char *data, unsigned int length) -{ -    gboolean result; -    GError *error = NULL; +void value_set_pdf_writer (GValue* value, gpointer v_object) { +	PDFWriter* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PDF_WRITER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PDF_WRITER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		pdf_writer_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		pdf_writer_unref (old); +	} +} -    result = g_output_stream_write_all (G_OUTPUT_STREAM (stream), data, length, NULL, NULL, &error); -     -    if (error) { -        g_warning ("Error writing data: %s", error->message); -        g_error_free (error); -    } -    return result ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR; +void value_take_pdf_writer (GValue* value, gpointer v_object) { +	PDFWriter* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PDF_WRITER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PDF_WRITER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		pdf_writer_unref (old); +	}  } -static gboolean -book_save_ps (Book *book, GFile *file, GError **error) -{ -    GFileOutputStream *stream; -    GList *iter; -    cairo_surface_t *surface; +static void pdf_writer_class_init (PDFWriterClass * klass) { +	pdf_writer_parent_class = g_type_class_peek_parent (klass); +	PDF_WRITER_CLASS (klass)->finalize = pdf_writer_finalize; +	g_type_class_add_private (klass, sizeof (PDFWriterPrivate)); +} -    stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error); -    if (!stream) -        return FALSE; -    surface = cairo_ps_surface_create_for_stream ((cairo_write_func_t) write_cairo_data, -                                                  stream, 0, 0); +static void pdf_writer_instance_init (PDFWriter * self) { +	self->priv = PDF_WRITER_GET_PRIVATE (self); +	self->offset = (gsize) 0; +	self->ref_count = 1; +} -    for (iter = book->priv->pages; iter; iter = iter->next) { -        Page *page = iter->data; -        double width, height; -        GdkPixbuf *image; -        image = page_get_image (page, TRUE); +static void pdf_writer_finalize (PDFWriter* obj) { +	PDFWriter * self; +	self = PDF_WRITER (obj); +	_g_list_free0 (self->object_offsets); +	_g_object_unref0 (self->priv->stream); +} -        width = gdk_pixbuf_get_width (image) * 72.0 / page_get_dpi (page); -        height = gdk_pixbuf_get_height (image) * 72.0 / page_get_dpi (page); -        cairo_ps_surface_set_size (surface, width, height); -        save_ps_pdf_surface (surface, image, page_get_dpi (page)); -        cairo_surface_show_page (surface); -         -        g_object_unref (image); -    } -    cairo_surface_destroy (surface); +GType pdf_writer_get_type (void) { +	static volatile gsize pdf_writer_type_id__volatile = 0; +	if (g_once_init_enter (&pdf_writer_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_pdf_writer_init, value_pdf_writer_free_value, value_pdf_writer_copy_value, value_pdf_writer_peek_pointer, "p", value_pdf_writer_collect_value, "p", value_pdf_writer_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (PDFWriterClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) pdf_writer_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (PDFWriter), 0, (GInstanceInitFunc) pdf_writer_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType pdf_writer_type_id; +		pdf_writer_type_id = g_type_register_fundamental (g_type_fundamental_next (), "PDFWriter", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&pdf_writer_type_id__volatile, pdf_writer_type_id); +	} +	return pdf_writer_type_id__volatile; +} -    g_object_unref (stream); -    return TRUE; +gpointer pdf_writer_ref (gpointer instance) { +	PDFWriter* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance;  } -typedef struct -{ -    int offset; -    int n_objects; -    GList *object_offsets; -    GFileOutputStream *stream; -} PDFWriter; +void pdf_writer_unref (gpointer instance) { +	PDFWriter* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		PDF_WRITER_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} -static PDFWriter * -pdf_writer_new (GFileOutputStream *stream) -{ -    PDFWriter *writer; -    writer = g_malloc0 (sizeof (PDFWriter)); -    writer->stream = g_object_ref (stream); -    return writer; +static cairo_status_t _ps_writer_write_cairo_data_cairo_write_func_t (gpointer self, guchar* data, int data_length1) { +	cairo_status_t result; +	result = ps_writer_write_cairo_data (self, data, data_length1); +	return result;  } -static void -pdf_writer_free (PDFWriter *writer) -{ -    g_object_unref (writer->stream); -    g_list_free (writer->object_offsets); -    g_free (writer); +PsWriter* ps_writer_construct (GType object_type, GFileOutputStream* stream) { +	PsWriter* self = NULL; +	GFileOutputStream* _tmp0_; +	cairo_surface_t* _tmp1_ = NULL; +	g_return_val_if_fail (stream != NULL, NULL); +	self = (PsWriter*) g_type_create_instance (object_type); +	_tmp0_ = _g_object_ref0 (stream); +	_g_object_unref0 (self->stream); +	self->stream = _tmp0_; +	_tmp1_ = cairo_ps_surface_create_for_stream (_ps_writer_write_cairo_data_cairo_write_func_t, self, (gdouble) 0, (gdouble) 0); +	_cairo_surface_destroy0 (self->surface); +	self->surface = _tmp1_; +	return self;  } -static void -pdf_write (PDFWriter *writer, const unsigned char *data, size_t length) -{ -    g_output_stream_write_all (G_OUTPUT_STREAM (writer->stream), data, length, NULL, NULL, NULL); -    writer->offset += length; +PsWriter* ps_writer_new (GFileOutputStream* stream) { +	return ps_writer_construct (TYPE_PS_WRITER, stream);  } -static void -pdf_printf (PDFWriter *writer, const char *format, ...) -{ -    va_list args; -    gchar *string; +static cairo_status_t ps_writer_write_cairo_data (PsWriter* self, guint8* data, int data_length1) { +	cairo_status_t result = 0; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, 0); +	{ +		g_output_stream_write_all ((GOutputStream*) self->stream, data, (gsize) data_length1, NULL, NULL, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch1_g_error; +		} +	} +	goto __finally1; +	__catch1_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("book.vala:565: Error writing data: %s", e->message); +		result = CAIRO_STATUS_WRITE_ERROR; +		_g_error_free0 (e); +		return result; +	} +	__finally1: +	if (_inner_error_ != NULL) { +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return 0; +	} +	result = CAIRO_STATUS_SUCCESS; +	return result; +} -    va_start (args, format); -    string = g_strdup_vprintf (format, args); -    va_end (args); -    pdf_write (writer, (unsigned char *)string, strlen (string)); -    g_free (string); +static void value_ps_writer_init (GValue* value) { +	value->data[0].v_pointer = NULL;  } -static int -pdf_start_object (PDFWriter *writer) -{ -    writer->n_objects++; -    writer->object_offsets = g_list_append (writer->object_offsets, GINT_TO_POINTER (writer->offset)); -    return writer->n_objects; +static void value_ps_writer_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		ps_writer_unref (value->data[0].v_pointer); +	}  } -static guchar * -compress_zlib (guchar *data, size_t length, size_t *n_written) -{ -    z_stream stream; -    guchar *out_data; +static void value_ps_writer_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = ps_writer_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} -    out_data = g_malloc (sizeof (guchar) * length); -    stream.zalloc = Z_NULL; -    stream.zfree = Z_NULL; -    stream.opaque = Z_NULL; -    if (deflateInit (&stream, Z_BEST_COMPRESSION) != Z_OK) -        return NULL; +static gpointer value_ps_writer_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} -    stream.next_in = data; -    stream.avail_in = length; -    stream.next_out = out_data; -    stream.avail_out = length; -    while (stream.avail_in > 0) { -        if (deflate (&stream, Z_FINISH) == Z_STREAM_ERROR) -            break; -    } -    deflateEnd (&stream); +static gchar* value_ps_writer_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		PsWriter* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = ps_writer_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + -    if (stream.avail_in > 0) { -        g_free (out_data); -        return NULL; -    } +static gchar* value_ps_writer_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	PsWriter** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = ps_writer_ref (value->data[0].v_pointer); +	} +	return NULL; +} -    *n_written = length - stream.avail_out; -    return out_data; +GParamSpec* param_spec_ps_writer (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecPsWriter* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_PS_WRITER), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec);  } - - -static void jpeg_init_cb (struct jpeg_compress_struct *info) {} -static boolean jpeg_empty_cb (struct jpeg_compress_struct *info) { return TRUE; } -static void jpeg_term_cb (struct jpeg_compress_struct *info) {} - -static guchar * -compress_jpeg (GdkPixbuf *image, size_t *n_written) -{ -    struct jpeg_compress_struct info; -    struct jpeg_error_mgr jerr; -    struct jpeg_destination_mgr dest_mgr; -    int r; -    guchar *pixels; -    guchar *data; -    size_t max_length; - -    info.err = jpeg_std_error (&jerr); -    jpeg_create_compress (&info); - -    pixels = gdk_pixbuf_get_pixels (image); -    info.image_width = gdk_pixbuf_get_width (image); -    info.image_height = gdk_pixbuf_get_height (image); -    info.input_components = 3; -    info.in_color_space = JCS_RGB; /* TODO: JCS_GRAYSCALE? */ -    jpeg_set_defaults (&info); - -    max_length = info.image_width * info.image_height * info.input_components; -    data = g_malloc (sizeof (guchar) * max_length); -    dest_mgr.next_output_byte = data; -    dest_mgr.free_in_buffer = max_length; -    dest_mgr.init_destination = jpeg_init_cb; -    dest_mgr.empty_output_buffer = jpeg_empty_cb; -    dest_mgr.term_destination = jpeg_term_cb; -    info.dest = &dest_mgr; - -    jpeg_start_compress (&info, TRUE); -    for (r = 0; r < info.image_height; r++) { -        JSAMPROW row[1]; -        row[0] = pixels + r * gdk_pixbuf_get_rowstride (image); -        jpeg_write_scanlines (&info, row, 1); -    } -    jpeg_finish_compress (&info); -    *n_written = max_length - dest_mgr.free_in_buffer; - -    jpeg_destroy_compress (&info); - -    return data; -} - - -static gboolean -book_save_pdf (Book *book, GFile *file, GError **error) -{ -    GFileOutputStream *stream; -    PDFWriter *writer; -    int catalog_number, pages_number, info_number; -    int xref_offset; -    int i; - -    stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error); -    if (!stream) -        return FALSE; - -    writer = pdf_writer_new (stream); -    g_object_unref (stream); - -    /* Header */ -    pdf_printf (writer, "%%PDF-1.3\n"); - -    /* Comment with binary as recommended so file is treated as binary */ -    pdf_printf (writer, "%%\xe2\xe3\xcf\xd3\n"); -   -    /* Catalog */ -    catalog_number = pdf_start_object (writer); -    pdf_printf (writer, "%d 0 obj\n", catalog_number); -    pdf_printf (writer, "<<\n"); -    pdf_printf (writer, "/Type /Catalog\n"); -    //FIXMEpdf_printf (writer, "/Metadata %d 0 R\n", catalog_number + 1);   -    pdf_printf (writer, "/Pages %d 0 R\n", catalog_number + 1); //+2 -    pdf_printf (writer, ">>\n"); -    pdf_printf (writer, "endobj\n"); - -    /* Metadata */ -    /* FIXME pdf_printf (writer, "\n"); -    number = pdf_start_object (writer); -    pdf_printf (writer, "%d 0 obj\n", number); -    pdf_printf (writer, "<<\n"); -    pdf_printf (writer, "/Type /Metadata\n"); -    pdf_printf (writer, "/Subtype /XML\n"); -    pdf_printf (writer, "/Length %d\n", ...); -    pdf_printf (writer, ">>\n"); -    pdf_printf (writer, "stream\n"); -    // ... -    pdf_printf (writer, "\n"); -    pdf_printf (writer, "endstream\n"); -    pdf_printf (writer, "endobj\n");*/ - -    /* Pages */ -    pdf_printf (writer, "\n"); -    pages_number = pdf_start_object (writer); -    pdf_printf (writer, "%d 0 obj\n", pages_number); -    pdf_printf (writer, "<<\n"); -    pdf_printf (writer, "/Type /Pages\n"); -    pdf_printf (writer, "/Kids ["); -    for (i = 0; i < book_get_n_pages (book); i++) { -        pdf_printf (writer, " %d 0 R", pages_number + 1 + (i*3)); -    } -    pdf_printf (writer, " ]\n"); -    pdf_printf (writer, "/Count %d\n", book_get_n_pages (book)); -    pdf_printf (writer, ">>\n"); -    pdf_printf (writer, "endobj\n"); - -    for (i = 0; i < book_get_n_pages (book); i++) { -        int number, width, height, depth; -        size_t data_length, compressed_length; -        Page *page; -        GdkPixbuf *image; -        guchar *pixels, *data, *compressed_data; -        gchar *command, width_buffer[G_ASCII_DTOSTR_BUF_SIZE], height_buffer[G_ASCII_DTOSTR_BUF_SIZE]; -        const gchar *color_space, *filter = NULL; -        float page_width, page_height; - -        page = book_get_page (book, i); -        image = page_get_image (page, TRUE); -        width = gdk_pixbuf_get_width (image); -        height = gdk_pixbuf_get_height (image); -        pixels = gdk_pixbuf_get_pixels (image); -        page_width = width * 72. / page_get_dpi (page); -        page_height = height * 72. / page_get_dpi (page); - -        if (page_is_color (page)) { -            int row; - -            depth = 8; -            color_space = "DeviceRGB"; -            data_length = height * width * 3 + 1; -            data = g_malloc (sizeof (guchar) * data_length); -            for (row = 0; row < height; row++) { -                int x; -                guchar *in_line, *out_line; - -                in_line = pixels + row * gdk_pixbuf_get_rowstride (image); -                out_line = data + row * width * 3; -                for (x = 0; x < width; x++) { -                    guchar *in_p = in_line + x*3; -                    guchar *out_p = out_line + x*3; - -                    out_p[0] = in_p[0]; -                    out_p[1] = in_p[1]; -                    out_p[2] = in_p[2]; -                } -            } -        } -        else if (page_get_depth (page) == 2) { -            int row, shift_count = 6; -            guchar *write_ptr; - -            depth = 2; -            color_space = "DeviceGray"; -            data_length = height * ((width * 2 + 7) / 8); -            data = g_malloc (sizeof (guchar) * data_length); -            write_ptr = data; -            write_ptr[0] = 0; -            for (row = 0; row < height; row++) { -                int x; -                guchar *in_line; - -                /* Pad to the next line */ -                if (shift_count != 6) { -                    write_ptr++; -                    write_ptr[0] = 0;                    -                    shift_count = 6; -                } - -                in_line = pixels + row * gdk_pixbuf_get_rowstride (image); -                for (x = 0; x < width; x++) { -                    guchar *in_p = in_line + x*3; -                    if (in_p[0] >= 192) -                        write_ptr[0] |= 3 << shift_count; -                    else if (in_p[0] >= 128) -                        write_ptr[0] |= 2 << shift_count; -                    else if (in_p[0] >= 64) -                        write_ptr[0] |= 1 << shift_count; -                    if (shift_count == 0) { -                        write_ptr++; -                        write_ptr[0] = 0; -                        shift_count = 6; -                    } -                    else -                        shift_count -= 2; -                } -            } -        } -        else if (page_get_depth (page) == 1) { -            int row, mask = 0x80; -            guchar *write_ptr; - -            depth = 1; -            color_space = "DeviceGray"; -            data_length = height * ((width + 7) / 8); -            data = g_malloc (sizeof (guchar) * data_length); -            write_ptr = data; -            write_ptr[0] = 0; -            for (row = 0; row < height; row++) { -                int x; -                guchar *in_line; - -                /* Pad to the next line */ -                if (mask != 0x80) { -                    write_ptr++; -                    write_ptr[0] = 0; -                    mask = 0x80; -                } - -                in_line = pixels + row * gdk_pixbuf_get_rowstride (image); -                for (x = 0; x < width; x++) { -                    guchar *in_p = in_line + x*3; -                    if (in_p[0] != 0) -                        write_ptr[0] |= mask; -                    mask >>= 1; -                    if (mask == 0) { -                        write_ptr++; -                        write_ptr[0] = 0; -                        mask = 0x80; -                    } -                } -            } -        } -        else { -            int row; - -            depth = 8; -            color_space = "DeviceGray"; -            data_length = height * width + 1; -            data = g_malloc (sizeof (guchar) * data_length); -            for (row = 0; row < height; row++) { -                int x; -                guchar *in_line, *out_line; - -                in_line = pixels + row * gdk_pixbuf_get_rowstride (image); -                out_line = data + row * width; -                for (x = 0; x < width; x++) { -                    guchar *in_p = in_line + x*3; -                    guchar *out_p = out_line + x; - -                    out_p[0] = in_p[0]; -                } -            } -        } - -        /* Compress data */ -        compressed_data = compress_zlib (data, data_length, &compressed_length); -        if (compressed_data) { -            /* Try if JPEG compression is better */ -            if (depth > 1) { -                guchar *jpeg_data; -                size_t jpeg_length; - -                jpeg_data = compress_jpeg (image, &jpeg_length); -                if (jpeg_length < compressed_length) { -                    filter = "DCTDecode"; -                    g_free (data); -                    g_free (compressed_data); -                    data = jpeg_data; -                    data_length = jpeg_length; -                } -            } - -            if (!filter) { -                filter = "FlateDecode"; -                g_free (data); -                data = compressed_data; -                data_length = compressed_length; -            } -        } - -        /* Page */ -        pdf_printf (writer, "\n"); -        number = pdf_start_object (writer); -        pdf_printf (writer, "%d 0 obj\n", number); -        pdf_printf (writer, "<<\n"); -        pdf_printf (writer, "/Type /Page\n"); -        pdf_printf (writer, "/Parent %d 0 R\n", pages_number); -        pdf_printf (writer, "/Resources << /XObject << /Im%d %d 0 R >> >>\n", i, number+1); -        pdf_printf (writer, "/MediaBox [ 0 0 %s %s ]\n", -                    g_ascii_formatd (width_buffer, sizeof (width_buffer), "%.2f", page_width), -                    g_ascii_formatd (height_buffer, sizeof (height_buffer), "%.2f", page_height)); -        pdf_printf (writer, "/Contents %d 0 R\n", number+2); -        pdf_printf (writer, ">>\n"); -        pdf_printf (writer, "endobj\n"); - -        /* Page image */ -        pdf_printf (writer, "\n"); -        number = pdf_start_object (writer); -        pdf_printf (writer, "%d 0 obj\n", number); -        pdf_printf (writer, "<<\n"); -        pdf_printf (writer, "/Type /XObject\n"); -        pdf_printf (writer, "/Subtype /Image\n"); -        pdf_printf (writer, "/Width %d\n", width); -        pdf_printf (writer, "/Height %d\n", height); -        pdf_printf (writer, "/ColorSpace /%s\n", color_space); -        pdf_printf (writer, "/BitsPerComponent %d\n", depth); -        pdf_printf (writer, "/Length %d\n", data_length); -        if (filter) -          pdf_printf (writer, "/Filter /%s\n", filter); -        pdf_printf (writer, ">>\n"); -        pdf_printf (writer, "stream\n"); -        pdf_write (writer, data, data_length); -        g_free (data); -        pdf_printf (writer, "\n"); -        pdf_printf (writer, "endstream\n"); -        pdf_printf (writer, "endobj\n");       - -        /* Page contents */ -        command = g_strdup_printf ("q\n" -                                   "%s 0 0 %s 0 0 cm\n" -                                   "/Im%d Do\n" -                                   "Q", -                                   g_ascii_formatd (width_buffer, sizeof (width_buffer), "%f", page_width), -                                   g_ascii_formatd (height_buffer, sizeof (height_buffer), "%f", page_height), -                                   i); -        pdf_printf (writer, "\n"); -        number = pdf_start_object (writer); -        pdf_printf (writer, "%d 0 obj\n", number); -        pdf_printf (writer, "<<\n"); -        pdf_printf (writer, "/Length %d\n", strlen (command) + 1); -        pdf_printf (writer, ">>\n"); -        pdf_printf (writer, "stream\n"); -        pdf_write (writer, (unsigned char *)command, strlen (command)); -        pdf_printf (writer, "\n"); -        pdf_printf (writer, "endstream\n"); -        pdf_printf (writer, "endobj\n"); -        g_free (command); -                   -        g_object_unref (image); -    } -   -    /* Info */ -    pdf_printf (writer, "\n"); -    info_number = pdf_start_object (writer); -    pdf_printf (writer, "%d 0 obj\n", info_number); -    pdf_printf (writer, "<<\n"); -    pdf_printf (writer, "/Creator (Simple Scan " VERSION ")\n"); -    pdf_printf (writer, ">>\n"); -    pdf_printf (writer, "endobj\n"); - -    /* Cross-reference table */ -    xref_offset = writer->offset; -    pdf_printf (writer, "xref\n"); -    pdf_printf (writer, "1 %d\n", writer->n_objects); -    GList *link; -    for (link = writer->object_offsets; link != NULL; link = link->next) { -        int offset = GPOINTER_TO_INT (link->data); -        pdf_printf (writer, "%010d 0000 n\n", offset); -    } - -    /* Trailer */ -    pdf_printf (writer, "trailer\n"); -    pdf_printf (writer, "<<\n"); -    pdf_printf (writer, "/Size %d\n", writer->n_objects); -    pdf_printf (writer, "/Info %d 0 R\n", info_number); -    pdf_printf (writer, "/Root %d 0 R\n", catalog_number); -    //FIXME: pdf_printf (writer, "/ID [<...> <...>]\n"); -    pdf_printf (writer, ">>\n"); -    pdf_printf (writer, "startxref\n"); -    pdf_printf (writer, "%d\n", xref_offset); -    pdf_printf (writer, "%%%%EOF\n"); -   -    pdf_writer_free (writer); - -    return TRUE; -} - - -gboolean -book_save (Book *book, const gchar *type, GFile *file, GError **error) -{ -    gboolean result = FALSE; - -    if (strcmp (type, "jpeg") == 0) -        result = book_save_multi_file (book, "jpeg", file, error); -    else if (strcmp (type, "png") == 0) -        result = book_save_multi_file (book, "png", file, error); -    else if (strcmp (type, "tiff") == 0) -        result = book_save_multi_file (book, "tiff", file, error);     -    else if (strcmp (type, "ps") == 0) -        result = book_save_ps (book, file, error);     -    else if (strcmp (type, "pdf") == 0) -        result = book_save_pdf (book, file, error); - -    return result; -} - - -void -book_set_needs_saving (Book *book, gboolean needs_saving) -{ -    gboolean needed_saving = book->priv->needs_saving; -    book->priv->needs_saving = needs_saving; -    if (needed_saving != needs_saving) -        g_object_notify (G_OBJECT (book), "needs-saving"); -} - - -gboolean -book_get_needs_saving (Book *book) -{ -    return book->priv->needs_saving; -} - - -static void -book_set_property (GObject      *object, -                   guint         prop_id, -                   const GValue *value, -                   GParamSpec   *pspec) -{ -    Book *self; - -    self = BOOK (object); - -    switch (prop_id) { -    case PROP_NEEDS_SAVING: -        book_set_needs_saving (self, g_value_get_boolean (value)); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } -} - - -static void -book_get_property (GObject    *object, -                   guint       prop_id, -                   GValue     *value, -                   GParamSpec *pspec) -{ -    Book *self; - -    self = BOOK (object); - -    switch (prop_id) { -    case PROP_NEEDS_SAVING: -        g_value_set_boolean (value, book_get_needs_saving (self)); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } -} - - -static void -book_finalize (GObject *object) -{ -    Book *book = BOOK (object); -    book_clear (book); -    G_OBJECT_CLASS (book_parent_class)->finalize (object); -} - - -static void -book_class_init (BookClass *klass) -{ -    GObjectClass *object_class = G_OBJECT_CLASS (klass); - -    object_class->get_property = book_get_property; -    object_class->set_property = book_set_property; -    object_class->finalize = book_finalize; - -    g_object_class_install_property (object_class, -                                     PROP_NEEDS_SAVING, -                                     g_param_spec_boolean ("needs-saving", -                                                           "needs-saving", -                                                           "TRUE if this book needs saving", -                                                           FALSE, -                                                           G_PARAM_READWRITE)); - -    signals[PAGE_ADDED] = -        g_signal_new ("page-added", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookClass, page_added), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__OBJECT, -                      G_TYPE_NONE, 1, page_get_type ()); -    signals[PAGE_REMOVED] = -        g_signal_new ("page-removed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookClass, page_removed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__OBJECT, -                      G_TYPE_NONE, 1, page_get_type ()); -    signals[REORDERED] = -        g_signal_new ("reordered", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookClass, reordered), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[CLEARED] = -        g_signal_new ("cleared", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (BookClass, cleared), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); - -    g_type_class_add_private (klass, sizeof (BookPrivate)); -} - - -static void -book_init (Book *book) -{ -    book->priv = G_TYPE_INSTANCE_GET_PRIVATE (book, BOOK_TYPE, BookPrivate); + + +gpointer value_get_ps_writer (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PS_WRITER), NULL); +	return value->data[0].v_pointer;  } + + +void value_set_ps_writer (GValue* value, gpointer v_object) { +	PsWriter* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PS_WRITER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PS_WRITER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		ps_writer_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		ps_writer_unref (old); +	} +} + + +void value_take_ps_writer (GValue* value, gpointer v_object) { +	PsWriter* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PS_WRITER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PS_WRITER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		ps_writer_unref (old); +	} +} + + +static void ps_writer_class_init (PsWriterClass * klass) { +	ps_writer_parent_class = g_type_class_peek_parent (klass); +	PS_WRITER_CLASS (klass)->finalize = ps_writer_finalize; +} + + +static void ps_writer_instance_init (PsWriter * self) { +	self->ref_count = 1; +} + + +static void ps_writer_finalize (PsWriter* obj) { +	PsWriter * self; +	self = PS_WRITER (obj); +	_cairo_surface_destroy0 (self->surface); +	_g_object_unref0 (self->stream); +} + + +GType ps_writer_get_type (void) { +	static volatile gsize ps_writer_type_id__volatile = 0; +	if (g_once_init_enter (&ps_writer_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_ps_writer_init, value_ps_writer_free_value, value_ps_writer_copy_value, value_ps_writer_peek_pointer, "p", value_ps_writer_collect_value, "p", value_ps_writer_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (PsWriterClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) ps_writer_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (PsWriter), 0, (GInstanceInitFunc) ps_writer_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType ps_writer_type_id; +		ps_writer_type_id = g_type_register_fundamental (g_type_fundamental_next (), "PsWriter", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&ps_writer_type_id__volatile, ps_writer_type_id); +	} +	return ps_writer_type_id__volatile; +} + + +gpointer ps_writer_ref (gpointer instance) { +	PsWriter* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void ps_writer_unref (gpointer instance) { +	PsWriter* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		PS_WRITER_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + + diff --git a/src/book.h b/src/book.h deleted file mode 100644 index cf82978..0000000 --- a/src/book.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2009 Canonical Ltd. - * Author: Robert Ancell <robert.ancell@canonical.com> - *  - * This program 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 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _BOOK_H_ -#define _BOOK_H_ - -#include <glib-object.h> -#include <gio/gio.h> -#include <cairo.h> -#include "page.h" - -G_BEGIN_DECLS - -#define BOOK_TYPE  (book_get_type ()) -#define BOOK(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), BOOK_TYPE, Book)) - - -typedef struct BookPrivate BookPrivate; - -typedef struct -{ -    GObject      parent_instance; -    BookPrivate *priv; -} Book; - -typedef struct -{ -    GObjectClass parent_class; - -    void (*page_added) (Book *book, Page *page); -    void (*page_removed) (Book *book, Page *page); -    void (*reordered) (Book *book); -    void (*cleared) (Book *book); -} BookClass; - - -GType book_get_type (void); - -Book *book_new (void); - -void book_clear (Book *book); - -Page *book_append_page (Book *book, gint width, gint height, gint dpi, ScanDirection orientation); - -void book_move_page (Book *book, Page *page, gint location); - -void book_delete_page (Book *book, Page *page); - -gint book_get_n_pages (Book *book); - -Page *book_get_page (Book *book, gint page_number); - -gint book_get_page_index (Book *book, Page *page); - -gboolean book_save (Book *book, const gchar *type, GFile *file, GError **error); - -void book_set_needs_saving (Book *book, gboolean needs_saving); - -gboolean book_get_needs_saving (Book *book); - -#endif /* _BOOK_H_ */ diff --git a/src/book.vala b/src/book.vala new file mode 100644 index 0000000..1aed281 --- /dev/null +++ b/src/book.vala @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +public class Book +{ +    private List<Page> pages; + +    private bool needs_saving; +     +    public signal void page_added (Page page); +    public signal void page_removed (Page page); +    public signal void reordered (); +    public signal void cleared (); +    public signal void needs_saving_changed (); + +    public Book () +    { +    } + +    public void clear () +    { +        pages = null; +        cleared (); +    } + +    private void page_changed_cb (Page page) +    { +        set_needs_saving (true); +    } + +    public Page append_page (int width, int height, int dpi, ScanDirection scan_direction) +    { +        var page = new Page (width, height, dpi, scan_direction); +        page.pixels_changed.connect (page_changed_cb); +        page.crop_changed.connect (page_changed_cb); + +        pages.append (page); +        page_added (page); +        set_needs_saving (true); + +        return page; +    } + +    public void move_page (Page page, uint location) +    { +        pages.remove (page); +        pages.insert (page, (int) location); +        reordered (); +        set_needs_saving (true); +    } + +    public void delete_page (Page page) +    { +        page.pixels_changed.disconnect (page_changed_cb); +        page.crop_changed.disconnect (page_changed_cb); +        page_removed (page); +        pages.remove (page); +        set_needs_saving (true); +    } + +    public uint get_n_pages () +    { +        return pages.length (); +    } + +    public Page get_page (int page_number) +    { +        if (page_number < 0) +            page_number = (int) pages.length () + page_number; +        return pages.nth_data (page_number); +    } + +    public uint get_page_index (Page page) +    { +        return pages.index (page); +    } + +    private File make_indexed_file (string uri, int i) +    { +        if (i == 0) +            return File.new_for_uri (uri); + +        /* Insert index before extension */ +        var basename = Path.get_basename (uri); +        string prefix = uri, suffix = ""; +        var extension_index = basename.last_index_of_char ('.'); +        if (extension_index >= 0) +        {           +            suffix = basename.slice (extension_index, basename.length); +            prefix = uri.slice (0, uri.length - suffix.length); +        } + +        return File.new_for_uri ("%s-%d%s".printf (prefix, i, suffix)); +    } + +    private void save_multi_file (string type, File file) throws Error +    { +        int i = 0; +        foreach (var page in pages) +        { +            page.save (type, make_indexed_file (file.get_uri (), i)); +            i++; +        } +    } + +    private void save_ps_pdf_surface (Cairo.Surface surface, Gdk.Pixbuf image, double dpi) +    { +        var context = new Cairo.Context (surface); +        context.scale (72.0 / dpi, 72.0 / dpi); +        Gdk.cairo_set_source_pixbuf (context, image, 0, 0); +        context.get_source ().set_filter (Cairo.Filter.BEST); +        context.paint (); +    } + +    private void save_ps (File file) throws Error +    { +        var stream = file.replace (null, false, FileCreateFlags.NONE, null); +        var writer = new PsWriter (stream); +        var surface = writer.surface; + +        foreach (var page in pages) +        { +            var image = page.get_image (true); +            var width = image.get_width () * 72.0 / page.get_dpi (); +            var height = image.get_height () * 72.0 / page.get_dpi (); +            surface.set_size (width, height); +            save_ps_pdf_surface (surface, image, page.get_dpi ()); +            surface.show_page (); +        } +    } + +    private uint8[]? compress_zlib (uint8[] data) +    { +        var stream = ZLib.DeflateStream (ZLib.Level.BEST_COMPRESSION); +        var out_data = new uint8[data.length]; + +        stream.next_in = data; +        stream.next_out = out_data; +        while (stream.avail_in > 0) +        { +            if (stream.deflate (ZLib.Flush.FINISH) == ZLib.Status.STREAM_ERROR) +                break; +        } + +        if (stream.avail_in > 0) +            return null; + +        var n_written = data.length - stream.avail_out; +        out_data.resize ((int) n_written); + +        return out_data; +    } + +    private static void jpeg_init_cb (JPEG.Compress info) {} +    private static bool jpeg_empty_cb (JPEG.Compress info) { return true; } +    private static void jpeg_term_cb (JPEG.Compress info) {} + +    private uint8[] compress_jpeg (Gdk.Pixbuf image, out size_t n_written) +    { +        var info = JPEG.Compress (); +        var jerr = JPEG.ErrorManager (); +        var dest_mgr = JPEG.DestinationManager (); + +        info.err = jerr.std_error (); +        info.create_compress (); + +        info.image_width = image.get_width (); +        info.image_height = image.get_height (); +        info.input_components = 3; +        info.in_color_space = JPEG.ColorSpace.RGB; /* TODO: JCS_GRAYSCALE? */ +        info.set_defaults (); + +        var max_length = info.image_width * info.image_height * info.input_components; +        var data = new uint8[max_length]; +        dest_mgr.next_output_byte = data; +        dest_mgr.free_in_buffer = max_length; +        dest_mgr.init_destination = jpeg_init_cb; +        dest_mgr.empty_output_buffer = jpeg_empty_cb; +        dest_mgr.term_destination = jpeg_term_cb; +        info.dest = &dest_mgr; + +        info.start_compress (true); +        unowned uint8[] pixels = image.get_pixels (); +        for (var r = 0; r < info.image_height; r++) +        { +            uint8* row[1]; +            row[0] = (uint8*) pixels + r * image.get_rowstride (); +            info.write_scanlines (row, 1); +        } +        info.finish_compress (); +        n_written = max_length - dest_mgr.free_in_buffer; + +        return data; +    } + +    private void save_pdf (File file) throws Error +    { +        var stream = file.replace (null, false, FileCreateFlags.NONE, null); +        var writer = new PDFWriter (stream); + +        /* Header */ +        writer.write_string ("%%PDF-1.3\n"); + +        /* Comment with binary as recommended so file is treated as binary */ +        writer.write_string ("%%\xe2\xe3\xcf\xd3\n"); + +        /* Catalog */ +        var catalog_number = writer.start_object (); +        writer.write_string ("%u 0 obj\n".printf (catalog_number)); +        writer.write_string ("<<\n"); +        writer.write_string ("/Type /Catalog\n"); +        //FIXMEwriter.write_string ("/Metadata %u 0 R\n".printf (catalog_number + 1)); +        writer.write_string ("/Pages %u 0 R\n".printf (catalog_number + 1)); //+2 +        writer.write_string (">>\n"); +        writer.write_string ("endobj\n"); + +        /* Metadata */ +        /* FIXME writer.write_string ("\n"); +        number = writer.start_object (); +        writer.write_string ("%u 0 obj\n".printf (number)); +        writer.write_string ("<<\n"); +        writer.write_string ("/Type /Metadata\n"); +        writer.write_string ("/Subtype /XML\n"); +        writer.write_string ("/Length %u\n".printf (...)); +        writer.write_string (">>\n"); +        writer.write_string ("stream\n"); +        // ... +        writer.write_string ("\n"); +        writer.write_string ("endstream\n"); +        writer.write_string ("endobj\n");*/ + +        /* Pages */ +        writer.write_string ("\n"); +        var pages_number = writer.start_object (); +        writer.write_string ("%u 0 obj\n".printf (pages_number)); +        writer.write_string ("<<\n"); +        writer.write_string ("/Type /Pages\n"); +        writer.write_string ("/Kids ["); +        for (var i = 0; i < get_n_pages (); i++) +            writer.write_string (" %u 0 R".printf (pages_number + 1 + (i*3))); +        writer.write_string (" ]\n"); +        writer.write_string ("/Count %u\n".printf (get_n_pages ())); +        writer.write_string (">>\n"); +        writer.write_string ("endobj\n"); + +        for (var i = 0; i < get_n_pages (); i++) +        { +            var page = get_page (i); +            var image = page.get_image (true); +            var width = image.get_width (); +            var height = image.get_height (); +            unowned uint8[] pixels = image.get_pixels (); +            var page_width = width * 72.0 / page.get_dpi (); +            var page_height = height * 72.0 / page.get_dpi (); + +            int depth = 8; +            string color_space = "DeviceRGB"; +            string? filter = null; +            char[] width_buffer = new char[double.DTOSTR_BUF_SIZE]; +            char[] height_buffer = new char[double.DTOSTR_BUF_SIZE]; +            uint8[] data; +            if (page.is_color ()) +            { +                depth = 8; +                color_space = "DeviceRGB"; +                var data_length = height * width * 3 + 1; +                data = new uint8[data_length]; +                for (var row = 0; row < height; row++) +                { +                    var in_offset = row * image.get_rowstride (); +                    var out_offset = row * width * 3; +                    for (var x = 0; x < width; x++) +                    { +                        var in_o = in_offset + x*3; +                        var out_o = out_offset + x*3; + +                        data[out_o] = pixels[in_o]; +                        data[out_o+1] = pixels[in_o+1]; +                        data[out_o+2] = pixels[in_o+2]; +                    } +                } +            } +            else if (page.get_depth () == 2) +            { +                int shift_count = 6; +                depth = 2; +                color_space = "DeviceGray"; +                var data_length = height * ((width * 2 + 7) / 8); +                data = new uint8[data_length]; +                var offset = 0; +                data[offset] = 0; +                for (var row = 0; row < height; row++) +                { +                    /* Pad to the next line */ +                    if (shift_count != 6) +                    { +                        offset++; +                        data[offset] = 0; +                        shift_count = 6; +                    } + +                    var in_offset = row * image.get_rowstride (); +                    for (var x = 0; x < width; x++) +                    { +                        var p = pixels[in_offset + x*3]; +                        if (p >= 192) +                            data[offset] |= 3 << shift_count; +                        else if (p >= 128) +                            data[offset] |= 2 << shift_count; +                        else if (p >= 64) +                            data[offset] |= 1 << shift_count; +                        if (shift_count == 0) +                        { +                            offset++; +                            data[offset] = 0; +                            shift_count = 6; +                        } +                        else +                            shift_count -= 2; +                    } +                } +            } +            else if (page.get_depth () == 1) +            { +                int mask = 0x80; + +                depth = 1; +                color_space = "DeviceGray"; +                var data_length = height * ((width + 7) / 8); +                data = new uint8[data_length]; +                var offset = 0; +                data[offset] = 0; +                for (var row = 0; row < height; row++) +                { +                    /* Pad to the next line */ +                    if (mask != 0x80) +                    { +                        offset++; +                        data[offset] = 0; +                        mask = 0x80; +                    } + +                    var in_offset = row * image.get_rowstride (); +                    for (var x = 0; x < width; x++) +                    { +                        if (pixels[in_offset+x*3] != 0) +                            data[offset] |= (uint8) mask; +                        mask >>= 1; +                        if (mask == 0) +                        { +                            offset++; +                            data[offset] = 0; +                            mask = 0x80; +                        } +                    } +                } +            } +            else +            { +                depth = 8; +                color_space = "DeviceGray"; +                var data_length = height * width + 1; +                data = new uint8 [data_length]; +                for (var row = 0; row < height; row++) +                { +                    var in_offset = row * image.get_rowstride (); +                    var out_offset = row * width; +                    for (var x = 0; x < width; x++) +                        data[out_offset+x] = pixels[in_offset+x*3]; +                } +            } + +            /* Compress data */ +            var compressed_data = compress_zlib (data); +            if (compressed_data != null) +            { +                /* Try if JPEG compression is better */ +                if (depth > 1) +                { +                    size_t jpeg_length; +                    var jpeg_data = compress_jpeg (image, out jpeg_length); +                    if (jpeg_length < compressed_data.length) +                    { +                        filter = "DCTDecode"; +                        data = jpeg_data; +                    } +                } + +                if (filter == null) +                { +                    filter = "FlateDecode"; +                    data = compressed_data; +                } +            } + +            /* Page */ +            writer.write_string ("\n"); +            var number = writer.start_object (); +            writer.write_string ("%u 0 obj\n".printf (number)); +            writer.write_string ("<<\n"); +            writer.write_string ("/Type /Page\n"); +            writer.write_string ("/Parent %u 0 R\n".printf (pages_number)); +            writer.write_string ("/Resources << /XObject << /Im%d %u 0 R >> >>\n".printf (i, number+1)); +            writer.write_string ("/MediaBox [ 0 0 %s %s ]\n".printf (page_width.format (width_buffer, "%.2f"), page_height.format (height_buffer, "%.2f"))); +            writer.write_string ("/Contents %u 0 R\n".printf (number+2)); +            writer.write_string (">>\n"); +            writer.write_string ("endobj\n"); + +            /* Page image */ +            writer.write_string ("\n"); +            number = writer.start_object (); +            writer.write_string ("%u 0 obj\n".printf (number)); +            writer.write_string ("<<\n"); +            writer.write_string ("/Type /XObject\n"); +            writer.write_string ("/Subtype /Image\n"); +            writer.write_string ("/Width %d\n".printf (width)); +            writer.write_string ("/Height %d\n".printf (height)); +            writer.write_string ("/ColorSpace /%s\n".printf (color_space)); +            writer.write_string ("/BitsPerComponent %d\n".printf (depth)); +            writer.write_string ("/Length %d\n".printf (data.length)); +            if (filter != null) +                writer.write_string ("/Filter /%s\n".printf (filter)); +            writer.write_string (">>\n"); +            writer.write_string ("stream\n"); +            writer.write (data); +            writer.write_string ("\n"); +            writer.write_string ("endstream\n"); +            writer.write_string ("endobj\n"); + +            /* Page contents */ +            var command = "q\n%s 0 0 %s 0 0 cm\n/Im%d Do\nQ".printf (page_width.format (width_buffer, "%f"), page_height.format (height_buffer, "%f"), i); +            writer.write_string ("\n"); +            number = writer.start_object (); +            writer.write_string ("%u 0 obj\n".printf (number)); +            writer.write_string ("<<\n"); +            writer.write_string ("/Length %d\n".printf (command.length + 1)); +            writer.write_string (">>\n"); +            writer.write_string ("stream\n"); +            writer.write_string (command); +            writer.write_string ("\n"); +            writer.write_string ("endstream\n"); +            writer.write_string ("endobj\n"); +        } + +        /* Info */ +        writer.write_string ("\n"); +        var info_number = writer.start_object (); +        writer.write_string ("%u 0 obj\n".printf (info_number)); +        writer.write_string ("<<\n"); +        writer.write_string ("/Creator (Simple Scan %s)\n".printf (Config.VERSION)); +        writer.write_string (">>\n"); +        writer.write_string ("endobj\n"); + +        /* Cross-reference table */ +        var xref_offset = writer.offset; +        writer.write_string ("xref\n"); +        writer.write_string ("1 %zu\n".printf (writer.object_offsets.length ())); +        foreach (var offset in writer.object_offsets) +            writer.write_string ("%010zu 0000 n\n".printf (offset)); + +        /* Trailer */ +        writer.write_string ("trailer\n"); +        writer.write_string ("<<\n"); +        writer.write_string ("/Size %zu\n".printf (writer.object_offsets.length ())); +        writer.write_string ("/Info %u 0 R\n".printf (info_number)); +        writer.write_string ("/Root %u 0 R\n".printf (catalog_number)); +        //FIXME: writer.write_string ("/ID [<...> <...>]\n"); +        writer.write_string (">>\n"); +        writer.write_string ("startxref\n"); +        writer.write_string ("%zu\n".printf (xref_offset)); +        writer.write_string ("%%%%EOF\n"); +    } + +    public void save (string type, File file) throws Error +    { +        if (strcmp (type, "jpeg") == 0) +            save_multi_file ("jpeg", file); +        else if (strcmp (type, "png") == 0) +            save_multi_file ("png", file); +        else if (strcmp (type, "tiff") == 0) +            save_multi_file ("tiff", file); +        else if (strcmp (type, "ps") == 0) +            save_ps (file); +        else if (strcmp (type, "pdf") == 0) +            save_pdf (file); +    } + +    public void set_needs_saving (bool needs_saving) +    { +        var needed_saving = this.needs_saving; +        this.needs_saving = needs_saving; +        if (needed_saving != needs_saving) +            needs_saving_changed (); +    } + +    public bool get_needs_saving () +    { +        return needs_saving; +    } +} + +private class PDFWriter +{ +    public size_t offset = 0; +    public List<uint> object_offsets; +    private FileOutputStream stream; + +    public PDFWriter (FileOutputStream stream) +    { +        this.stream = stream; +    } + +    public void write (uint8[] data) +    { +        try +        { +            stream.write_all (data, null, null); +        } +        catch (Error e) +        { +            warning ("Error writing PDF: %s", e.message); +        } +        offset += data.length; +    } + +    public void write_string (string text) +    { +        write ((uint8[]) text.to_utf8 ()); +    } + +    public uint start_object () +    { +        object_offsets.append ((uint)offset); +        return object_offsets.length (); +    } +} + +public class PsWriter +{ +    public Cairo.PsSurface surface; +    public FileOutputStream stream; + +    public PsWriter (FileOutputStream stream) +    { +        this.stream = stream; +        surface = new Cairo.PsSurface.for_stream (write_cairo_data, 0, 0); +    } + +    private Cairo.Status write_cairo_data (uint8[] data) +    { +        try +        { +            stream.write_all (data, null, null); +        } +        catch (Error e) +        { +            warning ("Error writing data: %s", e.message); +            return Cairo.Status.WRITE_ERROR; +        } + +        return Cairo.Status.SUCCESS; +    }    +} diff --git a/src/colord.vapi b/src/colord.vapi new file mode 100644 index 0000000..817673f --- /dev/null +++ b/src/colord.vapi @@ -0,0 +1,17 @@ +[CCode (cprefix = "Cd", lower_case_cprefix = "cd_", cheader_filename = "colord.h")] +namespace Colord { +	public class Client : GLib.Object { +        public Client (); +		public bool connect_sync (GLib.Cancellable? cancellable = null) throws GLib.Error; +		public Device find_device_by_property_sync (string key, string value, GLib.Cancellable? cancellable = null) throws GLib.Error; +	} +	public class Device : GLib.Object { +		public bool connect_sync (GLib.Cancellable? cancellable = null) throws GLib.Error; +		public Profile? get_default_profile (); +	} +	public class Profile : GLib.Object { +		public bool connect_sync (GLib.Cancellable? cancellable = null) throws GLib.Error; +		public string? filename { get; } +	} +	public const string DEVICE_PROPERTY_SERIAL; +} diff --git a/src/config.vapi b/src/config.vapi new file mode 100644 index 0000000..c326020 --- /dev/null +++ b/src/config.vapi @@ -0,0 +1,10 @@ +[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] +namespace Config +{ +  public const string PKGDATADIR; +  public const string LOCALE_DIR; +  public const string GETTEXT_PACKAGE; +  public const string VERSION; +  public const string UI_DIR; +  public const string ICON_DIR; +} diff --git a/src/jpeglib.vapi b/src/jpeglib.vapi new file mode 100644 index 0000000..3022b5b --- /dev/null +++ b/src/jpeglib.vapi @@ -0,0 +1,57 @@ +[CCode (cheader_filename = "jpeglib.h", cprefix = "jpeg_")] +namespace JPEG { +    [CCode (cprefix = "JCS_")] +    public enum ColorSpace +    { +        UNKNOWN, +        GRAYSCALE, +        RGB, +        YCbCr, +        CMYK, +        YCCK +    } + +    public ErrorManager std_error (out ErrorManager err); + +    [CCode (cname = "struct jpeg_compress_struct", cprefix = "jpeg_", destroy_function = "jpeg_destroy_compress")] +    public struct Compress +    { +        public DestinationManager* dest; +        public int image_width; +        public int image_height; +        public int input_components; +        public ColorSpace in_color_space; +        public ErrorManager* err; + +        public void create_compress (); +        public void set_defaults (); +        public void start_compress (bool write_all_tables); +        public void write_scanlines ([CCode (array_length = false)] uint8*[] scanlines, int num_Lines); +        public void finish_compress (); +    } + +    [CCode (cname = "struct jpeg_error_mgr")] +    public struct ErrorManager +    { +        [CCode (cname = "jpeg_std_error")] +        public ErrorManager* std_error (); +    } + +    [CCode (has_target = false)] +    public delegate void InitDestinationFunc (Compress cinfo); +    [CCode (has_target = false)] +    public delegate bool EmptyOutputBufferFunc (Compress cinfo); +    [CCode (has_target = false)] +    public delegate void TermDestinationFunc (Compress cinfo); + +    [CCode (cname = "struct jpeg_destination_mgr")] +    public struct DestinationManager +    { +        [CCode (array_length = false)] +        public unowned uint8[] next_output_byte; +        public int free_in_buffer; +        public InitDestinationFunc init_destination; +        public EmptyOutputBufferFunc empty_output_buffer; +        public TermDestinationFunc term_destination; +    } +} diff --git a/src/page-view.c b/src/page-view.c index eae49e6..5f916e7 100644 --- a/src/page-view.c +++ b/src/page-view.c @@ -1,7 +1,10 @@ +/* page-view.c generated by valac 0.13.1, the Vala compiler + * generated from page-view.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later @@ -9,1251 +12,2080 @@   * license.   */ +#include <glib.h> +#include <glib-object.h> +#include <gdk-pixbuf/gdk-pixdata.h> +#include <float.h>  #include <math.h> +#include <gdk/gdk.h> +#include <string.h> +#include <stdlib.h> +#include <cairo.h> +#include <gobject/gvaluecollector.h> + + +#define TYPE_CROP_LOCATION (crop_location_get_type ()) + +#define TYPE_PAGE_VIEW (page_view_get_type ()) +#define PAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE_VIEW, PageView)) +#define PAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE_VIEW, PageViewClass)) +#define IS_PAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE_VIEW)) +#define IS_PAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE_VIEW)) +#define PAGE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE_VIEW, PageViewClass)) + +typedef struct _PageView PageView; +typedef struct _PageViewClass PageViewClass; +typedef struct _PageViewPrivate PageViewPrivate; + +#define TYPE_PAGE (page_get_type ()) +#define PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE, Page)) +#define PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE, PageClass)) +#define IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE)) +#define IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE)) +#define PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE, PageClass)) + +typedef struct _Page Page; +typedef struct _PageClass PageClass; + +#define TYPE_SCAN_DIRECTION (scan_direction_get_type ()) +#define _page_unref0(var) ((var == NULL) ? NULL : (var = (page_unref (var), NULL))) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _g_free0(var) (var = (g_free (var), NULL)) +typedef struct _ParamSpecPageView ParamSpecPageView; + +typedef enum  { +	CROP_LOCATION_NONE = 0, +	CROP_LOCATION_MIDDLE, +	CROP_LOCATION_TOP, +	CROP_LOCATION_BOTTOM, +	CROP_LOCATION_LEFT, +	CROP_LOCATION_RIGHT, +	CROP_LOCATION_TOP_LEFT, +	CROP_LOCATION_TOP_RIGHT, +	CROP_LOCATION_BOTTOM_LEFT, +	CROP_LOCATION_BOTTOM_RIGHT +} CropLocation; + +struct _PageView { +	GTypeInstance parent_instance; +	volatile int ref_count; +	PageViewPrivate * priv; +}; -#include "page-view.h" +struct _PageViewClass { +	GTypeClass parent_class; +	void (*finalize) (PageView *self); +}; -enum { -    CHANGED, -    SIZE_CHANGED, -    LAST_SIGNAL +typedef enum  { +	SCAN_DIRECTION_TOP_TO_BOTTOM, +	SCAN_DIRECTION_LEFT_TO_RIGHT, +	SCAN_DIRECTION_BOTTOM_TO_TOP, +	SCAN_DIRECTION_RIGHT_TO_LEFT +} ScanDirection; + +struct _PageViewPrivate { +	Page* page; +	GdkPixbuf* image; +	gboolean selected; +	gint border_width; +	gboolean update_image; +	ScanDirection scan_direction; +	gint scan_line; +	gint width; +	gint height; +	gint x_offset; +	gint y_offset; +	CropLocation crop_location; +	gdouble selected_crop_px; +	gdouble selected_crop_py; +	gint selected_crop_x; +	gint selected_crop_y; +	gint selected_crop_w; +	gint selected_crop_h; +	GdkCursorType cursor; +	gint animate_n_segments; +	gint animate_segment; +	guint animate_timeout;  }; -static guint signals[LAST_SIGNAL] = { 0, }; -enum { -    PROP_0, -    PROP_PAGE +struct _ParamSpecPageView { +	GParamSpec parent_instance;  }; -typedef enum -{ -    CROP_NONE = 0, -    CROP_MIDDLE, -    CROP_TOP, -    CROP_BOTTOM, -    CROP_LEFT, -    CROP_RIGHT, -    CROP_TOP_LEFT, -    CROP_TOP_RIGHT, -    CROP_BOTTOM_LEFT, -    CROP_BOTTOM_RIGHT -} CropLocation; -struct PageViewPrivate -{ -    /* Page being rendered */ -    Page *page; -   -    /* Image to render at current resolution */ -    GdkPixbuf *image; -   -    /* Border around image */ -    gboolean selected; -    gint border_width; - -    /* True if image needs to be regenerated */ -    gboolean update_image; - -    /* Direction of currently scanned image */ -    ScanDirection scan_direction; -   -    /* Next scan line to render */ -    gint scan_line; - -    /* Dimensions of image to generate */ -    gint width, height; - -    /* Location to place this page */ -    gint x, y; - -    CropLocation crop_location; -    gdouble selected_crop_px, selected_crop_py; -    gint selected_crop_x, selected_crop_y; -    gint selected_crop_w, selected_crop_h; - -    /* Cursor over this page */ -    gint cursor; - -    gint animate_n_segments, animate_segment; -    guint animate_timeout; +static gpointer page_view_parent_class = NULL; + +GType crop_location_get_type (void) G_GNUC_CONST; +gpointer page_view_ref (gpointer instance); +void page_view_unref (gpointer instance); +GParamSpec* param_spec_page_view (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page_view (GValue* value, gpointer v_object); +void value_take_page_view (GValue* value, gpointer v_object); +gpointer value_get_page_view (const GValue* value); +GType page_view_get_type (void) G_GNUC_CONST; +gpointer page_ref (gpointer instance); +void page_unref (gpointer instance); +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page (GValue* value, gpointer v_object); +void value_take_page (GValue* value, gpointer v_object); +gpointer value_get_page (const GValue* value); +GType page_get_type (void) G_GNUC_CONST; +GType scan_direction_get_type (void) G_GNUC_CONST; +#define PAGE_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_PAGE_VIEW, PageViewPrivate)) +enum  { +	PAGE_VIEW_DUMMY_PROPERTY  }; +PageView* page_view_new (Page* page); +PageView* page_view_construct (GType object_type, Page* page); +static void page_view_page_pixels_changed_cb (PageView* self, Page* p); +static void _page_view_page_pixels_changed_cb_page_pixels_changed (Page* _sender, gpointer self); +static void page_view_page_size_changed_cb (PageView* self, Page* p); +static void _page_view_page_size_changed_cb_page_size_changed (Page* _sender, gpointer self); +static void page_view_page_overlay_changed_cb (PageView* self, Page* p); +static void _page_view_page_overlay_changed_cb_page_crop_changed (Page* _sender, gpointer self); +static void _page_view_page_overlay_changed_cb_page_scan_line_changed (Page* _sender, gpointer self); +static void page_view_scan_direction_changed_cb (PageView* self, Page* p); +static void _page_view_scan_direction_changed_cb_page_scan_direction_changed (Page* _sender, gpointer self); +Page* page_view_get_page (PageView* self); +void page_view_set_selected (PageView* self, gboolean selected); +gboolean page_view_get_selected (PageView* self); +void page_view_set_x_offset (PageView* self, gint offset); +void page_view_set_y_offset (PageView* self, gint offset); +gint page_view_get_x_offset (PageView* self); +gint page_view_get_y_offset (PageView* self); +static guchar page_view_get_sample (PageView* self, guchar* pixels, int pixels_length1, gint offset, gint x, gint depth, gint sample); +static void page_view_get_pixel (PageView* self, Page* page, gint x, gint y, guchar* pixel, int pixel_length1); +ScanDirection page_get_scan_direction (Page* self); +gint page_get_scan_width (Page* self); +gint page_get_scan_height (Page* self); +gint page_get_depth (Page* self); +gint page_get_n_channels (Page* self); +guchar* page_get_pixels (Page* self, int* result_length1); +gint page_get_rowstride (Page* self); +static void page_view_set_pixel (PageView* self, Page* page, gdouble l, gdouble r, gdouble t, gdouble b, guchar* output, int output_length1, gint offset); +static void page_view_update_preview (PageView* self, Page* page, GdkPixbuf** output_image, gint output_width, gint output_height, ScanDirection scan_direction, gint old_scan_line, gint scan_line); +gint page_get_width (Page* self); +gint page_get_height (Page* self); +gboolean page_has_data (Page* self); +static gint page_view_get_preview_width (PageView* self); +static gint page_view_get_preview_height (PageView* self); +static void page_view_update_page_view (PageView* self); +gint page_get_scan_line (Page* self); +static gint page_view_page_to_screen_x (PageView* self, gint x); +static gint page_view_page_to_screen_y (PageView* self, gint y); +static gint page_view_screen_to_page_x (PageView* self, gint x); +static gint page_view_screen_to_page_y (PageView* self, gint y); +static CropLocation page_view_get_crop_location (PageView* self, gint x, gint y); +gboolean page_has_crop (Page* self); +void page_get_crop (Page* self, gint* x, gint* y, gint* width, gint* height); +gchar* page_get_named_crop (Page* self); +void page_view_button_press (PageView* self, gint x, gint y); +void page_view_motion (PageView* self, gint x, gint y); +void page_move_crop (Page* self, gint x, gint y); +void page_set_custom_crop (Page* self, gint width, gint height); +void page_view_button_release (PageView* self, gint x, gint y); +GdkCursorType page_view_get_cursor (PageView* self); +static gboolean page_view_animation_cb (PageView* self); +static void page_view_update_animation (PageView* self); +gboolean page_is_scanning (Page* self); +static gboolean _page_view_animation_cb_gsource_func (gpointer self); +void page_view_render (PageView* self, cairo_t* context); +void page_view_set_width (PageView* self, gint width); +void page_view_set_height (PageView* self, gint height); +gint page_view_get_width (PageView* self); +gint page_view_get_height (PageView* self); +static void page_view_finalize (PageView* obj); + + +GType crop_location_get_type (void) { +	static volatile gsize crop_location_type_id__volatile = 0; +	if (g_once_init_enter (&crop_location_type_id__volatile)) { +		static const GEnumValue values[] = {{CROP_LOCATION_NONE, "CROP_LOCATION_NONE", "none"}, {CROP_LOCATION_MIDDLE, "CROP_LOCATION_MIDDLE", "middle"}, {CROP_LOCATION_TOP, "CROP_LOCATION_TOP", "top"}, {CROP_LOCATION_BOTTOM, "CROP_LOCATION_BOTTOM", "bottom"}, {CROP_LOCATION_LEFT, "CROP_LOCATION_LEFT", "left"}, {CROP_LOCATION_RIGHT, "CROP_LOCATION_RIGHT", "right"}, {CROP_LOCATION_TOP_LEFT, "CROP_LOCATION_TOP_LEFT", "top-left"}, {CROP_LOCATION_TOP_RIGHT, "CROP_LOCATION_TOP_RIGHT", "top-right"}, {CROP_LOCATION_BOTTOM_LEFT, "CROP_LOCATION_BOTTOM_LEFT", "bottom-left"}, {CROP_LOCATION_BOTTOM_RIGHT, "CROP_LOCATION_BOTTOM_RIGHT", "bottom-right"}, {0, NULL, NULL}}; +		GType crop_location_type_id; +		crop_location_type_id = g_enum_register_static ("CropLocation", values); +		g_once_init_leave (&crop_location_type_id__volatile, crop_location_type_id); +	} +	return crop_location_type_id__volatile; +} + + +static gpointer _page_ref0 (gpointer self) { +	return self ? page_ref (self) : NULL; +} + + +static void _page_view_page_pixels_changed_cb_page_pixels_changed (Page* _sender, gpointer self) { +	page_view_page_pixels_changed_cb (self, _sender); +} + + +static void _page_view_page_size_changed_cb_page_size_changed (Page* _sender, gpointer self) { +	page_view_page_size_changed_cb (self, _sender); +} + + +static void _page_view_page_overlay_changed_cb_page_crop_changed (Page* _sender, gpointer self) { +	page_view_page_overlay_changed_cb (self, _sender); +} + + +static void _page_view_page_overlay_changed_cb_page_scan_line_changed (Page* _sender, gpointer self) { +	page_view_page_overlay_changed_cb (self, _sender); +} + + +static void _page_view_scan_direction_changed_cb_page_scan_direction_changed (Page* _sender, gpointer self) { +	page_view_scan_direction_changed_cb (self, _sender); +} + + +PageView* page_view_construct (GType object_type, Page* page) { +	PageView* self = NULL; +	Page* _tmp0_; +	g_return_val_if_fail (page != NULL, NULL); +	self = (PageView*) g_type_create_instance (object_type); +	_tmp0_ = _page_ref0 (page); +	_page_unref0 (self->priv->page); +	self->priv->page = _tmp0_; +	g_signal_connect (page, "pixels-changed", (GCallback) _page_view_page_pixels_changed_cb_page_pixels_changed, self); +	g_signal_connect (page, "size-changed", (GCallback) _page_view_page_size_changed_cb_page_size_changed, self); +	g_signal_connect (page, "crop-changed", (GCallback) _page_view_page_overlay_changed_cb_page_crop_changed, self); +	g_signal_connect (page, "scan-line-changed", (GCallback) _page_view_page_overlay_changed_cb_page_scan_line_changed, self); +	g_signal_connect (page, "scan-direction-changed", (GCallback) _page_view_scan_direction_changed_cb_page_scan_direction_changed, self); +	return self; +} + + +PageView* page_view_new (Page* page) { +	return page_view_construct (TYPE_PAGE_VIEW, page); +} + -G_DEFINE_TYPE (PageView, page_view, G_TYPE_OBJECT); +Page* page_view_get_page (PageView* self) { +	Page* result = NULL; +	Page* _tmp0_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = _page_ref0 (self->priv->page); +	result = _tmp0_; +	return result; +} -PageView * -page_view_new (Page *page) -{ -    return g_object_new (PAGE_VIEW_TYPE, "page", page, NULL); +void page_view_set_selected (PageView* self, gboolean selected) { +	gboolean _tmp0_ = FALSE; +	gboolean _tmp1_ = FALSE; +	g_return_if_fail (self != NULL); +	if (self->priv->selected) { +		_tmp1_ = selected; +	} else { +		_tmp1_ = FALSE; +	} +	if (_tmp1_) { +		_tmp0_ = TRUE; +	} else { +		gboolean _tmp2_ = FALSE; +		if (!self->priv->selected) { +			_tmp2_ = !selected; +		} else { +			_tmp2_ = FALSE; +		} +		_tmp0_ = _tmp2_; +	} +	if (_tmp0_) { +		return; +	} +	self->priv->selected = selected; +	g_signal_emit_by_name (self, "changed");  } -Page * -page_view_get_page (PageView *view) -{ -    g_return_val_if_fail (view != NULL, NULL); -    return view->priv->page; +gboolean page_view_get_selected (PageView* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->selected; +	return result;  } -void -page_view_set_selected (PageView *view, gboolean selected) -{ -    g_return_if_fail (view != NULL); -    if ((view->priv->selected && selected) || (!view->priv->selected && !selected)) -        return; -    view->priv->selected = selected; -    g_signal_emit (view, signals[CHANGED], 0);   +void page_view_set_x_offset (PageView* self, gint offset) { +	g_return_if_fail (self != NULL); +	self->priv->x_offset = offset;  } -gboolean -page_view_get_selected (PageView *view) -{ -    g_return_val_if_fail (view != NULL, FALSE); -    return view->priv->selected; +void page_view_set_y_offset (PageView* self, gint offset) { +	g_return_if_fail (self != NULL); +	self->priv->y_offset = offset;  } -void -page_view_set_x_offset (PageView *view, gint offset) -{ -    g_return_if_fail (view != NULL); -    view->priv->x = offset; +gint page_view_get_x_offset (PageView* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->x_offset; +	return result;  } -void -page_view_set_y_offset (PageView *view, gint offset) -{ -    g_return_if_fail (view != NULL); -    view->priv->y = offset; +gint page_view_get_y_offset (PageView* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->y_offset; +	return result;  } -gint -page_view_get_x_offset (PageView *view) -{ -    g_return_val_if_fail (view != NULL, 0);   -    return view->priv->x;   +static guchar page_view_get_sample (PageView* self, guchar* pixels, int pixels_length1, gint offset, gint x, gint depth, gint sample) { +	guchar result = '\0'; +	g_return_val_if_fail (self != NULL, '\0'); +	result = (guchar) 0xFF; +	return result;  } -gint -page_view_get_y_offset (PageView *view) -{ -    g_return_val_if_fail (view != NULL, 0); -    return view->priv->y; +static void page_view_get_pixel (PageView* self, Page* page, gint x, gint y, guchar* pixel, int pixel_length1) { +	ScanDirection _tmp0_; +	gint _tmp5_; +	gint depth; +	gint _tmp6_; +	gint n_channels; +	gint _tmp7_; +	guchar* _tmp8_ = NULL; +	guchar* pixels; +	gint pixels_length1; +	gint _pixels_size_; +	gint _tmp9_; +	gint offset; +	gboolean _tmp10_ = FALSE; +	guchar _tmp16_; +	guchar _tmp17_; +	guchar _tmp18_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = page_get_scan_direction (page); +	switch (_tmp0_) { +		case SCAN_DIRECTION_TOP_TO_BOTTOM: +		{ +			break; +		} +		case SCAN_DIRECTION_BOTTOM_TO_TOP: +		{ +			gint _tmp1_; +			gint _tmp2_; +			_tmp1_ = page_get_scan_width (page); +			x = (_tmp1_ - x) - 1; +			_tmp2_ = page_get_scan_height (page); +			y = (_tmp2_ - y) - 1; +			break; +		} +		case SCAN_DIRECTION_LEFT_TO_RIGHT: +		{ +			gint t; +			gint _tmp3_; +			t = x; +			_tmp3_ = page_get_scan_width (page); +			x = (_tmp3_ - y) - 1; +			y = t; +			break; +		} +		case SCAN_DIRECTION_RIGHT_TO_LEFT: +		{ +			gint t; +			gint _tmp4_; +			t = x; +			x = y; +			_tmp4_ = page_get_scan_height (page); +			y = (_tmp4_ - t) - 1; +			break; +		} +		default: +		break; +	} +	_tmp5_ = page_get_depth (page); +	depth = _tmp5_; +	_tmp6_ = page_get_n_channels (page); +	n_channels = _tmp6_; +	_tmp8_ = page_get_pixels (page, &_tmp7_); +	pixels = _tmp8_; +	pixels_length1 = _tmp7_; +	_pixels_size_ = pixels_length1; +	_tmp9_ = page_get_rowstride (page); +	offset = _tmp9_ * y; +	if (depth == 8) { +		_tmp10_ = n_channels == 3; +	} else { +		_tmp10_ = FALSE; +	} +	if (_tmp10_) { +		gint o; +		o = offset + (x * n_channels); +		pixel[0] = pixels[o]; +		pixel[1] = pixels[o + 1]; +		pixel[2] = pixels[o + 2]; +		return; +	} else { +		gboolean _tmp11_ = FALSE; +		if (depth == 8) { +			_tmp11_ = n_channels == 1; +		} else { +			_tmp11_ = FALSE; +		} +		if (_tmp11_) { +			pixel[2] = pixels[offset + x]; +			pixel[1] = pixel[2]; +			pixel[0] = pixel[1]; +			return; +		} else { +			gboolean _tmp12_ = FALSE; +			if (depth == 1) { +				_tmp12_ = n_channels == 1; +			} else { +				_tmp12_ = FALSE; +			} +			if (_tmp12_) { +				gint o; +				gint _tmp13_ = 0; +				o = offset + (x / 8); +				if (((gint) (pixels[o] & (0x80 >> (x % 8)))) != 0) { +					_tmp13_ = 0x00; +				} else { +					_tmp13_ = 0xFF; +				} +				pixel[2] = (guchar) _tmp13_; +				pixel[1] = pixel[2]; +				pixel[0] = pixel[1]; +				return; +			} else { +				gboolean _tmp14_ = FALSE; +				if (depth == 2) { +					_tmp14_ = n_channels == 1; +				} else { +					_tmp14_ = FALSE; +				} +				if (_tmp14_) { +					gint _tmp15_[4] = {0}; +					gint block_shift[4]; +					gint o; +					gint sample; +					_tmp15_[0] = 6; +					_tmp15_[1] = 4; +					_tmp15_[2] = 2; +					_tmp15_[3] = 0; +					memcpy (block_shift, _tmp15_, 4 * sizeof (gint)); +					o = offset + (x / 4); +					sample = (pixels[o] >> block_shift[x % 4]) & 0x3; +					sample = (sample * 255) / 3; +					pixel[2] = (guchar) sample; +					pixel[1] = pixel[2]; +					pixel[0] = pixel[1]; +					return; +				} +			} +		} +	} +	_tmp16_ = page_view_get_sample (self, pixels, pixels_length1, offset, x, depth, x * n_channels); +	pixel[0] = _tmp16_; +	_tmp17_ = page_view_get_sample (self, pixels, pixels_length1, offset, x, depth, (x * n_channels) + 1); +	pixel[1] = _tmp17_; +	_tmp18_ = page_view_get_sample (self, pixels, pixels_length1, offset, x, depth, (x * n_channels) + 2); +	pixel[2] = _tmp18_;  } -static guchar -get_sample (const guchar *line, gint x, gint depth, gint sample) -{ -    // FIXME -    return 0xFF; +static void page_view_set_pixel (PageView* self, Page* page, gdouble l, gdouble r, gdouble t, gdouble b, guchar* output, int output_length1, gint offset) { +	gint L; +	gint R; +	gint T; +	gint B; +	gdouble red; +	gdouble green; +	gdouble blue; +	gboolean _tmp0_ = FALSE; +	gboolean _tmp1_ = FALSE; +	gboolean _tmp10_ = FALSE; +	gboolean _tmp11_ = FALSE; +	gboolean _tmp12_ = FALSE; +	gboolean _tmp13_ = FALSE; +	gdouble scale; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	L = (gint) l; +	if (((gdouble) L) != l) { +		L++; +	} +	R = (gint) r; +	T = (gint) t; +	if (((gdouble) T) != t) { +		T++; +	} +	B = (gint) b; +	red = 0.0; +	green = 0.0; +	blue = 0.0; +	if ((r - l) <= 1.0) { +		_tmp1_ = ((gint) r) == ((gint) l); +	} else { +		_tmp1_ = FALSE; +	} +	if (_tmp1_) { +		_tmp0_ = TRUE; +	} else { +		gboolean _tmp2_ = FALSE; +		if ((b - t) <= 1.0) { +			_tmp2_ = ((gint) b) == ((gint) t); +		} else { +			_tmp2_ = FALSE; +		} +		_tmp0_ = _tmp2_; +	} +	if (_tmp0_) { +		gboolean _tmp3_ = FALSE; +		gdouble scale; +		if (((gint) l) == ((gint) r)) { +			_tmp3_ = TRUE; +		} else { +			_tmp3_ = ((gint) t) == ((gint) b); +		} +		if (_tmp3_) { +			guchar p[3] = {0}; +			page_view_get_pixel (self, page, (gint) l, (gint) t, p, 3); +			output[offset] = p[0]; +			output[offset + 1] = p[1]; +			output[offset + 2] = p[2]; +			return; +		} +		if (L > R) { +			guchar p[3] = {0}; +			page_view_get_pixel (self, page, R, T - 1, p, 3); +			red = red + ((p[0] * (r - l)) * (T - t)); +			green = green + ((p[1] * (r - l)) * (T - t)); +			blue = blue + ((p[2] * (r - l)) * (T - t)); +			{ +				gint y; +				y = T; +				{ +					gboolean _tmp4_; +					_tmp4_ = TRUE; +					while (TRUE) { +						if (!_tmp4_) { +							y++; +						} +						_tmp4_ = FALSE; +						if (!(y < B)) { +							break; +						} +						page_view_get_pixel (self, page, R, y, p, 3); +						red = red + (p[0] * (r - l)); +						green = green + (p[1] * (r - l)); +						blue = blue + (p[2] * (r - l)); +					} +				} +			} +			page_view_get_pixel (self, page, R, B, p, 3); +			red = red + ((p[0] * (r - l)) * (b - B)); +			green = green + ((p[1] * (r - l)) * (b - B)); +			blue = blue + ((p[2] * (r - l)) * (b - B)); +		} else { +			guchar p[3] = {0}; +			page_view_get_pixel (self, page, L - 1, B, p, 3); +			red = red + ((p[0] * (b - t)) * (L - l)); +			green = green + ((p[1] * (b - t)) * (L - l)); +			blue = blue + ((p[2] * (b - t)) * (L - l)); +			{ +				gint x; +				x = L; +				{ +					gboolean _tmp5_; +					_tmp5_ = TRUE; +					while (TRUE) { +						if (!_tmp5_) { +							x++; +						} +						_tmp5_ = FALSE; +						if (!(x < R)) { +							break; +						} +						page_view_get_pixel (self, page, x, B, p, 3); +						red = red + (p[0] * (b - t)); +						green = green + (p[1] * (b - t)); +						blue = blue + (p[2] * (b - t)); +					} +				} +			} +			page_view_get_pixel (self, page, R, B, p, 3); +			red = red + ((p[0] * (b - t)) * (r - R)); +			green = green + ((p[1] * (b - t)) * (r - R)); +			blue = blue + ((p[2] * (b - t)) * (r - R)); +		} +		scale = 1.0 / ((r - l) * (b - t)); +		output[offset] = (guchar) ((red * scale) + 0.5); +		output[offset + 1] = (guchar) ((green * scale) + 0.5); +		output[offset + 2] = (guchar) ((blue * scale) + 0.5); +		return; +	} +	{ +		gint x; +		x = L; +		{ +			gboolean _tmp6_; +			_tmp6_ = TRUE; +			while (TRUE) { +				if (!_tmp6_) { +					x++; +				} +				_tmp6_ = FALSE; +				if (!(x < R)) { +					break; +				} +				{ +					gint y; +					y = T; +					{ +						gboolean _tmp7_; +						_tmp7_ = TRUE; +						while (TRUE) { +							guchar p[3] = {0}; +							if (!_tmp7_) { +								y++; +							} +							_tmp7_ = FALSE; +							if (!(y < B)) { +								break; +							} +							page_view_get_pixel (self, page, x, y, p, 3); +							red = red + p[0]; +							green = green + p[1]; +							blue = blue + p[2]; +						} +					} +				} +			} +		} +	} +	{ +		gint x; +		x = L; +		{ +			gboolean _tmp8_; +			_tmp8_ = TRUE; +			while (TRUE) { +				if (!_tmp8_) { +					x++; +				} +				_tmp8_ = FALSE; +				if (!(x < R)) { +					break; +				} +				if (t != ((gdouble) T)) { +					guchar p[3] = {0}; +					page_view_get_pixel (self, page, x, T - 1, p, 3); +					red = red + (p[0] * (T - t)); +					green = green + (p[1] * (T - t)); +					blue = blue + (p[2] * (T - t)); +				} +				if (b != ((gdouble) B)) { +					guchar p[3] = {0}; +					page_view_get_pixel (self, page, x, B, p, 3); +					red = red + (p[0] * (b - B)); +					green = green + (p[1] * (b - B)); +					blue = blue + (p[2] * (b - B)); +				} +			} +		} +	} +	{ +		gint y; +		y = T; +		{ +			gboolean _tmp9_; +			_tmp9_ = TRUE; +			while (TRUE) { +				if (!_tmp9_) { +					y++; +				} +				_tmp9_ = FALSE; +				if (!(y < B)) { +					break; +				} +				if (l != ((gdouble) L)) { +					guchar p[3] = {0}; +					page_view_get_pixel (self, page, L - 1, y, p, 3); +					red = red + (p[0] * (L - l)); +					green = green + (p[1] * (L - l)); +					blue = blue + (p[2] * (L - l)); +				} +				if (r != ((gdouble) R)) { +					guchar p[3] = {0}; +					page_view_get_pixel (self, page, R, y, p, 3); +					red = red + (p[0] * (r - R)); +					green = green + (p[1] * (r - R)); +					blue = blue + (p[2] * (r - R)); +				} +			} +		} +	} +	if (l != ((gdouble) L)) { +		_tmp10_ = t != ((gdouble) T); +	} else { +		_tmp10_ = FALSE; +	} +	if (_tmp10_) { +		guchar p[3] = {0}; +		page_view_get_pixel (self, page, L - 1, T - 1, p, 3); +		red = red + ((p[0] * (L - l)) * (T - t)); +		green = green + ((p[1] * (L - l)) * (T - t)); +		blue = blue + ((p[2] * (L - l)) * (T - t)); +	} +	if (r != ((gdouble) R)) { +		_tmp11_ = t != ((gdouble) T); +	} else { +		_tmp11_ = FALSE; +	} +	if (_tmp11_) { +		guchar p[3] = {0}; +		page_view_get_pixel (self, page, R, T - 1, p, 3); +		red = red + ((p[0] * (r - R)) * (T - t)); +		green = green + ((p[1] * (r - R)) * (T - t)); +		blue = blue + ((p[2] * (r - R)) * (T - t)); +	} +	if (r != ((gdouble) R)) { +		_tmp12_ = b != ((gdouble) B); +	} else { +		_tmp12_ = FALSE; +	} +	if (_tmp12_) { +		guchar p[3] = {0}; +		page_view_get_pixel (self, page, R, B, p, 3); +		red = red + ((p[0] * (r - R)) * (b - B)); +		green = green + ((p[1] * (r - R)) * (b - B)); +		blue = blue + ((p[2] * (r - R)) * (b - B)); +	} +	if (l != ((gdouble) L)) { +		_tmp13_ = b != ((gdouble) B); +	} else { +		_tmp13_ = FALSE; +	} +	if (_tmp13_) { +		guchar p[3] = {0}; +		page_view_get_pixel (self, page, L - 1, B, p, 3); +		red = red + ((p[0] * (L - l)) * (b - B)); +		green = green + ((p[1] * (L - l)) * (b - B)); +		blue = blue + ((p[2] * (L - l)) * (b - B)); +	} +	scale = 1.0 / ((r - l) * (b - t)); +	output[offset] = (guchar) ((red * scale) + 0.5); +	output[offset + 1] = (guchar) ((green * scale) + 0.5); +	output[offset + 2] = (guchar) ((blue * scale) + 0.5);  } -static void -get_pixel (Page *page, gint x, gint y, guchar *pixel) -{ -    gint t, depth, n_channels; -    const guchar *p, *line; - -    switch (page_get_scan_direction (page)) -    { -    case TOP_TO_BOTTOM: -        break; -    case BOTTOM_TO_TOP: -        x = page_get_scan_width (page) - x - 1; -        y = page_get_scan_height (page) - y - 1; -        break; -    case LEFT_TO_RIGHT: -        t = x; -        x = page_get_scan_width (page) - y - 1; -        y = t; -        break; -    case RIGHT_TO_LEFT: -        t = x; -        x = y; -        y = page_get_scan_height (page) - t - 1; -        break; -    } - -    depth = page_get_depth (page); -    n_channels = page_get_n_channels (page); -    line = page_get_pixels (page) + page_get_rowstride (page) * y; - -    /* Optimise for 8 bit images */ -    if (depth == 8 && n_channels == 3) { -        p = line + x * n_channels; -        pixel[0] = p[0]; -        pixel[1] = p[1]; -        pixel[2] = p[2]; -        return; -    } -    else if (depth == 8 && n_channels == 1) { -        p = line + x; -        pixel[0] = pixel[1] = pixel[2] = p[0]; -        return; -    } - -    /* Optimise for bitmaps */ -    else if (depth == 1 && n_channels == 1) { -        p = line + (x / 8); -        pixel[0] = pixel[1] = pixel[2] = p[0] & (0x80 >> (x % 8)) ? 0x00 : 0xFF; -        return; -    } - -    /* Optimise for 2 bit images */ -    else if (depth == 2 && n_channels == 1) { -        gint sample; -        gint block_shift[4] = { 6, 4, 2, 0 }; - -        p = line + (x / 4); -        sample = (p[0] >> block_shift[x % 4]) & 0x3; -        sample = sample * 255 / 3; - -        pixel[0] = pixel[1] = pixel[2] = sample; -        return; -    } - -    /* Use slow method */ -    pixel[0] = get_sample (line, x, depth, x * n_channels); -    pixel[0] = get_sample (line, x, depth, x * n_channels + 1); -    pixel[0] = get_sample (line, x, depth, x * n_channels + 2); +static void page_view_update_preview (PageView* self, Page* page, GdkPixbuf** output_image, gint output_width, gint output_height, ScanDirection scan_direction, gint old_scan_line, gint scan_line) { +	gint _tmp0_; +	gint input_width; +	gint _tmp1_; +	gint input_height; +	gint L = 0; +	gint R = 0; +	gint T = 0; +	gint B = 0; +	gboolean _tmp2_ = FALSE; +	gboolean _tmp3_ = FALSE; +	guint8* _tmp7_ = NULL; +	guchar* output; +	gint output_length1; +	gint _output_size_; +	gint _tmp8_; +	gint output_rowstride; +	gint _tmp9_; +	gint output_n_channels; +	gboolean _tmp10_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = page_get_width (page); +	input_width = _tmp0_; +	_tmp1_ = page_get_height (page); +	input_height = _tmp1_; +	if ((*output_image) == NULL) { +		_tmp3_ = TRUE; +	} else { +		gint _tmp4_; +		_tmp4_ = gdk_pixbuf_get_width (*output_image); +		_tmp3_ = _tmp4_ != output_width; +	} +	if (_tmp3_) { +		_tmp2_ = TRUE; +	} else { +		gint _tmp5_; +		_tmp5_ = gdk_pixbuf_get_height (*output_image); +		_tmp2_ = _tmp5_ != output_height; +	} +	if (_tmp2_) { +		GdkPixbuf* _tmp6_ = NULL; +		_tmp6_ = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, output_width, output_height); +		_g_object_unref0 (*output_image); +		*output_image = _tmp6_; +		L = 0; +		R = output_width - 1; +		T = 0; +		B = output_height - 1; +	} else { +		switch (scan_direction) { +			case SCAN_DIRECTION_TOP_TO_BOTTOM: +			{ +				L = 0; +				R = output_width - 1; +				T = (gint) ((((gdouble) old_scan_line) * output_height) / input_height); +				B = (gint) (((((gdouble) scan_line) * output_height) / input_height) + 0.5); +				break; +			} +			case SCAN_DIRECTION_LEFT_TO_RIGHT: +			{ +				L = (gint) ((((gdouble) old_scan_line) * output_width) / input_width); +				R = (gint) (((((gdouble) scan_line) * output_width) / input_width) + 0.5); +				T = 0; +				B = output_height - 1; +				break; +			} +			case SCAN_DIRECTION_BOTTOM_TO_TOP: +			{ +				L = 0; +				R = output_width - 1; +				T = (gint) ((((gdouble) (input_height - scan_line)) * output_height) / input_height); +				B = (gint) (((((gdouble) (input_height - old_scan_line)) * output_height) / input_height) + 0.5); +				break; +			} +			case SCAN_DIRECTION_RIGHT_TO_LEFT: +			{ +				L = (gint) ((((gdouble) (input_width - scan_line)) * output_width) / input_width); +				R = (gint) (((((gdouble) (input_width - old_scan_line)) * output_width) / input_width) + 0.5); +				T = 0; +				B = output_height - 1; +				break; +			} +			default: +			{ +				T = 0; +				B = T; +				R = B; +				L = R; +				break; +			} +		} +	} +	if (R >= output_width) { +		R = output_width - 1; +	} +	if (B >= output_height) { +		B = output_height - 1; +	} +	g_return_if_fail (L >= 0); +	g_return_if_fail (R < output_width); +	g_return_if_fail (T >= 0); +	g_return_if_fail (B < output_height); +	g_return_if_fail ((*output_image) != NULL); +	_tmp7_ = gdk_pixbuf_get_pixels (*output_image); +	output = _tmp7_; +	output_length1 = -1; +	_output_size_ = output_length1; +	_tmp8_ = gdk_pixbuf_get_rowstride (*output_image); +	output_rowstride = _tmp8_; +	_tmp9_ = gdk_pixbuf_get_n_channels (*output_image); +	output_n_channels = _tmp9_; +	_tmp10_ = page_has_data (page); +	if (!_tmp10_) { +		{ +			gint x; +			x = L; +			{ +				gboolean _tmp11_; +				_tmp11_ = TRUE; +				while (TRUE) { +					if (!_tmp11_) { +						x++; +					} +					_tmp11_ = FALSE; +					if (!(x <= R)) { +						break; +					} +					{ +						gint y; +						y = T; +						{ +							gboolean _tmp12_; +							_tmp12_ = TRUE; +							while (TRUE) { +								gint o; +								if (!_tmp12_) { +									y++; +								} +								_tmp12_ = FALSE; +								if (!(y <= B)) { +									break; +								} +								o = (output_rowstride * y) + (x * output_n_channels); +								output[o + 2] = (guchar) 0xFF; +								output[o + 1] = output[o + 2]; +								output[o] = output[o + 1]; +							} +						} +					} +				} +			} +		} +		return; +	} +	{ +		gint x; +		x = L; +		{ +			gboolean _tmp13_; +			_tmp13_ = TRUE; +			while (TRUE) { +				gdouble l; +				gdouble r; +				if (!_tmp13_) { +					x++; +				} +				_tmp13_ = FALSE; +				if (!(x <= R)) { +					break; +				} +				l = (((gdouble) x) * input_width) / output_width; +				r = (((gdouble) (x + 1)) * input_width) / output_width; +				{ +					gint y; +					y = T; +					{ +						gboolean _tmp14_; +						_tmp14_ = TRUE; +						while (TRUE) { +							gdouble t; +							gdouble b; +							if (!_tmp14_) { +								y++; +							} +							_tmp14_ = FALSE; +							if (!(y <= B)) { +								break; +							} +							t = (((gdouble) y) * input_height) / output_height; +							b = (((gdouble) (y + 1)) * input_height) / output_height; +							page_view_set_pixel (self, page, l, r, t, b, output, output_length1, (output_rowstride * y) + (x * output_n_channels)); +						} +					} +				} +			} +		} +	}  } -static void -set_pixel (Page *page, -           double l, double r, double t, double b, guchar *pixel) -{ -    gint x, y; -    gint L, R, T, B; -    guchar p[3]; -    double scale, red, green, blue; -   -    /* Decimation: -     *  -     * Target pixel is defined by (t,l)-(b,r) -     * It touches 16 pixels in original image -     * It completely covers 4 pixels in original image (T,L)-(B,R) -     * Add covered pixels and add weighted partially covered pixels. -     * Divide by total area. -     *  -     *      l  L           R   r  -     *   +-----+-----+-----+-----+ -     *   |     |     |     |     | -     * t |  +--+-----+-----+---+ | -     * T +--+--+-----+-----+---+-+ -     *   |  |  |     |     |   | | -     *   |  |  |     |     |   | | -     *   +--+--+-----+-----+---+-+ -     *   |  |  |     |     |   | | -     *   |  |  |     |     |   | | -     * B +--+--+-----+-----+---+-+ -     *   |  |  |     |     |   | | -     * b |  +--+-----+-----+---+ | -     *   +-----+-----+-----+-----+ -     *  -     *  -     * Interpolation: -     *  -     *             l    r -     *   +-----+-----+-----+-----+ -     *   |     |     |     |     | -     *   |     |     |     |     | -     *   +-----+-----+-----+-----+ -     * t |     |   +-+--+  |     | -     *   |     |   | |  |  |     | -     *   +-----+---+-+--+--+-----+ -     * b |     |   +-+--+  |     | -     *   |     |     |     |     | -     *   +-----+-----+-----+-----+ -     *   |     |     |     |     | -     *   |     |     |     |     | -     *   +-----+-----+-----+-----+ -     *  -     * Same again, just no completely covered pixels. -     */ -   -    L = l; -    if (L != l) -        L++; -    R = r; -    T = t; -    if (T != t) -        T++; -    B = b; -   -    red = green = blue = 0.0; - -    /* Target can fit inside one source pixel -     * +-----+ -     * |     | -     * | +--+|      +-----+-----+      +-----+      +-----+      +-----+ -     * +-+--++  or  |   +-++    |  or  | +-+ |  or  | +--+|  or  |  +--+ -     * | +--+|      |   +-++    |      | +-+ |      | |  ||      |  |  | -     * |     |      +-----+-----+      +-----+      +-+--++      +--+--+ -     * +-----+ -     */ -    if ((r - l <= 1.0 && (gint)r == (gint)l) || (b - t <= 1.0 && (gint)b == (gint)t)) { -        /* Inside */ -        if ((gint)l == (gint)r || (gint)t == (gint)b) { -            get_pixel (page, (gint)l, (gint)t, p); -            pixel[0] = p[0]; -            pixel[1] = p[1]; -            pixel[2] = p[2]; -            return; -        } - -        /* Stradling horizontal edge */ -        if (L > R) { -            get_pixel (page, R, T-1, p); -            red   += p[0] * (r-l)*(T-t); -            green += p[1] * (r-l)*(T-t); -            blue  += p[2] * (r-l)*(T-t); -            for (y = T; y < B; y++) { -                get_pixel (page, R, y, p); -                red   += p[0] * (r-l); -                green += p[1] * (r-l); -                blue  += p[2] * (r-l); -            } -            get_pixel (page, R, B, p); -            red   += p[0] * (r-l)*(b-B); -            green += p[1] * (r-l)*(b-B); -            blue  += p[2] * (r-l)*(b-B); -        } -        /* Stradling vertical edge */ -        else { -            get_pixel (page, L - 1, B, p); -            red   += p[0] * (b-t)*(L-l); -            green += p[1] * (b-t)*(L-l); -            blue  += p[2] * (b-t)*(L-l); -            for (x = L; x < R; x++) { -                get_pixel (page, x, B, p); -                red   += p[0] * (b-t); -                green += p[1] * (b-t); -                blue  += p[2] * (b-t); -            } -            get_pixel (page, R, B, p); -            red   += p[0] * (b-t)*(r-R); -            green += p[1] * (b-t)*(r-R); -            blue  += p[2] * (b-t)*(r-R); -        } - -        scale = 1.0 / ((r - l) * (b - t)); -        pixel[0] = (guchar)(red * scale + 0.5); -        pixel[1] = (guchar)(green * scale + 0.5); -        pixel[2] = (guchar)(blue * scale + 0.5); -        return; -    } - -    /* Add the middle pixels */ -    for (x = L; x < R; x++) { -        for (y = T; y < B; y++) { -            get_pixel (page, x, y, p); -            red   += p[0]; -            green += p[1]; -            blue  += p[2]; -        } -    } - -    /* Add the weighted top and bottom pixels */ -    for (x = L; x < R; x++) { -        if (t != T) { -            get_pixel (page, x, T - 1, p); -            red   += p[0] * (T - t); -            green += p[1] * (T - t); -            blue  += p[2] * (T - t); -        } - -        if (b != B) { -            get_pixel (page, x, B, p); -            red   += p[0] * (b - B); -            green += p[1] * (b - B); -            blue  += p[2] * (b - B); -        } -    } - -    /* Add the left and right pixels */ -    for (y = T; y < B; y++) { -        if (l != L) { -            get_pixel (page, L - 1, y, p); -            red   += p[0] * (L - l); -            green += p[1] * (L - l); -            blue  += p[2] * (L - l); -        } - -        if (r != R) { -            get_pixel (page, R, y, p); -            red   += p[0] * (r - R); -            green += p[1] * (r - R); -            blue  += p[2] * (r - R); -        } -    } -   -    /* Add the corner pixels */ -    if (l != L && t != T) { -        get_pixel (page, L - 1, T - 1, p); -        red   += p[0] * (L - l)*(T - t); -        green += p[1] * (L - l)*(T - t); -        blue  += p[2] * (L - l)*(T - t); -    } -    if (r != R && t != T) { -        get_pixel (page, R, T - 1, p); -        red   += p[0] * (r - R)*(T - t); -        green += p[1] * (r - R)*(T - t); -        blue  += p[2] * (r - R)*(T - t); -    } -    if (r != R && b != B) { -        get_pixel (page, R, B, p); -        red   += p[0] * (r - R)*(b - B); -        green += p[1] * (r - R)*(b - B); -        blue  += p[2] * (r - R)*(b - B); -    } -    if (l != L && b != B) { -        get_pixel (page, L - 1, B, p); -        red   += p[0] * (L - l)*(b - B); -        green += p[1] * (L - l)*(b - B); -        blue  += p[2] * (L - l)*(b - B); -    } - -    /* Scale pixel values and clamp in range [0, 255] */ -    scale = 1.0 / ((r - l) * (b - t)); -    pixel[0] = (guchar)(red * scale + 0.5); -    pixel[1] = (guchar)(green * scale + 0.5); -    pixel[2] = (guchar)(blue * scale + 0.5); +static gint page_view_get_preview_width (PageView* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->width - (self->priv->border_width * 2); +	return result;  } -static void -update_preview (Page *page, -                GdkPixbuf **output_image, gint output_width, gint output_height, -                ScanDirection scan_direction, gint old_scan_line, gint scan_line) -{ -    guchar *output; -    gint input_width, input_height; -    gint output_rowstride, output_n_channels; -    gint x, y; -    gint L, R, T, B; - -    input_width = page_get_width (page); -    input_height = page_get_height (page); -   -    /* Create new image if one does not exist or has changed size */ -    if (!*output_image || -        gdk_pixbuf_get_width (*output_image) != output_width || -        gdk_pixbuf_get_height (*output_image) != output_height) { -        if (*output_image) -            g_object_unref (*output_image);  -        *output_image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, -                                        FALSE, -                                        8, -                                        output_width, -                                        output_height); - -        /* Update entire image */ -        L = 0; -        R = output_width - 1; -        T = 0; -        B = output_height - 1; -    } -    /* Otherwise only update changed area */ -    else { -        switch (scan_direction) { -        case TOP_TO_BOTTOM: -            L = 0; -            R = output_width - 1; -            T = (gint)((double)old_scan_line * output_height / input_height); -            B = (gint)((double)scan_line * output_height / input_height + 0.5); -            break; -        case LEFT_TO_RIGHT: -            L = (gint)((double)old_scan_line * output_width / input_width); -            R = (gint)((double)scan_line * output_width / input_width + 0.5); -            T = 0; -            B = output_height - 1; -            break; -        case BOTTOM_TO_TOP: -            L = 0; -            R = output_width - 1; -            T = (gint)((double)(input_height - scan_line) * output_height / input_height); -            B = (gint)((double)(input_height - old_scan_line) * output_height / input_height + 0.5); -            break; -        case RIGHT_TO_LEFT: -            L = (gint)((double)(input_width - scan_line) * output_width / input_width); -            R = (gint)((double)(input_width - old_scan_line) * output_width / input_width + 0.5); -            T = 0; -            B = output_height - 1; -            break; -        default: -            L = R = B = T = 0; -            break; -        } -    } - -    /* FIXME: There's an off by one error in there somewhere... */ -    if (R >= output_width) -        R = output_width - 1; -    if (B >= output_height) -        B = output_height - 1; - -    g_return_if_fail (L >= 0); -    g_return_if_fail (R < output_width); -    g_return_if_fail (T >= 0); -    g_return_if_fail (B < output_height); -    g_return_if_fail (*output_image != NULL); -   -    output = gdk_pixbuf_get_pixels (*output_image); -    output_rowstride = gdk_pixbuf_get_rowstride (*output_image); -    output_n_channels = gdk_pixbuf_get_n_channels (*output_image); -   -    if (!page_has_data (page)) { -        for (x = L; x <= R; x++) -            for (y = T; y <= B; y++) { -                guchar *pixel; -                pixel = output + output_rowstride * y + x * output_n_channels; -                pixel[0] = pixel[1] = pixel[2] = 0xFF; -            } -        return;  -    } - -    /* Update changed area */ -    for (x = L; x <= R; x++) { -        double l, r; - -        l = (double)x * input_width / output_width; -        r = (double)(x + 1) * input_width / output_width; - -        for (y = T; y <= B; y++) { -            double t, b; - -            t = (double)y * input_height / output_height; -            b = (double)(y + 1) * input_height / output_height; - -            set_pixel (page, -                       l, r, t, b, -                       output + output_rowstride * y + x * output_n_channels); -        } -    } +static gint page_view_get_preview_height (PageView* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->height - (self->priv->border_width * 2); +	return result;  } -static gint -get_preview_width (PageView *view) -{ -    return view->priv->width - view->priv->border_width * 2; +static void page_view_update_page_view (PageView* self) { +	gint old_scan_line; +	gint _tmp0_; +	gint scan_line; +	ScanDirection _tmp1_; +	ScanDirection left_steps; +	gboolean _tmp2_ = FALSE; +	ScanDirection _tmp3_; +	gint _tmp4_; +	gint _tmp5_; +	ScanDirection _tmp6_; +	g_return_if_fail (self != NULL); +	if (!self->priv->update_image) { +		return; +	} +	old_scan_line = self->priv->scan_line; +	_tmp0_ = page_get_scan_line (self->priv->page); +	scan_line = _tmp0_; +	_tmp1_ = page_get_scan_direction (self->priv->page); +	left_steps = self->priv->scan_direction - _tmp1_; +	if (left_steps != 0) { +		_tmp2_ = self->priv->image != NULL; +	} else { +		_tmp2_ = FALSE; +	} +	if (_tmp2_) { +		_g_object_unref0 (self->priv->image); +		self->priv->image = NULL; +	} +	_tmp3_ = page_get_scan_direction (self->priv->page); +	self->priv->scan_direction = _tmp3_; +	_tmp4_ = page_view_get_preview_width (self); +	_tmp5_ = page_view_get_preview_height (self); +	_tmp6_ = page_get_scan_direction (self->priv->page); +	page_view_update_preview (self, self->priv->page, &self->priv->image, _tmp4_, _tmp5_, _tmp6_, old_scan_line, scan_line); +	self->priv->update_image = FALSE; +	self->priv->scan_line = scan_line;  } -static gint -get_preview_height (PageView *view) -{ -    return view->priv->height - view->priv->border_width * 2; +static gint page_view_page_to_screen_x (PageView* self, gint x) { +	gint result = 0; +	gint _tmp0_; +	gint _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = page_view_get_preview_width (self); +	_tmp1_ = page_get_width (self->priv->page); +	result = (gint) (((((gdouble) x) * _tmp0_) / _tmp1_) + 0.5); +	return result;  } -static void -update_page_view (PageView *view) -{ -    gint old_scan_line, scan_line, left_steps; +static gint page_view_page_to_screen_y (PageView* self, gint y) { +	gint result = 0; +	gint _tmp0_; +	gint _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = page_view_get_preview_height (self); +	_tmp1_ = page_get_height (self->priv->page); +	result = (gint) (((((gdouble) y) * _tmp0_) / _tmp1_) + 0.5); +	return result; +} + -    if (!view->priv->update_image) -        return; +static gint page_view_screen_to_page_x (PageView* self, gint x) { +	gint result = 0; +	gint _tmp0_; +	gint _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = page_get_width (self->priv->page); +	_tmp1_ = page_view_get_preview_width (self); +	result = (gint) (((((gdouble) x) * _tmp0_) / _tmp1_) + 0.5); +	return result; +} -    old_scan_line = view->priv->scan_line; -    scan_line = page_get_scan_line (view->priv->page); -    /* Delete old image if scan direction changed */ -    left_steps = view->priv->scan_direction - page_get_scan_direction (view->priv->page); -    if (left_steps && view->priv->image) { -        g_object_unref (view->priv->image); -        view->priv->image = NULL; -    } -    view->priv->scan_direction = page_get_scan_direction (view->priv->page); +static gint page_view_screen_to_page_y (PageView* self, gint y) { +	gint result = 0; +	gint _tmp0_; +	gint _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = page_get_height (self->priv->page); +	_tmp1_ = page_view_get_preview_height (self); +	result = (gint) (((((gdouble) y) * _tmp0_) / _tmp1_) + 0.5); +	return result; +} -    update_preview (view->priv->page, -                    &view->priv->image, -                    get_preview_width (view), -                    get_preview_height (view), -                    page_get_scan_direction (view->priv->page), old_scan_line, scan_line); -    view->priv->update_image = FALSE; -    view->priv->scan_line = scan_line; +static CropLocation page_view_get_crop_location (PageView* self, gint x, gint y) { +	CropLocation result = 0; +	gboolean _tmp0_; +	gint cx = 0; +	gint cy = 0; +	gint cw = 0; +	gint ch = 0; +	gint _tmp1_; +	gint _tmp2_; +	gint _tmp3_; +	gint _tmp4_; +	gint _tmp5_; +	gint dx; +	gint _tmp6_; +	gint dy; +	gint _tmp7_; +	gint dw; +	gint _tmp8_; +	gint dh; +	gint ix; +	gint iy; +	gboolean _tmp9_ = FALSE; +	gboolean _tmp10_ = FALSE; +	gboolean _tmp11_ = FALSE; +	gchar* _tmp12_ = NULL; +	gchar* name; +	gint crop_border; +	gboolean _tmp13_ = FALSE; +	gboolean _tmp14_ = FALSE; +	gboolean _tmp15_ = FALSE; +	gboolean _tmp16_ = FALSE; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = page_has_crop (self->priv->page); +	if (!_tmp0_) { +		result = 0; +		return result; +	} +	page_get_crop (self->priv->page, &_tmp1_, &_tmp2_, &_tmp3_, &_tmp4_); +	cx = _tmp1_; +	cy = _tmp2_; +	cw = _tmp3_; +	ch = _tmp4_; +	_tmp5_ = page_view_page_to_screen_x (self, cx); +	dx = _tmp5_; +	_tmp6_ = page_view_page_to_screen_y (self, cy); +	dy = _tmp6_; +	_tmp7_ = page_view_page_to_screen_x (self, cw); +	dw = _tmp7_; +	_tmp8_ = page_view_page_to_screen_y (self, ch); +	dh = _tmp8_; +	ix = x - dx; +	iy = y - dy; +	if (ix < 0) { +		_tmp11_ = TRUE; +	} else { +		_tmp11_ = ix > dw; +	} +	if (_tmp11_) { +		_tmp10_ = TRUE; +	} else { +		_tmp10_ = iy < 0; +	} +	if (_tmp10_) { +		_tmp9_ = TRUE; +	} else { +		_tmp9_ = iy > dh; +	} +	if (_tmp9_) { +		result = CROP_LOCATION_NONE; +		return result; +	} +	_tmp12_ = page_get_named_crop (self->priv->page); +	name = _tmp12_; +	if (name != NULL) { +		result = CROP_LOCATION_MIDDLE; +		_g_free0 (name); +		return result; +	} +	crop_border = 20; +	if (dw < (crop_border * 3)) { +		crop_border = dw / 3; +	} +	if (dh < (crop_border * 3)) { +		crop_border = dh / 3; +	} +	if (ix < crop_border) { +		_tmp13_ = iy < crop_border; +	} else { +		_tmp13_ = FALSE; +	} +	if (_tmp13_) { +		result = CROP_LOCATION_TOP_LEFT; +		_g_free0 (name); +		return result; +	} +	if (ix > (dw - crop_border)) { +		_tmp14_ = iy < crop_border; +	} else { +		_tmp14_ = FALSE; +	} +	if (_tmp14_) { +		result = CROP_LOCATION_TOP_RIGHT; +		_g_free0 (name); +		return result; +	} +	if (ix < crop_border) { +		_tmp15_ = iy > (dh - crop_border); +	} else { +		_tmp15_ = FALSE; +	} +	if (_tmp15_) { +		result = CROP_LOCATION_BOTTOM_LEFT; +		_g_free0 (name); +		return result; +	} +	if (ix > (dw - crop_border)) { +		_tmp16_ = iy > (dh - crop_border); +	} else { +		_tmp16_ = FALSE; +	} +	if (_tmp16_) { +		result = CROP_LOCATION_BOTTOM_RIGHT; +		_g_free0 (name); +		return result; +	} +	if (ix < crop_border) { +		result = CROP_LOCATION_LEFT; +		_g_free0 (name); +		return result; +	} +	if (ix > (dw - crop_border)) { +		result = CROP_LOCATION_RIGHT; +		_g_free0 (name); +		return result; +	} +	if (iy < crop_border) { +		result = CROP_LOCATION_TOP; +		_g_free0 (name); +		return result; +	} +	if (iy > (dh - crop_border)) { +		result = CROP_LOCATION_BOTTOM; +		_g_free0 (name); +		return result; +	} +	result = CROP_LOCATION_MIDDLE; +	_g_free0 (name); +	return result;  } -static gint -page_to_screen_x (PageView *view, gint x) -{ -    return (double) x * get_preview_width (view) / page_get_width (view->priv->page) + 0.5; +void page_view_button_press (PageView* self, gint x, gint y) { +	CropLocation location = 0; +	CropLocation _tmp0_; +	g_return_if_fail (self != NULL); +	_tmp0_ = page_view_get_crop_location (self, x, y); +	location = _tmp0_; +	if (location != CROP_LOCATION_NONE) { +		gint _tmp1_; +		gint _tmp2_; +		gint _tmp3_; +		gint _tmp4_; +		self->priv->crop_location = location; +		self->priv->selected_crop_px = (gdouble) x; +		self->priv->selected_crop_py = (gdouble) y; +		page_get_crop (self->priv->page, &_tmp1_, &_tmp2_, &_tmp3_, &_tmp4_); +		self->priv->selected_crop_x = _tmp1_; +		self->priv->selected_crop_y = _tmp2_; +		self->priv->selected_crop_w = _tmp3_; +		self->priv->selected_crop_h = _tmp4_; +	}  } -static gint -page_to_screen_y (PageView *view, gint y) -{ -    return (double) y * get_preview_height (view) / page_get_height (view->priv->page) + 0.5;     +void page_view_motion (PageView* self, gint x, gint y) { +	CropLocation _tmp0_; +	CropLocation location; +	GdkCursorType cursor = 0; +	gint _tmp1_; +	gint pw; +	gint _tmp2_; +	gint ph; +	gint cx = 0; +	gint cy = 0; +	gint cw = 0; +	gint ch = 0; +	gint _tmp3_; +	gint _tmp4_; +	gint _tmp5_; +	gint _tmp6_; +	gint _tmp7_; +	gint dx; +	gint _tmp8_; +	gint dy; +	gint new_x; +	gint new_y; +	gint new_w; +	gint new_h; +	gint _tmp9_; +	gint min_size; +	gboolean _tmp10_ = FALSE; +	gboolean _tmp11_ = FALSE; +	gboolean _tmp12_ = FALSE; +	gboolean _tmp13_ = FALSE; +	gboolean _tmp14_ = FALSE; +	gboolean _tmp15_ = FALSE; +	gboolean _tmp16_ = FALSE; +	gboolean _tmp17_ = FALSE; +	gboolean _tmp18_ = FALSE; +	gboolean _tmp19_ = FALSE; +	gboolean _tmp20_ = FALSE; +	gboolean _tmp21_ = FALSE; +	gboolean _tmp22_ = FALSE; +	gboolean _tmp23_ = FALSE; +	gboolean _tmp24_ = FALSE; +	gboolean _tmp25_ = FALSE; +	gboolean _tmp26_ = FALSE; +	g_return_if_fail (self != NULL); +	_tmp0_ = page_view_get_crop_location (self, x, y); +	location = _tmp0_; +	switch (location) { +		case CROP_LOCATION_MIDDLE: +		{ +			cursor = GDK_HAND1; +			break; +		} +		case CROP_LOCATION_TOP: +		{ +			cursor = GDK_TOP_SIDE; +			break; +		} +		case CROP_LOCATION_BOTTOM: +		{ +			cursor = GDK_BOTTOM_SIDE; +			break; +		} +		case CROP_LOCATION_LEFT: +		{ +			cursor = GDK_LEFT_SIDE; +			break; +		} +		case CROP_LOCATION_RIGHT: +		{ +			cursor = GDK_RIGHT_SIDE; +			break; +		} +		case CROP_LOCATION_TOP_LEFT: +		{ +			cursor = GDK_TOP_LEFT_CORNER; +			break; +		} +		case CROP_LOCATION_TOP_RIGHT: +		{ +			cursor = GDK_TOP_RIGHT_CORNER; +			break; +		} +		case CROP_LOCATION_BOTTOM_LEFT: +		{ +			cursor = GDK_BOTTOM_LEFT_CORNER; +			break; +		} +		case CROP_LOCATION_BOTTOM_RIGHT: +		{ +			cursor = GDK_BOTTOM_RIGHT_CORNER; +			break; +		} +		default: +		{ +			cursor = GDK_ARROW; +			break; +		} +	} +	if (self->priv->crop_location == CROP_LOCATION_NONE) { +		self->priv->cursor = cursor; +		return; +	} +	_tmp1_ = page_get_width (self->priv->page); +	pw = _tmp1_; +	_tmp2_ = page_get_height (self->priv->page); +	ph = _tmp2_; +	page_get_crop (self->priv->page, &_tmp3_, &_tmp4_, &_tmp5_, &_tmp6_); +	cx = _tmp3_; +	cy = _tmp4_; +	cw = _tmp5_; +	ch = _tmp6_; +	_tmp7_ = page_view_screen_to_page_x (self, x - ((gint) self->priv->selected_crop_px)); +	dx = _tmp7_; +	_tmp8_ = page_view_screen_to_page_y (self, y - ((gint) self->priv->selected_crop_py)); +	dy = _tmp8_; +	new_x = self->priv->selected_crop_x; +	new_y = self->priv->selected_crop_y; +	new_w = self->priv->selected_crop_w; +	new_h = self->priv->selected_crop_h; +	_tmp9_ = page_view_screen_to_page_x (self, 15); +	min_size = _tmp9_; +	if (self->priv->crop_location == CROP_LOCATION_TOP_LEFT) { +		_tmp11_ = TRUE; +	} else { +		_tmp11_ = self->priv->crop_location == CROP_LOCATION_LEFT; +	} +	if (_tmp11_) { +		_tmp10_ = TRUE; +	} else { +		_tmp10_ = self->priv->crop_location == CROP_LOCATION_BOTTOM_LEFT; +	} +	if (_tmp10_) { +		if (dx > (new_w - min_size)) { +			dx = new_w - min_size; +		} +		if ((new_x + dx) < 0) { +			dx = -new_x; +		} +	} +	if (self->priv->crop_location == CROP_LOCATION_TOP_LEFT) { +		_tmp13_ = TRUE; +	} else { +		_tmp13_ = self->priv->crop_location == CROP_LOCATION_TOP; +	} +	if (_tmp13_) { +		_tmp12_ = TRUE; +	} else { +		_tmp12_ = self->priv->crop_location == CROP_LOCATION_TOP_RIGHT; +	} +	if (_tmp12_) { +		if (dy > (new_h - min_size)) { +			dy = new_h - min_size; +		} +		if ((new_y + dy) < 0) { +			dy = -new_y; +		} +	} +	if (self->priv->crop_location == CROP_LOCATION_TOP_RIGHT) { +		_tmp15_ = TRUE; +	} else { +		_tmp15_ = self->priv->crop_location == CROP_LOCATION_RIGHT; +	} +	if (_tmp15_) { +		_tmp14_ = TRUE; +	} else { +		_tmp14_ = self->priv->crop_location == CROP_LOCATION_BOTTOM_RIGHT; +	} +	if (_tmp14_) { +		if (dx < (min_size - new_w)) { +			dx = min_size - new_w; +		} +		if (((new_x + new_w) + dx) > pw) { +			dx = (pw - new_x) - new_w; +		} +	} +	if (self->priv->crop_location == CROP_LOCATION_BOTTOM_LEFT) { +		_tmp17_ = TRUE; +	} else { +		_tmp17_ = self->priv->crop_location == CROP_LOCATION_BOTTOM; +	} +	if (_tmp17_) { +		_tmp16_ = TRUE; +	} else { +		_tmp16_ = self->priv->crop_location == CROP_LOCATION_BOTTOM_RIGHT; +	} +	if (_tmp16_) { +		if (dy < (min_size - new_h)) { +			dy = min_size - new_h; +		} +		if (((new_y + new_h) + dy) > ph) { +			dy = (ph - new_y) - new_h; +		} +	} +	if (self->priv->crop_location == CROP_LOCATION_MIDDLE) { +		if (((new_x + dx) + new_w) > pw) { +			dx = (pw - new_x) - new_w; +		} +		if ((new_x + dx) < 0) { +			dx = -new_x; +		} +		if (((new_y + dy) + new_h) > ph) { +			dy = (ph - new_y) - new_h; +		} +		if ((new_y + dy) < 0) { +			dy = -new_y; +		} +	} +	if (self->priv->crop_location == CROP_LOCATION_MIDDLE) { +		new_x = new_x + dx; +		new_y = new_y + dy; +	} +	if (self->priv->crop_location == CROP_LOCATION_TOP_LEFT) { +		_tmp19_ = TRUE; +	} else { +		_tmp19_ = self->priv->crop_location == CROP_LOCATION_LEFT; +	} +	if (_tmp19_) { +		_tmp18_ = TRUE; +	} else { +		_tmp18_ = self->priv->crop_location == CROP_LOCATION_BOTTOM_LEFT; +	} +	if (_tmp18_) { +		new_x = new_x + dx; +		new_w = new_w - dx; +	} +	if (self->priv->crop_location == CROP_LOCATION_TOP_LEFT) { +		_tmp21_ = TRUE; +	} else { +		_tmp21_ = self->priv->crop_location == CROP_LOCATION_TOP; +	} +	if (_tmp21_) { +		_tmp20_ = TRUE; +	} else { +		_tmp20_ = self->priv->crop_location == CROP_LOCATION_TOP_RIGHT; +	} +	if (_tmp20_) { +		new_y = new_y + dy; +		new_h = new_h - dy; +	} +	if (self->priv->crop_location == CROP_LOCATION_TOP_RIGHT) { +		_tmp23_ = TRUE; +	} else { +		_tmp23_ = self->priv->crop_location == CROP_LOCATION_RIGHT; +	} +	if (_tmp23_) { +		_tmp22_ = TRUE; +	} else { +		_tmp22_ = self->priv->crop_location == CROP_LOCATION_BOTTOM_RIGHT; +	} +	if (_tmp22_) { +		new_w = new_w + dx; +	} +	if (self->priv->crop_location == CROP_LOCATION_BOTTOM_LEFT) { +		_tmp25_ = TRUE; +	} else { +		_tmp25_ = self->priv->crop_location == CROP_LOCATION_BOTTOM; +	} +	if (_tmp25_) { +		_tmp24_ = TRUE; +	} else { +		_tmp24_ = self->priv->crop_location == CROP_LOCATION_BOTTOM_RIGHT; +	} +	if (_tmp24_) { +		new_h = new_h + dy; +	} +	page_move_crop (self->priv->page, new_x, new_y); +	if (new_w != cw) { +		_tmp26_ = TRUE; +	} else { +		_tmp26_ = new_h != ch; +	} +	if (_tmp26_) { +		page_set_custom_crop (self->priv->page, new_w, new_h); +	}  } -static gint -screen_to_page_x (PageView *view, gint x) -{ -    return (double) x * page_get_width (view->priv->page) / get_preview_width (view) + 0.5; +void page_view_button_release (PageView* self, gint x, gint y) { +	g_return_if_fail (self != NULL); +	self->priv->crop_location = CROP_LOCATION_NONE; +	g_signal_emit_by_name (self, "changed");  } -static gint -screen_to_page_y (PageView *view, gint y) -{ -    return (double) y * page_get_height (view->priv->page) / get_preview_height (view) + 0.5; +GdkCursorType page_view_get_cursor (PageView* self) { +	GdkCursorType result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->cursor; +	return result;  } -static CropLocation -get_crop_location (PageView *view, gint x, gint y) -{ -    gint cx, cy, cw, ch; -    gint dx, dy, dw, dh; -    gint ix, iy; -    gint crop_border = 20; -    gchar *name; - -    if (!page_has_crop (view->priv->page)) -        return 0; - -    page_get_crop (view->priv->page, &cx, &cy, &cw, &ch); -    dx = page_to_screen_x (view, cx); -    dy = page_to_screen_y (view, cy); -    dw = page_to_screen_x (view, cw); -    dh = page_to_screen_y (view, ch); -    ix = x - dx; -    iy = y - dy; - -    if (ix < 0 || ix > dw || iy < 0 || iy > dh) -        return CROP_NONE; - -    /* Can't resize named crops */ -    name = page_get_named_crop (view->priv->page); -    if (name != NULL) { -        g_free (name); -        return CROP_MIDDLE; -    } - -    /* Adjust borders so can select */ -    if (dw < crop_border * 3) -        crop_border = dw / 3; -    if (dh < crop_border * 3) -        crop_border = dh / 3; - -    /* Top left */ -    if (ix < crop_border && iy < crop_border) -        return CROP_TOP_LEFT; -    /* Top right */ -    if (ix > dw - crop_border && iy < crop_border) -        return CROP_TOP_RIGHT; -    /* Bottom left */ -    if (ix < crop_border && iy > dh - crop_border) -        return CROP_BOTTOM_LEFT; -    /* Bottom right */ -    if (ix > dw - crop_border && iy > dh - crop_border) -        return CROP_BOTTOM_RIGHT; - -    /* Left */ -    if (ix < crop_border) -        return CROP_LEFT; -    /* Right */ -    if (ix > dw - crop_border) -        return CROP_RIGHT; -    /* Top */ -    if (iy < crop_border) -        return CROP_TOP; -    /* Bottom */ -    if (iy > dh - crop_border) -        return CROP_BOTTOM; - -    /* In the middle */ -    return CROP_MIDDLE; +static gboolean page_view_animation_cb (PageView* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	self->priv->animate_segment = (self->priv->animate_segment + 1) % self->priv->animate_n_segments; +	g_signal_emit_by_name (self, "changed"); +	result = TRUE; +	return result;  } -void -page_view_button_press (PageView *view, gint x, gint y) -{ -    CropLocation location; - -    g_return_if_fail (view != NULL); - -    /* See if selecting crop */ -    location = get_crop_location (view, x, y);; -    if (location != CROP_NONE) { -        view->priv->crop_location = location; -        view->priv->selected_crop_px = x; -        view->priv->selected_crop_py = y; -        page_get_crop (view->priv->page, -                       &view->priv->selected_crop_x, -                       &view->priv->selected_crop_y, -                       &view->priv->selected_crop_w, -                       &view->priv->selected_crop_h); -    } +static gboolean _page_view_animation_cb_gsource_func (gpointer self) { +	gboolean result; +	result = page_view_animation_cb (self); +	return result;  } -void -page_view_motion (PageView *view, gint x, gint y) -{ -    gint pw, ph; -    gint cx, cy, cw, ch, dx, dy; -    gint new_x, new_y, new_w, new_h; -    CropLocation location; -    gint cursor; -    gint min_size; -   -    min_size = screen_to_page_x (view, 15); - -    g_return_if_fail (view != NULL); -   -    location = get_crop_location (view, x, y); -    switch (location) { -    case CROP_MIDDLE: -        cursor = GDK_HAND1; -        break; -    case CROP_TOP: -        cursor = GDK_TOP_SIDE; -        break; -    case CROP_BOTTOM: -        cursor = GDK_BOTTOM_SIDE; -        break; -    case CROP_LEFT: -        cursor = GDK_LEFT_SIDE; -        break; -    case CROP_RIGHT: -        cursor = GDK_RIGHT_SIDE; -        break; -    case CROP_TOP_LEFT: -        cursor = GDK_TOP_LEFT_CORNER; -        break; -    case CROP_TOP_RIGHT: -        cursor = GDK_TOP_RIGHT_CORNER; -        break; -    case CROP_BOTTOM_LEFT: -        cursor = GDK_BOTTOM_LEFT_CORNER; -        break; -    case CROP_BOTTOM_RIGHT: -        cursor = GDK_BOTTOM_RIGHT_CORNER; -        break; -    default: -        cursor = GDK_ARROW; -        break; -    } - -    if (view->priv->crop_location == CROP_NONE) { -        view->priv->cursor = cursor; -        return; -    } - -    /* Move the crop */   -    pw = page_get_width (view->priv->page); -    ph = page_get_height (view->priv->page); -    page_get_crop (view->priv->page, &cx, &cy, &cw, &ch); - -    dx = screen_to_page_x (view, x - view->priv->selected_crop_px); -    dy = screen_to_page_y (view, y - view->priv->selected_crop_py); - -    new_x = view->priv->selected_crop_x; -    new_y = view->priv->selected_crop_y; -    new_w = view->priv->selected_crop_w; -    new_h = view->priv->selected_crop_h; - -    /* Limit motion to remain within page and minimum crop size */ -    if (view->priv->crop_location == CROP_TOP_LEFT || -        view->priv->crop_location == CROP_LEFT || -        view->priv->crop_location == CROP_BOTTOM_LEFT) { -        if (dx > new_w - min_size) -            dx = new_w - min_size; -        if (new_x + dx < 0) -            dx = -new_x; -    } -    if (view->priv->crop_location == CROP_TOP_LEFT || -        view->priv->crop_location == CROP_TOP || -        view->priv->crop_location == CROP_TOP_RIGHT) { -        if (dy > new_h - min_size) -            dy = new_h - min_size; -        if (new_y + dy < 0) -            dy = -new_y; -    } -      -    if (view->priv->crop_location == CROP_TOP_RIGHT || -        view->priv->crop_location == CROP_RIGHT || -        view->priv->crop_location == CROP_BOTTOM_RIGHT) { -        if (dx < min_size - new_w) -            dx = min_size - new_w; -        if (new_x + new_w + dx > pw) -            dx = pw - new_x - new_w; -    } -    if (view->priv->crop_location == CROP_BOTTOM_LEFT || -        view->priv->crop_location == CROP_BOTTOM || -        view->priv->crop_location == CROP_BOTTOM_RIGHT) { -        if (dy < min_size - new_h) -            dy = min_size - new_h; -        if (new_y + new_h + dy > ph) -            dy = ph - new_y - new_h; -    } -    if (view->priv->crop_location == CROP_MIDDLE) { -        if (new_x + dx + new_w > pw) -            dx = pw - new_x - new_w; -        if (new_x + dx < 0) -            dx = -new_x; -        if (new_y + dy + new_h > ph) -            dy = ph - new_y - new_h; -        if (new_y + dy  < 0) -            dy = -new_y; -    } - -    /* Move crop */ -    if (view->priv->crop_location == CROP_MIDDLE) { -        new_x += dx; -        new_y += dy;           -    } -    if (view->priv->crop_location == CROP_TOP_LEFT || -        view->priv->crop_location == CROP_LEFT || -        view->priv->crop_location == CROP_BOTTOM_LEFT)  -    { -        new_x += dx; -        new_w -= dx; -    } -    if (view->priv->crop_location == CROP_TOP_LEFT || -        view->priv->crop_location == CROP_TOP || -        view->priv->crop_location == CROP_TOP_RIGHT) { -        new_y += dy; -        new_h -= dy; -    } -  -    if (view->priv->crop_location == CROP_TOP_RIGHT || -        view->priv->crop_location == CROP_RIGHT || -        view->priv->crop_location == CROP_BOTTOM_RIGHT) { -        new_w += dx; -    } -    if (view->priv->crop_location == CROP_BOTTOM_LEFT || -        view->priv->crop_location == CROP_BOTTOM || -        view->priv->crop_location == CROP_BOTTOM_RIGHT) { -        new_h += dy; -    } - -    page_move_crop (view->priv->page, new_x, new_y); - -    /* If reshaped crop, must be a custom crop */ -    if (new_w != cw || new_h != ch) -        page_set_custom_crop (view->priv->page, new_w, new_h); +static void page_view_update_animation (PageView* self) { +	gboolean animate = FALSE; +	gboolean is_animating = FALSE; +	gboolean _tmp0_ = FALSE; +	gboolean _tmp1_; +	g_return_if_fail (self != NULL); +	_tmp1_ = page_is_scanning (self->priv->page); +	if (_tmp1_) { +		gboolean _tmp2_; +		_tmp2_ = page_has_data (self->priv->page); +		_tmp0_ = !_tmp2_; +	} else { +		_tmp0_ = FALSE; +	} +	animate = _tmp0_; +	is_animating = self->priv->animate_timeout != ((guint) 0); +	if (animate == is_animating) { +		return; +	} +	if (animate) { +		self->priv->animate_segment = 0; +		if (self->priv->animate_timeout == ((guint) 0)) { +			guint _tmp3_; +			_tmp3_ = g_timeout_add_full (G_PRIORITY_DEFAULT, (guint) 150, _page_view_animation_cb_gsource_func, page_view_ref (self), page_view_unref); +			self->priv->animate_timeout = _tmp3_; +		} +	} else { +		if (self->priv->animate_timeout != ((guint) 0)) { +			g_source_remove (self->priv->animate_timeout); +		} +		self->priv->animate_timeout = (guint) 0; +	}  } -void -page_view_button_release (PageView *view, gint x, gint y) -{ -    g_return_if_fail (view != NULL); +void page_view_render (PageView* self, cairo_t* context) { +	gint _tmp0_; +	gint w; +	gint _tmp1_; +	gint h; +	gboolean _tmp2_ = FALSE; +	gboolean _tmp3_; +	gboolean _tmp11_ = FALSE; +	gboolean _tmp12_; +	gboolean _tmp20_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (context != NULL); +	page_view_update_animation (self); +	page_view_update_page_view (self); +	_tmp0_ = page_view_get_preview_width (self); +	w = _tmp0_; +	_tmp1_ = page_view_get_preview_height (self); +	h = _tmp1_; +	cairo_set_line_width (context, (gdouble) 1); +	cairo_translate (context, (gdouble) self->priv->x_offset, (gdouble) self->priv->y_offset); +	cairo_set_source_rgb (context, (gdouble) 0, (gdouble) 0, (gdouble) 0); +	cairo_set_line_width (context, (gdouble) self->priv->border_width); +	cairo_rectangle (context, ((gdouble) self->priv->border_width) / 2, ((gdouble) self->priv->border_width) / 2, (gdouble) (self->priv->width - self->priv->border_width), (gdouble) (self->priv->height - self->priv->border_width)); +	cairo_stroke (context); +	cairo_translate (context, (gdouble) self->priv->border_width, (gdouble) self->priv->border_width); +	gdk_cairo_set_source_pixbuf (context, self->priv->image, (gdouble) 0, (gdouble) 0); +	cairo_paint (context); +	_tmp3_ = page_is_scanning (self->priv->page); +	if (_tmp3_) { +		gboolean _tmp4_; +		_tmp4_ = page_has_data (self->priv->page); +		_tmp2_ = !_tmp4_; +	} else { +		_tmp2_ = FALSE; +	} +	if (_tmp2_) { +		gdouble outer_radius = 0.0; +		gdouble arc; +		gdouble _tmp5_; +		gdouble x; +		gdouble _tmp6_; +		gdouble y; +		gdouble _tmp7_; +		gdouble inner_radius; +		gdouble offset; +		if (w > h) { +			outer_radius = 0.15 * w; +		} else { +			outer_radius = 0.15 * h; +		} +		arc = G_PI / self->priv->animate_n_segments; +		_tmp5_ = sin (arc); +		x = outer_radius * _tmp5_; +		_tmp6_ = cos (arc); +		y = outer_radius * (_tmp6_ - 1.0); +		_tmp7_ = sqrt ((x * x) + (y * y)); +		inner_radius = 0.6 * _tmp7_; +		offset = 0.0; +		{ +			gint i; +			i = 0; +			{ +				gboolean _tmp8_; +				_tmp8_ = TRUE; +				while (TRUE) { +					gdouble _tmp9_; +					gdouble _tmp10_; +					if (!_tmp8_) { +						i++; +						offset = offset + (arc * 2); +					} +					_tmp8_ = FALSE; +					if (!(i < self->priv->animate_n_segments)) { +						break; +					} +					_tmp9_ = sin (offset); +					x = (w / 2) + (outer_radius * _tmp9_); +					_tmp10_ = cos (offset); +					y = (h / 2) - (outer_radius * _tmp10_); +					cairo_arc (context, x, y, inner_radius, (gdouble) 0, 2 * G_PI); +					if (i == self->priv->animate_segment) { +						cairo_set_source_rgb (context, 0.75, 0.75, 0.75); +						cairo_fill_preserve (context); +					} +					cairo_set_source_rgb (context, 0.5, 0.5, 0.5); +					cairo_stroke (context); +				} +			} +		} +	} +	_tmp12_ = page_is_scanning (self->priv->page); +	if (_tmp12_) { +		gint _tmp13_; +		_tmp13_ = page_get_scan_line (self->priv->page); +		_tmp11_ = _tmp13_ > 0; +	} else { +		_tmp11_ = FALSE; +	} +	if (_tmp11_) { +		gint _tmp14_; +		gint scan_line; +		gdouble s = 0.0; +		gdouble x1 = 0.0; +		gdouble y1 = 0.0; +		gdouble x2 = 0.0; +		gdouble y2 = 0.0; +		ScanDirection _tmp15_; +		_tmp14_ = page_get_scan_line (self->priv->page); +		scan_line = _tmp14_; +		_tmp15_ = page_get_scan_direction (self->priv->page); +		switch (_tmp15_) { +			case SCAN_DIRECTION_TOP_TO_BOTTOM: +			{ +				gint _tmp16_; +				_tmp16_ = page_view_page_to_screen_y (self, scan_line); +				s = (gdouble) _tmp16_; +				x1 = (gdouble) 0; +				y1 = s + 0.5; +				x2 = (gdouble) w; +				y2 = s + 0.5; +				break; +			} +			case SCAN_DIRECTION_BOTTOM_TO_TOP: +			{ +				gint _tmp17_; +				_tmp17_ = page_view_page_to_screen_y (self, scan_line); +				s = (gdouble) _tmp17_; +				x1 = (gdouble) 0; +				y1 = (h - s) + 0.5; +				x2 = (gdouble) w; +				y2 = (h - s) + 0.5; +				break; +			} +			case SCAN_DIRECTION_LEFT_TO_RIGHT: +			{ +				gint _tmp18_; +				_tmp18_ = page_view_page_to_screen_x (self, scan_line); +				s = (gdouble) _tmp18_; +				x1 = s + 0.5; +				y1 = (gdouble) 0; +				x2 = s + 0.5; +				y2 = (gdouble) h; +				break; +			} +			case SCAN_DIRECTION_RIGHT_TO_LEFT: +			{ +				gint _tmp19_; +				_tmp19_ = page_view_page_to_screen_x (self, scan_line); +				s = (gdouble) _tmp19_; +				x1 = (w - s) + 0.5; +				y1 = (gdouble) 0; +				x2 = (w - s) + 0.5; +				y2 = (gdouble) h; +				break; +			} +			default: +			{ +				y2 = (gdouble) 0; +				x2 = y2; +				y1 = x2; +				x1 = y1; +				break; +			} +		} +		cairo_move_to (context, x1, y1); +		cairo_line_to (context, x2, y2); +		cairo_set_source_rgb (context, 1.0, 0.0, 0.0); +		cairo_stroke (context); +	} +	_tmp20_ = page_has_crop (self->priv->page); +	if (_tmp20_) { +		gint x = 0; +		gint y = 0; +		gint crop_width = 0; +		gint crop_height = 0; +		gint _tmp21_; +		gint _tmp22_; +		gint _tmp23_; +		gint _tmp24_; +		gint _tmp25_; +		gint dx; +		gint _tmp26_; +		gint dy; +		gint _tmp27_; +		gint dw; +		gint _tmp28_; +		gint dh; +		page_get_crop (self->priv->page, &_tmp21_, &_tmp22_, &_tmp23_, &_tmp24_); +		x = _tmp21_; +		y = _tmp22_; +		crop_width = _tmp23_; +		crop_height = _tmp24_; +		_tmp25_ = page_view_page_to_screen_x (self, x); +		dx = _tmp25_; +		_tmp26_ = page_view_page_to_screen_y (self, y); +		dy = _tmp26_; +		_tmp27_ = page_view_page_to_screen_x (self, crop_width); +		dw = _tmp27_; +		_tmp28_ = page_view_page_to_screen_y (self, crop_height); +		dh = _tmp28_; +		cairo_rectangle (context, (gdouble) 0, (gdouble) 0, (gdouble) w, (gdouble) h); +		cairo_new_sub_path (context); +		cairo_rectangle (context, (gdouble) dx, (gdouble) dy, (gdouble) dw, (gdouble) dh); +		cairo_set_fill_rule (context, CAIRO_FILL_RULE_EVEN_ODD); +		cairo_set_source_rgba (context, 0.25, 0.25, 0.25, 0.2); +		cairo_fill (context); +		cairo_rectangle (context, dx - 1.5, dy - 1.5, (gdouble) (dw + 3), (gdouble) (dh + 3)); +		cairo_set_source_rgb (context, 1.0, 1.0, 1.0); +		cairo_stroke (context); +		cairo_rectangle (context, dx - 0.5, dy - 0.5, (gdouble) (dw + 1), (gdouble) (dh + 1)); +		cairo_set_source_rgb (context, 0.0, 0.0, 0.0); +		cairo_stroke (context); +	} +} + -    /* Complete crop */ -    view->priv->crop_location = CROP_NONE; -    g_signal_emit (view, signals[CHANGED], 0); +void page_view_set_width (PageView* self, gint width) { +	gint _tmp0_; +	gint _tmp1_; +	gint height; +	gboolean _tmp2_ = FALSE; +	g_return_if_fail (self != NULL); +	_tmp0_ = page_get_height (self->priv->page); +	_tmp1_ = page_get_width (self->priv->page); +	height = (gint) ((((gdouble) width) * _tmp0_) / _tmp1_); +	if (self->priv->width == width) { +		_tmp2_ = self->priv->height == height; +	} else { +		_tmp2_ = FALSE; +	} +	if (_tmp2_) { +		return; +	} +	self->priv->width = width; +	self->priv->height = height; +	self->priv->update_image = TRUE; +	g_signal_emit_by_name (self, "size-changed"); +	g_signal_emit_by_name (self, "changed");  } -gint -page_view_get_cursor (PageView *view) -{ -    g_return_val_if_fail (view != NULL, 0); -    return view->priv->cursor; +void page_view_set_height (PageView* self, gint height) { +	gint _tmp0_; +	gint _tmp1_; +	gint width; +	gboolean _tmp2_ = FALSE; +	g_return_if_fail (self != NULL); +	_tmp0_ = page_get_width (self->priv->page); +	_tmp1_ = page_get_height (self->priv->page); +	width = (gint) ((((gdouble) height) * _tmp0_) / _tmp1_); +	if (self->priv->width == width) { +		_tmp2_ = self->priv->height == height; +	} else { +		_tmp2_ = FALSE; +	} +	if (_tmp2_) { +		return; +	} +	self->priv->width = width; +	self->priv->height = height; +	self->priv->update_image = TRUE; +	g_signal_emit_by_name (self, "size-changed"); +	g_signal_emit_by_name (self, "changed");  } -static gboolean -animation_cb (PageView *view) -{ -    view->priv->animate_segment = (view->priv->animate_segment + 1) % view->priv->animate_n_segments; -    g_signal_emit (view, signals[CHANGED], 0); -    return TRUE; +gint page_view_get_width (PageView* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->width; +	return result;  } -static void -update_animation (PageView *view) -{ -    gboolean animate, is_animating; - -    animate = page_is_scanning (view->priv->page) && !page_has_data (view->priv->page); -    is_animating = view->priv->animate_timeout != 0; -    if (animate == is_animating) -        return; -   -    if (animate) { -        view->priv->animate_segment = 0; -        if (view->priv->animate_timeout == 0) -            view->priv->animate_timeout = g_timeout_add (150, (GSourceFunc) animation_cb, view); -    } -    else -    { -        if (view->priv->animate_timeout != 0) -            g_source_remove (view->priv->animate_timeout); -        view->priv->animate_timeout = 0; -    } +gint page_view_get_height (PageView* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->height; +	return result;  } -void -page_view_render (PageView *view, cairo_t *context) -{ -    gint width, height; - -    g_return_if_fail (view != NULL); -    g_return_if_fail (context != NULL); - -    update_animation (view); -    update_page_view (view); - -    width = get_preview_width (view); -    height = get_preview_height (view); - -    cairo_set_line_width (context, 1); -    cairo_translate (context, view->priv->x, view->priv->y); - -    /* Draw page border */ -    cairo_set_source_rgb (context, 0, 0, 0); -    cairo_set_line_width (context, view->priv->border_width); -    cairo_rectangle (context, -                     (double)view->priv->border_width / 2, -                     (double)view->priv->border_width / 2, -                     view->priv->width - view->priv->border_width, -                     view->priv->height - view->priv->border_width); -    cairo_stroke (context); - -    /* Draw image */ -    cairo_translate (context, view->priv->border_width, view->priv->border_width); -    gdk_cairo_set_source_pixbuf (context, view->priv->image, 0, 0); -    cairo_paint (context); - -    /* Draw throbber */ -    if (page_is_scanning (view->priv->page) && !page_has_data (view->priv->page)) { -        gdouble inner_radius, outer_radius, x, y, arc, offset = 0.0; -        gint i; - -        if (width > height) -            outer_radius = 0.15 * width; -        else -            outer_radius = 0.15 * height; -        arc = M_PI / view->priv->animate_n_segments; - -        /* Space circles */ -        x = outer_radius * sin (arc); -        y = outer_radius * (cos (arc) - 1.0); -        inner_radius = 0.6 * sqrt (x*x + y*y); - -        for (i = 0; i < view->priv->animate_n_segments; i++, offset += arc * 2) { -            x = width / 2 + outer_radius * sin (offset); -            y = height / 2 - outer_radius * cos (offset); -            cairo_arc (context, x, y, inner_radius, 0, 2 * M_PI); - -            if (i == view->priv->animate_segment) { -                cairo_set_source_rgb (context, 0.75, 0.75, 0.75); -                cairo_fill_preserve (context); -            } - -            cairo_set_source_rgb (context, 0.5, 0.5, 0.5); -            cairo_stroke (context); -        } -    } - -    /* Draw scan line */ -    if (page_is_scanning (view->priv->page) && page_get_scan_line (view->priv->page) > 0) { -        gint scan_line; -        double s; -        double x1, y1, x2, y2; - -        scan_line = page_get_scan_line (view->priv->page); - -        switch (page_get_scan_direction (view->priv->page)) { -        case TOP_TO_BOTTOM: -            s = page_to_screen_y (view, scan_line); -            x1 = 0; y1 = s + 0.5; -            x2 = width; y2 = s + 0.5; -            break; -        case BOTTOM_TO_TOP: -            s = page_to_screen_y (view, scan_line); -            x1 = 0; y1 = height - s + 0.5; -            x2 = width; y2 = height - s + 0.5; -            break; -        case LEFT_TO_RIGHT: -            s = page_to_screen_x (view, scan_line); -            x1 = s + 0.5; y1 = 0; -            x2 = s + 0.5; y2 = height; -            break; -        case RIGHT_TO_LEFT: -            s = page_to_screen_x (view, scan_line); -            x1 = width - s + 0.5; y1 = 0; -            x2 = width - s + 0.5; y2 = height; -            break; -        default: -            x1 = y1 = x2 = y2 = 0; -            break; -        } - -        cairo_move_to (context, x1, y1); -        cairo_line_to (context, x2, y2); -        cairo_set_source_rgb (context, 1.0, 0.0, 0.0); -        cairo_stroke (context); -    } -     -    /* Draw crop */ -    if (page_has_crop (view->priv->page)) { -        gint x, y, crop_width, crop_height; -        gdouble dx, dy, dw, dh; - -        page_get_crop (view->priv->page, &x, &y, &crop_width, &crop_height); - -        dx = page_to_screen_x (view, x); -        dy = page_to_screen_y (view, y); -        dw = page_to_screen_x (view, crop_width); -        dh = page_to_screen_y (view, crop_height); -         -        /* Shade out cropped area */ -        cairo_rectangle (context, -                         0, 0, -                         width, height); -        cairo_new_sub_path (context); -        cairo_rectangle (context, dx, dy, dw, dh); -        cairo_set_fill_rule (context, CAIRO_FILL_RULE_EVEN_ODD); -        cairo_set_source_rgba (context, 0.25, 0.25, 0.25, 0.2); -        cairo_fill (context); -         -        /* Show new edge */ -        cairo_rectangle (context, dx - 1.5, dy - 1.5, dw + 3, dh + 3); -        cairo_set_source_rgb (context, 1.0, 1.0, 1.0); -        cairo_stroke (context); -        cairo_rectangle (context, dx - 0.5, dy - 0.5, dw + 1, dh + 1); -        cairo_set_source_rgb (context, 0.0, 0.0, 0.0); -        cairo_stroke (context); -    } +static void page_view_page_pixels_changed_cb (PageView* self, Page* p) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (p != NULL); +	self->priv->update_image = TRUE; +	g_signal_emit_by_name (self, "changed");  } -void -page_view_set_width (PageView *view, gint width) -{ -    gint height; +static void page_view_page_size_changed_cb (PageView* self, Page* p) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (p != NULL); +	self->priv->update_image = TRUE; +	g_signal_emit_by_name (self, "size-changed"); +	g_signal_emit_by_name (self, "changed"); +} -    g_return_if_fail (view != NULL); -    // FIXME: Automatically update when get updated image -    height = (double)width * page_get_height (view->priv->page) / page_get_width (view->priv->page); -    if (view->priv->width == width && view->priv->height == height) -        return; +static void page_view_page_overlay_changed_cb (PageView* self, Page* p) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (p != NULL); +	g_signal_emit_by_name (self, "changed"); +} -    view->priv->width = width; -    view->priv->height = height; -   -    /* Regenerate image */ -    view->priv->update_image = TRUE; -    g_signal_emit (view, signals[SIZE_CHANGED], 0); -    g_signal_emit (view, signals[CHANGED], 0); +static void page_view_scan_direction_changed_cb (PageView* self, Page* p) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (p != NULL); +	self->priv->update_image = TRUE; +	g_signal_emit_by_name (self, "size-changed"); +	g_signal_emit_by_name (self, "changed");  } -void -page_view_set_height (PageView *view, gint height) -{ -    gint width; +static void value_page_view_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} -    g_return_if_fail (view != NULL); -    // FIXME: Automatically update when get updated image -    width = (double)height * page_get_width (view->priv->page) / page_get_height (view->priv->page); -    if (view->priv->width == width && view->priv->height == height) -        return; +static void value_page_view_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		page_view_unref (value->data[0].v_pointer); +	} +} -    view->priv->width = width; -    view->priv->height = height; -   -    /* Regenerate image */ -    view->priv->update_image = TRUE; -    g_signal_emit (view, signals[SIZE_CHANGED], 0);   -    g_signal_emit (view, signals[CHANGED], 0); +static void value_page_view_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = page_view_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	}  } -gint -page_view_get_width (PageView *view) -{ -    g_return_val_if_fail (view != NULL, 0); -    return view->priv->width; +static gpointer value_page_view_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer;  } -gint -page_view_get_height (PageView *view) -{ -    g_return_val_if_fail (view != NULL, 0); -    return view->priv->height; +static gchar* value_page_view_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		PageView* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = page_view_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL;  } -static void -page_pixels_changed_cb (Page *p, PageView *view) -{ -    /* Regenerate image */ -    view->priv->update_image = TRUE; -    g_signal_emit (view, signals[CHANGED], 0); +static gchar* value_page_view_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	PageView** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = page_view_ref (value->data[0].v_pointer); +	} +	return NULL;  } -static void -page_size_changed_cb (Page *p, PageView *view) -{ -    /* Regenerate image */ -    view->priv->update_image = TRUE; -    g_signal_emit (view, signals[SIZE_CHANGED], 0); -    g_signal_emit (view, signals[CHANGED], 0); +GParamSpec* param_spec_page_view (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecPageView* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_PAGE_VIEW), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec);  } -static void -page_overlay_changed_cb (Page *p, PageView *view) -{ -    g_signal_emit (view, signals[CHANGED], 0); +gpointer value_get_page_view (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PAGE_VIEW), NULL); +	return value->data[0].v_pointer;  } -static void -scan_direction_changed_cb (Page *p, PageView *view) -{ -    /* Regenerate image */ -    view->priv->update_image = TRUE; -    g_signal_emit (view, signals[SIZE_CHANGED], 0); -    g_signal_emit (view, signals[CHANGED], 0); +void value_set_page_view (GValue* value, gpointer v_object) { +	PageView* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PAGE_VIEW)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PAGE_VIEW)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		page_view_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		page_view_unref (old); +	}  } -static void -page_view_set_page (PageView *view, Page *page) -{ -    g_return_if_fail (view != NULL); -    g_return_if_fail (view->priv->page == NULL); +void value_take_page_view (GValue* value, gpointer v_object) { +	PageView* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PAGE_VIEW)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PAGE_VIEW)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		page_view_unref (old); +	} +} + -    view->priv->page = g_object_ref (page); -    g_signal_connect (view->priv->page, "pixels-changed", G_CALLBACK (page_pixels_changed_cb), view); -    g_signal_connect (view->priv->page, "size-changed", G_CALLBACK (page_size_changed_cb), view); -    g_signal_connect (view->priv->page, "crop-changed", G_CALLBACK (page_overlay_changed_cb), view); -    g_signal_connect (view->priv->page, "scan-line-changed", G_CALLBACK (page_overlay_changed_cb), view); -    g_signal_connect (view->priv->page, "scan-direction-changed", G_CALLBACK (scan_direction_changed_cb), view); +static void page_view_class_init (PageViewClass * klass) { +	page_view_parent_class = g_type_class_peek_parent (klass); +	PAGE_VIEW_CLASS (klass)->finalize = page_view_finalize; +	g_type_class_add_private (klass, sizeof (PageViewPrivate)); +	g_signal_new ("size_changed", TYPE_PAGE_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("changed", TYPE_PAGE_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);  } -static void -page_view_set_property (GObject      *object, -                        guint         prop_id, -                        const GValue *value, -                        GParamSpec   *pspec) -{ -    PageView *self; - -    self = PAGE_VIEW (object); - -    switch (prop_id) { -    case PROP_PAGE: -        page_view_set_page (self, g_value_get_object (value)); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } +static void page_view_instance_init (PageView * self) { +	self->priv = PAGE_VIEW_GET_PRIVATE (self); +	self->priv->image = NULL; +	self->priv->border_width = 1; +	self->priv->update_image = TRUE; +	self->priv->cursor = GDK_ARROW; +	self->priv->animate_n_segments = 7; +	self->ref_count = 1;  } -static void -page_view_get_property (GObject    *object, -                        guint       prop_id, -                        GValue     *value, -                        GParamSpec *pspec) -{ -    PageView *self; - -    self = PAGE_VIEW (object); - -    switch (prop_id) { -    case PROP_PAGE: -        g_value_set_object (value, self->priv->page); -        break; -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } +static void page_view_finalize (PageView* obj) { +	PageView * self; +	self = PAGE_VIEW (obj); +	_page_unref0 (self->priv->page); +	_g_object_unref0 (self->priv->image);  } -static void -page_view_finalize (GObject *object) -{ -    PageView *view = PAGE_VIEW (object); -    g_object_unref (view->priv->page); -    view->priv->page = NULL; -    if (view->priv->image) -        g_object_unref (view->priv->image); -    view->priv->image = NULL; -    if (view->priv->animate_timeout != 0) -        g_source_remove (view->priv->animate_timeout); -    view->priv->animate_timeout = 0; -    G_OBJECT_CLASS (page_view_parent_class)->finalize (object); +GType page_view_get_type (void) { +	static volatile gsize page_view_type_id__volatile = 0; +	if (g_once_init_enter (&page_view_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_page_view_init, value_page_view_free_value, value_page_view_copy_value, value_page_view_peek_pointer, "p", value_page_view_collect_value, "p", value_page_view_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (PageViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) page_view_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (PageView), 0, (GInstanceInitFunc) page_view_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType page_view_type_id; +		page_view_type_id = g_type_register_fundamental (g_type_fundamental_next (), "PageView", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&page_view_type_id__volatile, page_view_type_id); +	} +	return page_view_type_id__volatile;  } -static void -page_view_class_init (PageViewClass *klass) -{ -    GObjectClass *object_class = G_OBJECT_CLASS (klass); - -    object_class->get_property = page_view_get_property; -    object_class->set_property = page_view_set_property; -    object_class->finalize = page_view_finalize; - -    signals[CHANGED] = -        g_signal_new ("changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageViewClass, changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[SIZE_CHANGED] = -        g_signal_new ("size-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageViewClass, size_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); - -    g_type_class_add_private (klass, sizeof (PageViewPrivate)); - -    g_object_class_install_property (object_class, -                                     PROP_PAGE, -                                     g_param_spec_object ("page", -                                                          "page", -                                                          "Page being rendered", -                                                          PAGE_TYPE, -                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +gpointer page_view_ref (gpointer instance) { +	PageView* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance;  } -static void -page_view_init (PageView *view) -{ -    view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, PAGE_VIEW_TYPE, PageViewPrivate); -    view->priv->update_image = TRUE; -    view->priv->cursor = GDK_ARROW; -    view->priv->border_width = 1; -    view->priv->animate_n_segments = 7; +void page_view_unref (gpointer instance) { +	PageView* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		PAGE_VIEW_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	}  } + + + diff --git a/src/page-view.h b/src/page-view.h deleted file mode 100644 index dd64197..0000000 --- a/src/page-view.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2009 Canonical Ltd. - * Author: Robert Ancell <robert.ancell@canonical.com> - *  - * This program 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 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _PAGE_VIEW_H_ -#define _PAGE_VIEW_H_ - -#include <glib-object.h> -#include <gtk/gtk.h> -#include <cairo.h> -#include "page.h" - -G_BEGIN_DECLS - -#define PAGE_VIEW_TYPE  (page_view_get_type ()) -#define PAGE_VIEW(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PAGE_VIEW_TYPE, PageView)) - - -typedef struct PageViewPrivate PageViewPrivate; - -typedef struct -{ -    GObject          parent_instance; -    PageViewPrivate *priv; -} PageView; - -typedef struct -{ -    GObjectClass parent_class; - -    void (*changed) (PageView *view); -    void (*size_changed) (PageView *view); -} PageViewClass; - - -GType page_view_get_type (void); - -PageView *page_view_new (Page *page); - -Page *page_view_get_page (PageView *view); - -void page_view_set_selected (PageView *view, gboolean selected); - -gboolean page_view_get_selected (PageView *view); - -void page_view_set_x_offset (PageView *view, gint offset); - -void page_view_set_y_offset (PageView *view, gint offset); - -gint page_view_get_x_offset (PageView *view); - -gint page_view_get_y_offset (PageView *view); - -void page_view_set_width (PageView *view, gint width); - -void page_view_set_height (PageView *view, gint height); - -gint page_view_get_width (PageView *view); - -gint page_view_get_height (PageView *view); - -void page_view_button_press (PageView *view, gint x, gint y); - -void page_view_motion (PageView *view, gint x, gint y); - -void page_view_button_release (PageView *view, gint x, gint y); - -gint page_view_get_cursor (PageView *view); - -void page_view_render (PageView *view, cairo_t *context); - -#endif /* _PAGE_VIEW_H_ */ diff --git a/src/page-view.vala b/src/page-view.vala new file mode 100644 index 0000000..97bcaf0 --- /dev/null +++ b/src/page-view.vala @@ -0,0 +1,1043 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +public enum CropLocation +{ +    NONE = 0, +    MIDDLE, +    TOP, +    BOTTOM, +    LEFT, +    RIGHT, +    TOP_LEFT, +    TOP_RIGHT, +    BOTTOM_LEFT, +    BOTTOM_RIGHT +} + +public class PageView +{ +    /* Page being rendered */ +    private Page page; + +    /* Image to render at current resolution */ +    private Gdk.Pixbuf? image = null; + +    /* Border around image */ +    private bool selected; +    private int border_width = 1; + +    /* True if image needs to be regenerated */ +    private bool update_image = true; + +    /* Direction of currently scanned image */ +    private ScanDirection scan_direction; + +    /* Next scan line to render */ +    private int scan_line; + +    /* Dimensions of image to generate */ +    private int width; +    private int height; + +    /* Location to place this page */ +    private int x_offset; +    private int y_offset; + +    private CropLocation crop_location; +    private double selected_crop_px; +    private double selected_crop_py; +    private int selected_crop_x; +    private int selected_crop_y; +    private int selected_crop_w; +    private int selected_crop_h; + +    /* Cursor over this page */ +    private Gdk.CursorType cursor = Gdk.CursorType.ARROW; + +    private int animate_n_segments = 7; +    private int animate_segment; +    private uint animate_timeout; + +    public signal void size_changed (); +    public signal void changed (); + +    public PageView (Page page) +    { +        this.page = page; +        page.pixels_changed.connect (page_pixels_changed_cb); +        page.size_changed.connect (page_size_changed_cb); +        page.crop_changed.connect (page_overlay_changed_cb); +        page.scan_line_changed.connect (page_overlay_changed_cb); +        page.scan_direction_changed.connect (scan_direction_changed_cb); +    } + +    public Page get_page () +    { +        return page; +    } + +    public void set_selected (bool selected) +    { +        if ((this.selected && selected) || (!this.selected && !selected)) +            return; +        this.selected = selected; +        changed (); +    } + +    public bool get_selected () +    { +        return selected; +    } + +    public void set_x_offset (int offset) +    { +        x_offset = offset; +    } + +    public void set_y_offset (int offset) +    { +        y_offset = offset; +    } + +    public int get_x_offset () +    { +        return x_offset; +    } + +    public int get_y_offset () +    { +        return y_offset; +    } + +    private uchar get_sample (uchar[] pixels, int offset, int x, int depth, int sample) +    { +        // FIXME +        return 0xFF; +    } + +    private void get_pixel (Page page, int x, int y, uchar[] pixel) +    { +        switch (page.get_scan_direction ()) +        { +        case ScanDirection.TOP_TO_BOTTOM: +            break; +        case ScanDirection.BOTTOM_TO_TOP: +            x = page.get_scan_width () - x - 1; +            y = page.get_scan_height () - y - 1; +            break; +        case ScanDirection.LEFT_TO_RIGHT: +            var t = x; +            x = page.get_scan_width () - y - 1; +            y = t; +            break; +        case ScanDirection.RIGHT_TO_LEFT: +            var t = x; +            x = y; +            y = page.get_scan_height () - t - 1; +            break; +        } + +        var depth = page.get_depth (); +        var n_channels = page.get_n_channels (); +        unowned uchar[] pixels = page.get_pixels (); +        var offset = page.get_rowstride () * y; + +        /* Optimise for 8 bit images */ +        if (depth == 8 && n_channels == 3) +        { +            var o = offset + x * n_channels; +            pixel[0] = pixels[o]; +            pixel[1] = pixels[o+1]; +            pixel[2] = pixels[o+2]; +            return; +        } +        else if (depth == 8 && n_channels == 1) +        { +            pixel[0] = pixel[1] = pixel[2] = pixels[offset + x]; +            return; +        } + +        /* Optimise for bitmaps */ +        else if (depth == 1 && n_channels == 1) +        { +            var o = offset + (x / 8); +            pixel[0] = pixel[1] = pixel[2] = (pixels[o] & (0x80 >> (x % 8))) != 0 ? 0x00 : 0xFF; +            return; +        } + +        /* Optimise for 2 bit images */ +        else if (depth == 2 && n_channels == 1) +        { +            int block_shift[4] = { 6, 4, 2, 0 }; + +            var o = offset + (x / 4); +            var sample = (pixels[o] >> block_shift[x % 4]) & 0x3; +            sample = sample * 255 / 3; + +            pixel[0] = pixel[1] = pixel[2] = (uchar) sample; +            return; +        } + +        /* Use slow method */ +        pixel[0] = get_sample (pixels, offset, x, depth, x * n_channels); +        pixel[1] = get_sample (pixels, offset, x, depth, x * n_channels + 1); +        pixel[2] = get_sample (pixels, offset, x, depth, x * n_channels + 2); +    } + +    private void set_pixel (Page page, double l, double r, double t, double b, uchar[] output, int offset) +    { +        /* Decimation: +         * +         * Target pixel is defined by (t,l)-(b,r) +         * It touches 16 pixels in original image +         * It completely covers 4 pixels in original image (T,L)-(B,R) +         * Add covered pixels and add weighted partially covered pixels. +         * Divide by total area. +         * +         *      l  L           R   r +         *   +-----+-----+-----+-----+ +         *   |     |     |     |     | +         * t |  +--+-----+-----+---+ | +         * T +--+--+-----+-----+---+-+ +         *   |  |  |     |     |   | | +         *   |  |  |     |     |   | | +         *   +--+--+-----+-----+---+-+ +         *   |  |  |     |     |   | | +         *   |  |  |     |     |   | | +         * B +--+--+-----+-----+---+-+ +         *   |  |  |     |     |   | | +         * b |  +--+-----+-----+---+ | +         *   +-----+-----+-----+-----+ +         * +         * +         * Interpolation: +         * +         *             l    r +         *   +-----+-----+-----+-----+ +         *   |     |     |     |     | +         *   |     |     |     |     | +         *   +-----+-----+-----+-----+ +         * t |     |   +-+--+  |     | +         *   |     |   | |  |  |     | +         *   +-----+---+-+--+--+-----+ +         * b |     |   +-+--+  |     | +         *   |     |     |     |     | +         *   +-----+-----+-----+-----+ +         *   |     |     |     |     | +         *   |     |     |     |     | +         *   +-----+-----+-----+-----+ +         * +         * Same again, just no completely covered pixels. +         */ + +        var L = (int) l; +        if (L != l) +            L++; +        var R = (int) r; +        var T = (int) t; +        if (T != t) +            T++; +        var B = (int) b; + +        var red = 0.0; +        var green = 0.0; +        var blue = 0.0; + +        /* Target can fit inside one source pixel +         * +-----+ +         * |     | +         * | +--+|      +-----+-----+      +-----+      +-----+      +-----+ +         * +-+--++  or  |   +-++    |  or  | +-+ |  or  | +--+|  or  |  +--+ +         * | +--+|      |   +-++    |      | +-+ |      | |  ||      |  |  | +         * |     |      +-----+-----+      +-----+      +-+--++      +--+--+ +         * +-----+ +         */ +        if ((r - l <= 1.0 && (int)r == (int)l) || (b - t <= 1.0 && (int)b == (int)t)) +        { +            /* Inside */ +            if ((int)l == (int)r || (int)t == (int)b) +            { +                uchar p[3]; +                get_pixel (page, (int)l, (int)t, p); +                output[offset] = p[0]; +                output[offset+1] = p[1]; +                output[offset+2] = p[2]; +                return; +            } + +            /* Stradling horizontal edge */ +            if (L > R) +            { +                uchar p[3]; +                get_pixel (page, R, T-1, p); +                red   += p[0] * (r-l)*(T-t); +                green += p[1] * (r-l)*(T-t); +                blue  += p[2] * (r-l)*(T-t); +                for (var y = T; y < B; y++) +                { +                    get_pixel (page, R, y, p); +                    red   += p[0] * (r-l); +                    green += p[1] * (r-l); +                    blue  += p[2] * (r-l); +                } +                get_pixel (page, R, B, p); +                red   += p[0] * (r-l)*(b-B); +                green += p[1] * (r-l)*(b-B); +                blue  += p[2] * (r-l)*(b-B); +            } +            /* Stradling vertical edge */ +            else +            { +                uchar p[3]; +                get_pixel (page, L - 1, B, p); +                red   += p[0] * (b-t)*(L-l); +                green += p[1] * (b-t)*(L-l); +                blue  += p[2] * (b-t)*(L-l); +                for (var x = L; x < R; x++) { +                    get_pixel (page, x, B, p); +                    red   += p[0] * (b-t); +                    green += p[1] * (b-t); +                    blue  += p[2] * (b-t); +                } +                get_pixel (page, R, B, p); +                red   += p[0] * (b-t)*(r-R); +                green += p[1] * (b-t)*(r-R); +                blue  += p[2] * (b-t)*(r-R); +            } + +            var scale = 1.0 / ((r - l) * (b - t)); +            output[offset] = (uchar)(red * scale + 0.5); +            output[offset+1] = (uchar)(green * scale + 0.5); +            output[offset+2] = (uchar)(blue * scale + 0.5); +            return; +        } + +        /* Add the middle pixels */ +        for (var x = L; x < R; x++) +        { +            for (var y = T; y < B; y++) +            { +                uchar p[3]; +                get_pixel (page, x, y, p); +                red   += p[0]; +                green += p[1]; +                blue  += p[2]; +            } +        } + +        /* Add the weighted top and bottom pixels */ +        for (var x = L; x < R; x++) +        { +            if (t != T) +            { +                uchar p[3]; +                get_pixel (page, x, T - 1, p); +                red   += p[0] * (T - t); +                green += p[1] * (T - t); +                blue  += p[2] * (T - t); +            } + +            if (b != B) +            { +                uchar p[3]; +                get_pixel (page, x, B, p); +                red   += p[0] * (b - B); +                green += p[1] * (b - B); +                blue  += p[2] * (b - B); +            } +        } + +        /* Add the left and right pixels */ +        for (var y = T; y < B; y++) +        { +            if (l != L) +            { +                uchar p[3]; +                get_pixel (page, L - 1, y, p); +                red   += p[0] * (L - l); +                green += p[1] * (L - l); +                blue  += p[2] * (L - l); +            } + +            if (r != R) +            { +                uchar p[3]; +                get_pixel (page, R, y, p); +                red   += p[0] * (r - R); +                green += p[1] * (r - R); +                blue  += p[2] * (r - R); +            } +        } + +        /* Add the corner pixels */ +        if (l != L && t != T) +        { +            uchar p[3]; +            get_pixel (page, L - 1, T - 1, p); +            red   += p[0] * (L - l)*(T - t); +            green += p[1] * (L - l)*(T - t); +            blue  += p[2] * (L - l)*(T - t); +        } +        if (r != R && t != T) +        { +            uchar p[3]; +            get_pixel (page, R, T - 1, p); +            red   += p[0] * (r - R)*(T - t); +            green += p[1] * (r - R)*(T - t); +            blue  += p[2] * (r - R)*(T - t); +        } +        if (r != R && b != B) +        { +            uchar p[3]; +            get_pixel (page, R, B, p); +            red   += p[0] * (r - R)*(b - B); +            green += p[1] * (r - R)*(b - B); +            blue  += p[2] * (r - R)*(b - B); +        } +        if (l != L && b != B) +        { +            uchar p[3]; +            get_pixel (page, L - 1, B, p); +            red   += p[0] * (L - l)*(b - B); +            green += p[1] * (L - l)*(b - B); +            blue  += p[2] * (L - l)*(b - B); +        } + +        /* Scale pixel values and clamp in range [0, 255] */ +        var scale = 1.0 / ((r - l) * (b - t)); +        output[offset] = (uchar)(red * scale + 0.5); +        output[offset+1] = (uchar)(green * scale + 0.5); +        output[offset+2] = (uchar)(blue * scale + 0.5); +    } + +    private void update_preview (Page page, ref Gdk.Pixbuf? output_image, int output_width, int output_height, +                                 ScanDirection scan_direction, int old_scan_line, int scan_line) +    { +        var input_width = page.get_width (); +        var input_height = page.get_height (); + +        /* Create new image if one does not exist or has changed size */ +        int L, R, T, B; +        if (output_image == null || +            output_image.get_width () != output_width || +            output_image.get_height () != output_height) +        { +            output_image = new Gdk.Pixbuf (Gdk.Colorspace.RGB, +                                           false, +                                           8, +                                           output_width, +                                           output_height); + +            /* Update entire image */ +            L = 0; +            R = output_width - 1; +            T = 0; +            B = output_height - 1; +        } +        /* Otherwise only update changed area */ +        else +        { +            switch (scan_direction) +            { +            case ScanDirection.TOP_TO_BOTTOM: +                L = 0; +                R = output_width - 1; +                T = (int)((double)old_scan_line * output_height / input_height); +                B = (int)((double)scan_line * output_height / input_height + 0.5); +                break; +            case ScanDirection.LEFT_TO_RIGHT: +                L = (int)((double)old_scan_line * output_width / input_width); +                R = (int)((double)scan_line * output_width / input_width + 0.5); +                T = 0; +                B = output_height - 1; +                break; +            case ScanDirection.BOTTOM_TO_TOP: +                L = 0; +                R = output_width - 1; +                T = (int)((double)(input_height - scan_line) * output_height / input_height); +                B = (int)((double)(input_height - old_scan_line) * output_height / input_height + 0.5); +                break; +            case ScanDirection.RIGHT_TO_LEFT: +                L = (int)((double)(input_width - scan_line) * output_width / input_width); +                R = (int)((double)(input_width - old_scan_line) * output_width / input_width + 0.5); +                T = 0; +                B = output_height - 1; +                break; +            default: +                L = R = B = T = 0; +                break; +            } +        } + +        /* FIXME: There's an off by one error in there somewhere... */ +        if (R >= output_width) +            R = output_width - 1; +        if (B >= output_height) +            B = output_height - 1; + +        return_if_fail (L >= 0); +        return_if_fail (R < output_width); +        return_if_fail (T >= 0); +        return_if_fail (B < output_height); +        return_if_fail (output_image != null); + +        unowned uchar[] output = output_image.get_pixels (); +        var output_rowstride = output_image.get_rowstride (); +        var output_n_channels = output_image.get_n_channels (); + +        if (!page.has_data ()) +        { +            for (var x = L; x <= R; x++) +                for (var y = T; y <= B; y++) +                { +                    var o = output_rowstride * y + x * output_n_channels; +                    output[o] = output[o+1] = output[o+2] = 0xFF; +                } +            return; +        } + +        /* Update changed area */ +        for (var x = L; x <= R; x++) +        { +            var l = (double)x * input_width / output_width; +            var r = (double)(x + 1) * input_width / output_width; + +            for (var y = T; y <= B; y++) +            { +                var t = (double)y * input_height / output_height; +                var b = (double)(y + 1) * input_height / output_height; + +                set_pixel (page, +                           l, r, t, b, +                           output, output_rowstride * y + x * output_n_channels); +            } +        } +    } + +    private int get_preview_width () +    { +        return width - border_width * 2; +    } + +    private int get_preview_height () +    { +        return height - border_width * 2; +    } + +    private void update_page_view () +    { +        if (!update_image) +            return; + +        var old_scan_line = scan_line; +        var scan_line = page.get_scan_line (); + +        /* Delete old image if scan direction changed */ +        var left_steps = scan_direction - page.get_scan_direction (); +        if (left_steps != 0 && image != null) +            image = null; +        scan_direction = page.get_scan_direction (); + +        update_preview (page, +                        ref image, +                        get_preview_width (), +                        get_preview_height (), +                        page.get_scan_direction (), old_scan_line, scan_line); + +        update_image = false; +        this.scan_line = scan_line; +    } + +    private int page_to_screen_x (int x) +    { +        return (int) ((double)x * get_preview_width () / page.get_width () + 0.5); +    } + +    private int page_to_screen_y (int y) +    { +        return (int) ((double)y * get_preview_height () / page.get_height () + 0.5); +    } + +    private int screen_to_page_x (int x) +    { +        return (int) ((double)x * page.get_width () / get_preview_width () + 0.5); +    } + +    private int screen_to_page_y (int y) +    { +        return (int) ((double)y * page.get_height () / get_preview_height () + 0.5); +    } + +    private CropLocation get_crop_location (int x, int y) +    { +        if (!page.has_crop ()) +            return 0; + +        int cx, cy, cw, ch; +        page.get_crop (out cx, out cy, out cw, out ch); +        var dx = page_to_screen_x (cx); +        var dy = page_to_screen_y (cy); +        var dw = page_to_screen_x (cw); +        var dh = page_to_screen_y (ch); +        var ix = x - dx; +        var iy = y - dy; + +        if (ix < 0 || ix > dw || iy < 0 || iy > dh) +            return CropLocation.NONE; + +        /* Can't resize named crops */ +        var name = page.get_named_crop (); +        if (name != null) +            return CropLocation.MIDDLE; + +        /* Adjust borders so can select */ +        int crop_border = 20; +        if (dw < crop_border * 3) +            crop_border = dw / 3; +        if (dh < crop_border * 3) +            crop_border = dh / 3; + +        /* Top left */ +        if (ix < crop_border && iy < crop_border) +            return CropLocation.TOP_LEFT; +        /* Top right */ +        if (ix > dw - crop_border && iy < crop_border) +            return CropLocation.TOP_RIGHT; +        /* Bottom left */ +        if (ix < crop_border && iy > dh - crop_border) +            return CropLocation.BOTTOM_LEFT; +        /* Bottom right */ +        if (ix > dw - crop_border && iy > dh - crop_border) +            return CropLocation.BOTTOM_RIGHT; + +        /* Left */ +        if (ix < crop_border) +            return CropLocation.LEFT; +        /* Right */ +        if (ix > dw - crop_border) +            return CropLocation.RIGHT; +        /* Top */ +        if (iy < crop_border) +            return CropLocation.TOP; +        /* Bottom */ +        if (iy > dh - crop_border) +            return CropLocation.BOTTOM; + +        /* In the middle */ +        return CropLocation.MIDDLE; +    } + +    public void button_press (int x, int y) +    { +        CropLocation location; + +        /* See if selecting crop */ +        location = get_crop_location (x, y);; +        if (location != CropLocation.NONE) +        { +            crop_location = location; +            selected_crop_px = x; +            selected_crop_py = y; +            page.get_crop (out selected_crop_x, +                           out selected_crop_y, +                           out selected_crop_w, +                           out selected_crop_h); +        } +    } + +    public void motion (int x, int y) +    { +        var location = get_crop_location (x, y); +        Gdk.CursorType cursor; +        switch (location) +        { +        case CropLocation.MIDDLE: +            cursor = Gdk.CursorType.HAND1; +            break; +        case CropLocation.TOP: +            cursor = Gdk.CursorType.TOP_SIDE; +            break; +        case CropLocation.BOTTOM: +            cursor = Gdk.CursorType.BOTTOM_SIDE; +            break; +        case CropLocation.LEFT: +            cursor = Gdk.CursorType.LEFT_SIDE; +            break; +        case CropLocation.RIGHT: +            cursor = Gdk.CursorType.RIGHT_SIDE; +            break; +        case CropLocation.TOP_LEFT: +            cursor = Gdk.CursorType.TOP_LEFT_CORNER; +            break; +        case CropLocation.TOP_RIGHT: +            cursor = Gdk.CursorType.TOP_RIGHT_CORNER; +            break; +        case CropLocation.BOTTOM_LEFT: +            cursor = Gdk.CursorType.BOTTOM_LEFT_CORNER; +            break; +        case CropLocation.BOTTOM_RIGHT: +            cursor = Gdk.CursorType.BOTTOM_RIGHT_CORNER; +            break; +        default: +            cursor = Gdk.CursorType.ARROW; +            break; +        } + +        if (crop_location == CropLocation.NONE) +        { +            this.cursor = cursor; +            return; +        } + +        /* Move the crop */ +        var pw = page.get_width (); +        var ph = page.get_height (); +        int cx, cy, cw, ch; +        page.get_crop (out cx, out cy, out cw, out ch); + +        var dx = screen_to_page_x (x - (int) selected_crop_px); +        var dy = screen_to_page_y (y - (int) selected_crop_py); + +        var new_x = selected_crop_x; +        var new_y = selected_crop_y; +        var new_w = selected_crop_w; +        var new_h = selected_crop_h; + +        /* Limit motion to remain within page and minimum crop size */ +        var min_size = screen_to_page_x (15); +        if (crop_location == CropLocation.TOP_LEFT || +            crop_location == CropLocation.LEFT || +            crop_location == CropLocation.BOTTOM_LEFT) +        { +            if (dx > new_w - min_size) +                dx = new_w - min_size; +            if (new_x + dx < 0) +                dx = -new_x; +        } +        if (crop_location == CropLocation.TOP_LEFT || +            crop_location == CropLocation.TOP || +            crop_location == CropLocation.TOP_RIGHT) +        { +            if (dy > new_h - min_size) +                dy = new_h - min_size; +            if (new_y + dy < 0) +                dy = -new_y; +        } + +        if (crop_location == CropLocation.TOP_RIGHT || +            crop_location == CropLocation.RIGHT || +            crop_location == CropLocation.BOTTOM_RIGHT) +        { +            if (dx < min_size - new_w) +                dx = min_size - new_w; +            if (new_x + new_w + dx > pw) +                dx = pw - new_x - new_w; +        } +        if (crop_location == CropLocation.BOTTOM_LEFT || +            crop_location == CropLocation.BOTTOM || +            crop_location == CropLocation.BOTTOM_RIGHT) +        { +            if (dy < min_size - new_h) +                dy = min_size - new_h; +            if (new_y + new_h + dy > ph) +                dy = ph - new_y - new_h; +        } +        if (crop_location == CropLocation.MIDDLE) +        { +            if (new_x + dx + new_w > pw) +                dx = pw - new_x - new_w; +            if (new_x + dx < 0) +                dx = -new_x; +            if (new_y + dy + new_h > ph) +                dy = ph - new_y - new_h; +            if (new_y + dy  < 0) +                dy = -new_y; +        } + +        /* Move crop */ +        if (crop_location == CropLocation.MIDDLE) +        { +            new_x += dx; +            new_y += dy; +        } +        if (crop_location == CropLocation.TOP_LEFT || +            crop_location == CropLocation.LEFT || +            crop_location == CropLocation.BOTTOM_LEFT) +        { +            new_x += dx; +            new_w -= dx; +        } +        if (crop_location == CropLocation.TOP_LEFT || +            crop_location == CropLocation.TOP || +            crop_location == CropLocation.TOP_RIGHT) +        { +            new_y += dy; +            new_h -= dy; +        } + +        if (crop_location == CropLocation.TOP_RIGHT || +            crop_location == CropLocation.RIGHT || +            crop_location == CropLocation.BOTTOM_RIGHT) +            new_w += dx; +        if (crop_location == CropLocation.BOTTOM_LEFT || +            crop_location == CropLocation.BOTTOM || +            crop_location == CropLocation.BOTTOM_RIGHT) +            new_h += dy; + +        page.move_crop (new_x, new_y); + +        /* If reshaped crop, must be a custom crop */ +        if (new_w != cw || new_h != ch) +            page.set_custom_crop (new_w, new_h); +    } + +    public void button_release (int x, int y) +    { +        /* Complete crop */ +        crop_location = CropLocation.NONE; +        changed (); +    } + +    public Gdk.CursorType get_cursor () +    { +        return cursor; +    } + +    private bool animation_cb () +    { +        animate_segment = (animate_segment + 1) % animate_n_segments; +        changed (); +        return true; +    } + +    private void update_animation () +    { +        bool animate, is_animating; + +        animate = page.is_scanning () && !page.has_data (); +        is_animating = animate_timeout != 0; +        if (animate == is_animating) +            return; + +        if (animate) +        { +            animate_segment = 0; +            if (animate_timeout == 0) +                animate_timeout = Timeout.add (150, animation_cb); +        } +        else +        { +            if (animate_timeout != 0) +                Source.remove (animate_timeout); +            animate_timeout = 0; +        } +    } + +    public void render (Cairo.Context context) +    { +        update_animation (); +        update_page_view (); + +        var w = get_preview_width (); +        var h = get_preview_height (); + +        context.set_line_width (1); +        context.translate (x_offset, y_offset); + +        /* Draw page border */ +        context.set_source_rgb (0, 0, 0); +        context.set_line_width (border_width); +        context.rectangle ((double)border_width / 2, +                           (double)border_width / 2, +                           width - border_width, +                           height - border_width); +        context.stroke (); + +        /* Draw image */ +        context.translate (border_width, border_width); +        Gdk.cairo_set_source_pixbuf (context, image, 0, 0); +        context.paint (); + +        /* Draw throbber */ +        if (page.is_scanning () && !page.has_data ()) +        { +            double outer_radius; +            if (w > h) +                outer_radius = 0.15 * w; +            else +                outer_radius = 0.15 * h; +            var arc = Math.PI / animate_n_segments; + +            /* Space circles */ +            var x = outer_radius * Math.sin (arc); +            var y = outer_radius * (Math.cos (arc) - 1.0); +            var inner_radius = 0.6 * Math.sqrt (x*x + y*y); + +            double offset = 0.0;           +            for (var i = 0; i < animate_n_segments; i++, offset += arc * 2) +            { +                x = w / 2 + outer_radius * Math.sin (offset); +                y = h / 2 - outer_radius * Math.cos (offset); +                context.arc (x, y, inner_radius, 0, 2 * Math.PI); + +                if (i == animate_segment) +                { +                    context.set_source_rgb (0.75, 0.75, 0.75); +                    context.fill_preserve (); +                } + +                context.set_source_rgb (0.5, 0.5, 0.5); +                context.stroke (); +            } +        } + +        /* Draw scan line */ +        if (page.is_scanning () && page.get_scan_line () > 0) +        { +            var scan_line = page.get_scan_line (); + +            double s; +            double x1, y1, x2, y2; +            switch (page.get_scan_direction ()) +            { +            case ScanDirection.TOP_TO_BOTTOM: +                s = page_to_screen_y (scan_line); +                x1 = 0; y1 = s + 0.5; +                x2 = w; y2 = s + 0.5; +                break; +            case ScanDirection.BOTTOM_TO_TOP: +                s = page_to_screen_y (scan_line); +                x1 = 0; y1 = h - s + 0.5; +                x2 = w; y2 = h - s + 0.5; +                break; +            case ScanDirection.LEFT_TO_RIGHT: +                s = page_to_screen_x (scan_line); +                x1 = s + 0.5; y1 = 0; +                x2 = s + 0.5; y2 = h; +                break; +            case ScanDirection.RIGHT_TO_LEFT: +                s = page_to_screen_x (scan_line); +                x1 = w - s + 0.5; y1 = 0; +                x2 = w - s + 0.5; y2 = h; +                break; +            default: +                x1 = y1 = x2 = y2 = 0; +                break; +            } + +            context.move_to (x1, y1); +            context.line_to (x2, y2); +            context.set_source_rgb (1.0, 0.0, 0.0); +            context.stroke (); +        } + +        /* Draw crop */ +        if (page.has_crop ()) +        { +            int x, y, crop_width, crop_height; +            page.get_crop (out x, out y, out crop_width, out crop_height); + +            var dx = page_to_screen_x (x); +            var dy = page_to_screen_y (y); +            var dw = page_to_screen_x (crop_width); +            var dh = page_to_screen_y (crop_height); + +            /* Shade out cropped area */ +            context.rectangle (0, 0, w, h); +            context.new_sub_path (); +            context.rectangle (dx, dy, dw, dh); +            context.set_fill_rule (Cairo.FillRule.EVEN_ODD); +            context.set_source_rgba (0.25, 0.25, 0.25, 0.2); +            context.fill (); + +            /* Show new edge */ +            context.rectangle (dx - 1.5, dy - 1.5, dw + 3, dh + 3); +            context.set_source_rgb (1.0, 1.0, 1.0); +            context.stroke (); +            context.rectangle (dx - 0.5, dy - 0.5, dw + 1, dh + 1); +            context.set_source_rgb (0.0, 0.0, 0.0); +            context.stroke (); +        } +    } + +    public void set_width (int width) +    { +        // FIXME: Automatically update when get updated image +        var height = (int) ((double)width * page.get_height () / page.get_width ()); +        if (this.width == width && this.height == height) +            return; + +        this.width = width; +        this.height = height; + +        /* Regenerate image */ +        update_image = true; + +        size_changed (); +        changed (); +    } + +    public void set_height (int height) +    { +        // FIXME: Automatically update when get updated image +        var width = (int) ((double)height * page.get_width () / page.get_height ()); +        if (this.width == width && this.height == height) +            return; + +        this.width = width; +        this.height = height; + +        /* Regenerate image */ +        update_image = true; + +        size_changed (); +        changed (); +    } + +    public int get_width () +    { +        return width; +    } + +    public int get_height () +    { +        return height; +    } + +    private void page_pixels_changed_cb (Page p) +    { +        /* Regenerate image */ +        update_image = true; +        changed (); +    } + +    private void page_size_changed_cb (Page p) +    { +        /* Regenerate image */ +        update_image = true; +        size_changed (); +        changed (); +    } + +    private void page_overlay_changed_cb (Page p) +    { +        changed (); +    } + +    private void scan_direction_changed_cb (Page p) +    { +        /* Regenerate image */ +        update_image = true; +        size_changed (); +        changed (); +    } +} @@ -1,7 +1,10 @@ +/* page.c generated by valac 0.13.1, the Vala compiler + * generated from page.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later @@ -9,902 +12,1924 @@   * license.   */ +#include <glib.h> +#include <glib-object.h> +#include <stdlib.h>  #include <string.h> -#include "page.h" - -enum { -    PIXELS_CHANGED, -    SIZE_CHANGED, -    SCAN_LINE_CHANGED, -    SCAN_DIRECTION_CHANGED, -    CROP_CHANGED, -    LAST_SIGNAL +#include <float.h> +#include <math.h> +#include <gdk-pixbuf/gdk-pixdata.h> +#include <glib/gstdio.h> +#include <gio/gio.h> +#include <gobject/gvaluecollector.h> + + +#define TYPE_SCAN_DIRECTION (scan_direction_get_type ()) + +#define TYPE_PAGE (page_get_type ()) +#define PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE, Page)) +#define PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE, PageClass)) +#define IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE)) +#define IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE)) +#define PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE, PageClass)) + +typedef struct _Page Page; +typedef struct _PageClass PageClass; +typedef struct _PagePrivate PagePrivate; +#define _g_free0(var) (var = (g_free (var), NULL)) + +#define TYPE_SCAN_PAGE_INFO (scan_page_info_get_type ()) +#define SCAN_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_PAGE_INFO, ScanPageInfo)) +#define SCAN_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_PAGE_INFO, ScanPageInfoClass)) +#define IS_SCAN_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_PAGE_INFO)) +#define IS_SCAN_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_PAGE_INFO)) +#define SCAN_PAGE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_PAGE_INFO, ScanPageInfoClass)) + +typedef struct _ScanPageInfo ScanPageInfo; +typedef struct _ScanPageInfoClass ScanPageInfoClass; +typedef struct _ScanPageInfoPrivate ScanPageInfoPrivate; + +#define TYPE_SCAN_LINE (scan_line_get_type ()) +#define SCAN_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_LINE, ScanLine)) +#define SCAN_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_LINE, ScanLineClass)) +#define IS_SCAN_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_LINE)) +#define IS_SCAN_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_LINE)) +#define SCAN_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_LINE, ScanLineClass)) + +typedef struct _ScanLine ScanLine; +typedef struct _ScanLineClass ScanLineClass; +typedef struct _ScanLinePrivate ScanLinePrivate; +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) + +#define TYPE_PIXBUF_WRITER (pixbuf_writer_get_type ()) +#define PIXBUF_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PIXBUF_WRITER, PixbufWriter)) +#define PIXBUF_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PIXBUF_WRITER, PixbufWriterClass)) +#define IS_PIXBUF_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PIXBUF_WRITER)) +#define IS_PIXBUF_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PIXBUF_WRITER)) +#define PIXBUF_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PIXBUF_WRITER, PixbufWriterClass)) + +typedef struct _PixbufWriter PixbufWriter; +typedef struct _PixbufWriterClass PixbufWriterClass; +#define _pixbuf_writer_unref0(var) ((var == NULL) ? NULL : (var = (pixbuf_writer_unref (var), NULL))) +typedef struct _ParamSpecPage ParamSpecPage; +typedef struct _PixbufWriterPrivate PixbufWriterPrivate; +typedef struct _ParamSpecPixbufWriter ParamSpecPixbufWriter; + +typedef enum  { +	SCAN_DIRECTION_TOP_TO_BOTTOM, +	SCAN_DIRECTION_LEFT_TO_RIGHT, +	SCAN_DIRECTION_BOTTOM_TO_TOP, +	SCAN_DIRECTION_RIGHT_TO_LEFT +} ScanDirection; + +struct _Page { +	GTypeInstance parent_instance; +	volatile int ref_count; +	PagePrivate * priv;  }; -static guint signals[LAST_SIGNAL] = { 0, }; -struct PagePrivate -{ -    /* Resolution of page */ -    gint dpi; +struct _PageClass { +	GTypeClass parent_class; +	void (*finalize) (Page *self); +}; -    /* Number of rows in this page or -1 if currently unknown */ -    gint expected_rows; +struct _PagePrivate { +	gint dpi; +	gint expected_rows; +	gint depth; +	gchar* color_profile; +	gint width; +	gint n_rows; +	gint rowstride; +	gint n_channels; +	guchar* pixels; +	gint pixels_length1; +	gint _pixels_size_; +	gboolean scanning; +	gboolean has_data_; +	gint scan_line; +	ScanDirection scan_direction; +	gboolean has_crop_; +	gchar* crop_name; +	gint crop_x; +	gint crop_y; +	gint crop_width; +	gint crop_height; +}; -    /* Bit depth */ -    gint depth; +struct _ScanPageInfo { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanPageInfoPrivate * priv; +	gint width; +	gint height; +	gint depth; +	gint n_channels; +	gdouble dpi; +	gchar* device; +}; -    /* Color profile */ -    gchar *color_profile; +struct _ScanPageInfoClass { +	GTypeClass parent_class; +	void (*finalize) (ScanPageInfo *self); +}; + +struct _ScanLine { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanLinePrivate * priv; +	gint number; +	gint n_lines; +	gint width; +	gint depth; +	gint channel; +	guchar* data; +	gint data_length1; +	gint data_length; +}; + +struct _ScanLineClass { +	GTypeClass parent_class; +	void (*finalize) (ScanLine *self); +}; -    /* Scanned image data */ -    gint width, n_rows, rowstride, n_channels; -    guchar *pixels; +struct _ParamSpecPage { +	GParamSpec parent_instance; +}; -    /* Page is getting data */ -    gboolean scanning; +struct _PixbufWriter { +	GTypeInstance parent_instance; +	volatile int ref_count; +	PixbufWriterPrivate * priv; +	GFileOutputStream* stream; +}; -    /* TRUE if have some page data */ -    gboolean has_data; +struct _PixbufWriterClass { +	GTypeClass parent_class; +	void (*finalize) (PixbufWriter *self); +}; -    /* Expected next scan row */ -    gint scan_line; +struct _ParamSpecPixbufWriter { +	GParamSpec parent_instance; +}; -    /* Rotation of scanned data */ -    ScanDirection scan_direction; -    /* Crop */ -    gboolean has_crop; -    gchar *crop_name; -    gint crop_x, crop_y, crop_width, crop_height; +static gpointer page_parent_class = NULL; +static gpointer pixbuf_writer_parent_class = NULL; + +GType scan_direction_get_type (void) G_GNUC_CONST; +gpointer page_ref (gpointer instance); +void page_unref (gpointer instance); +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page (GValue* value, gpointer v_object); +void value_take_page (GValue* value, gpointer v_object); +gpointer value_get_page (const GValue* value); +GType page_get_type (void) G_GNUC_CONST; +#define PAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_PAGE, PagePrivate)) +enum  { +	PAGE_DUMMY_PROPERTY +}; +Page* page_new (gint width, gint height, gint dpi, ScanDirection scan_direction); +Page* page_construct (GType object_type, gint width, gint height, gint dpi, ScanDirection scan_direction); +gpointer scan_page_info_ref (gpointer instance); +void scan_page_info_unref (gpointer instance); +GParamSpec* param_spec_scan_page_info (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_page_info (GValue* value, gpointer v_object); +void value_take_scan_page_info (GValue* value, gpointer v_object); +gpointer value_get_scan_page_info (const GValue* value); +GType scan_page_info_get_type (void) G_GNUC_CONST; +void page_set_page_info (Page* self, ScanPageInfo* info); +void page_start (Page* self); +gboolean page_is_scanning (Page* self); +gboolean page_has_data (Page* self); +gboolean page_is_color (Page* self); +gint page_get_scan_line (Page* self); +gpointer scan_line_ref (gpointer instance); +void scan_line_unref (gpointer instance); +GParamSpec* param_spec_scan_line (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_line (GValue* value, gpointer v_object); +void value_take_scan_line (GValue* value, gpointer v_object); +gpointer value_get_scan_line (const GValue* value); +GType scan_line_get_type (void) G_GNUC_CONST; +static void page_parse_line (Page* self, ScanLine* line, gint n, gboolean* size_changed); +gint page_get_scan_height (Page* self); +void page_parse_scan_line (Page* self, ScanLine* line); +void page_finish (Page* self); +ScanDirection page_get_scan_direction (Page* self); +static void page_set_scan_direction (Page* self, ScanDirection direction); +gint page_get_width (Page* self); +gint page_get_height (Page* self); +void page_rotate_left (Page* self); +void page_rotate_right (Page* self); +gint page_get_dpi (Page* self); +gboolean page_is_landscape (Page* self); +gint page_get_depth (Page* self); +gint page_get_n_channels (Page* self); +gint page_get_rowstride (Page* self); +gint page_get_scan_width (Page* self); +void page_set_color_profile (Page* self, const gchar* color_profile); +gchar* page_get_color_profile (Page* self); +void page_set_no_crop (Page* self); +void page_set_custom_crop (Page* self, gint width, gint height); +void page_set_named_crop (Page* self, const gchar* name); +void page_move_crop (Page* self, gint x, gint y); +void page_rotate_crop (Page* self); +gboolean page_has_crop (Page* self); +void page_get_crop (Page* self, gint* x, gint* y, gint* width, gint* height); +gchar* page_get_named_crop (Page* self); +guchar* page_get_pixels (Page* self, int* result_length1); +static guchar page_get_sample (Page* self, guchar* pixels, int pixels_length1, gint offset, gint x, gint depth, gint n_channels, gint channel); +static void page_get_pixel (Page* self, gint x, gint y, guchar* pixel, int pixel_length1, gint offset); +GdkPixbuf* page_get_image (Page* self, gboolean apply_crop); +static gchar* page_get_icc_data_encoded (Page* self, const gchar* icc_profile_filename); +void page_save (Page* self, const gchar* type, GFile* file, GError** error); +PixbufWriter* pixbuf_writer_new (GFileOutputStream* stream); +PixbufWriter* pixbuf_writer_construct (GType object_type, GFileOutputStream* stream); +gpointer pixbuf_writer_ref (gpointer instance); +void pixbuf_writer_unref (gpointer instance); +GParamSpec* param_spec_pixbuf_writer (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_pixbuf_writer (GValue* value, gpointer v_object); +void value_take_pixbuf_writer (GValue* value, gpointer v_object); +gpointer value_get_pixbuf_writer (const GValue* value); +GType pixbuf_writer_get_type (void) G_GNUC_CONST; +void pixbuf_writer_save (PixbufWriter* self, GdkPixbuf* image, const gchar* type, gchar** option_keys, int option_keys_length1, gchar** option_values, int option_values_length1, GError** error); +static void page_finalize (Page* obj); +enum  { +	PIXBUF_WRITER_DUMMY_PROPERTY  }; +static gboolean pixbuf_writer_write_pixbuf_data (PixbufWriter* self, guint8* buf, int buf_length1, GError** error); +static gboolean _pixbuf_writer_write_pixbuf_data_gdk_pixbuf_save_func (guint8* buf, gsize buf_length1, GError** error, gpointer self); +static void pixbuf_writer_finalize (PixbufWriter* obj); +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func); +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func); + + +GType scan_direction_get_type (void) { +	static volatile gsize scan_direction_type_id__volatile = 0; +	if (g_once_init_enter (&scan_direction_type_id__volatile)) { +		static const GEnumValue values[] = {{SCAN_DIRECTION_TOP_TO_BOTTOM, "SCAN_DIRECTION_TOP_TO_BOTTOM", "top-to-bottom"}, {SCAN_DIRECTION_LEFT_TO_RIGHT, "SCAN_DIRECTION_LEFT_TO_RIGHT", "left-to-right"}, {SCAN_DIRECTION_BOTTOM_TO_TOP, "SCAN_DIRECTION_BOTTOM_TO_TOP", "bottom-to-top"}, {SCAN_DIRECTION_RIGHT_TO_LEFT, "SCAN_DIRECTION_RIGHT_TO_LEFT", "right-to-left"}, {0, NULL, NULL}}; +		GType scan_direction_type_id; +		scan_direction_type_id = g_enum_register_static ("ScanDirection", values); +		g_once_init_leave (&scan_direction_type_id__volatile, scan_direction_type_id); +	} +	return scan_direction_type_id__volatile; +} + + +Page* page_construct (GType object_type, gint width, gint height, gint dpi, ScanDirection scan_direction) { +	Page* self = NULL; +	gboolean _tmp0_ = FALSE; +	self = (Page*) g_type_create_instance (object_type); +	if (scan_direction == SCAN_DIRECTION_TOP_TO_BOTTOM) { +		_tmp0_ = TRUE; +	} else { +		_tmp0_ = scan_direction == SCAN_DIRECTION_BOTTOM_TO_TOP; +	} +	if (_tmp0_) { +		self->priv->width = width; +		self->priv->n_rows = height; +	} else { +		self->priv->width = height; +		self->priv->n_rows = width; +	} +	self->priv->dpi = dpi; +	self->priv->scan_direction = scan_direction; +	return self; +} + + +Page* page_new (gint width, gint height, gint dpi, ScanDirection scan_direction) { +	return page_construct (TYPE_PAGE, width, height, dpi, scan_direction); +} + + +void page_set_page_info (Page* self, ScanPageInfo* info) { +	gint _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (info != NULL); +	self->priv->expected_rows = info->height; +	self->priv->dpi = (gint) info->dpi; +	self->priv->width = info->width; +	self->priv->n_rows = info->height; +	if (self->priv->n_rows < 0) { +		self->priv->n_rows = self->priv->width / 2; +	} +	self->priv->depth = info->depth; +	self->priv->n_channels = info->n_channels; +	self->priv->rowstride = (((self->priv->width * self->priv->depth) * self->priv->n_channels) + 7) / 8; +	_tmp0_ = self->priv->n_rows * self->priv->rowstride; +	self->priv->pixels = g_renew (guchar, self->priv->pixels, self->priv->n_rows * self->priv->rowstride); +	(_tmp0_ > self->priv->pixels_length1) ? memset (self->priv->pixels + self->priv->pixels_length1, 0, sizeof (guchar) * (_tmp0_ - self->priv->pixels_length1)) : NULL; +	self->priv->pixels_length1 = _tmp0_; +	self->priv->_pixels_size_ = _tmp0_; +	g_return_if_fail (self->priv->pixels != NULL); +	if (self->priv->depth == 1) { +		memset (self->priv->pixels, 0x00, (gsize) (self->priv->n_rows * self->priv->rowstride)); +	} else { +		memset (self->priv->pixels, 0xFF, (gsize) (self->priv->n_rows * self->priv->rowstride)); +	} +	g_signal_emit_by_name (self, "size-changed"); +	g_signal_emit_by_name (self, "pixels-changed"); +} + + +void page_start (Page* self) { +	g_return_if_fail (self != NULL); +	self->priv->scanning = TRUE; +	g_signal_emit_by_name (self, "scan-line-changed"); +} + + +gboolean page_is_scanning (Page* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->scanning; +	return result; +} + + +gboolean page_has_data (Page* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->has_data_; +	return result; +} + + +gboolean page_is_color (Page* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->n_channels > 1; +	return result; +} + + +gint page_get_scan_line (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->scan_line; +	return result; +} + + +static void page_parse_line (Page* self, ScanLine* line, gint n, gboolean* size_changed) { +	gboolean _size_changed = FALSE; +	gint line_number = 0; +	gint offset; +	gint line_offset; +	g_return_if_fail (self != NULL); +	g_return_if_fail (line != NULL); +	line_number = line->number + n; +	_size_changed = FALSE; +	while (TRUE) { +		gint _tmp0_; +		gint rows = 0; +		gint _tmp1_; +		_tmp0_ = page_get_scan_height (self); +		if (!(line_number >= _tmp0_)) { +			break; +		} +		rows = self->priv->n_rows; +		self->priv->n_rows = rows + (self->priv->width / 2); +		g_debug ("page.vala:151: Extending image from %d lines to %d lines", rows, self->priv->n_rows); +		_tmp1_ = self->priv->n_rows * self->priv->rowstride; +		self->priv->pixels = g_renew (guchar, self->priv->pixels, self->priv->n_rows * self->priv->rowstride); +		(_tmp1_ > self->priv->pixels_length1) ? memset (self->priv->pixels + self->priv->pixels_length1, 0, sizeof (guchar) * (_tmp1_ - self->priv->pixels_length1)) : NULL; +		self->priv->pixels_length1 = _tmp1_; +		self->priv->_pixels_size_ = _tmp1_; +		_size_changed = TRUE; +	} +	offset = line_number * self->priv->rowstride; +	line_offset = n * line->data_length; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp2_; +			_tmp2_ = TRUE; +			while (TRUE) { +				if (!_tmp2_) { +					i++; +				} +				_tmp2_ = FALSE; +				if (!(i < line->data_length)) { +					break; +				} +				self->priv->pixels[offset + i] = line->data[line_offset + i]; +			} +		} +	} +	self->priv->scan_line = line_number; +	if (size_changed) { +		*size_changed = _size_changed; +	} +} + + +void page_parse_scan_line (Page* self, ScanLine* line) { +	gboolean size_has_changed; +	g_return_if_fail (self != NULL); +	g_return_if_fail (line != NULL); +	size_has_changed = FALSE; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp0_; +			_tmp0_ = TRUE; +			while (TRUE) { +				gboolean _tmp1_; +				if (!_tmp0_) { +					i++; +				} +				_tmp0_ = FALSE; +				if (!(i < line->n_lines)) { +					break; +				} +				page_parse_line (self, line, i, &_tmp1_); +				size_has_changed = _tmp1_; +			} +		} +	} +	self->priv->has_data_ = TRUE; +	if (size_has_changed) { +		g_signal_emit_by_name (self, "size-changed"); +	} +	g_signal_emit_by_name (self, "scan-line-changed"); +	g_signal_emit_by_name (self, "pixels-changed"); +} + + +void page_finish (Page* self) { +	gboolean size_has_changed; +	gboolean _tmp0_ = FALSE; +	g_return_if_fail (self != NULL); +	size_has_changed = FALSE; +	if (self->priv->expected_rows < 0) { +		gint _tmp1_; +		_tmp1_ = page_get_scan_height (self); +		_tmp0_ = self->priv->scan_line != _tmp1_; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		gint rows = 0; +		gint _tmp2_; +		rows = self->priv->n_rows; +		self->priv->n_rows = self->priv->scan_line; +		_tmp2_ = self->priv->n_rows * self->priv->rowstride; +		self->priv->pixels = g_renew (guchar, self->priv->pixels, self->priv->n_rows * self->priv->rowstride); +		(_tmp2_ > self->priv->pixels_length1) ? memset (self->priv->pixels + self->priv->pixels_length1, 0, sizeof (guchar) * (_tmp2_ - self->priv->pixels_length1)) : NULL; +		self->priv->pixels_length1 = _tmp2_; +		self->priv->_pixels_size_ = _tmp2_; +		g_debug ("page.vala:193: Trimming page from %d lines to %d lines", rows, self->priv->n_rows); +		size_has_changed = TRUE; +	} +	self->priv->scanning = FALSE; +	if (size_has_changed) { +		g_signal_emit_by_name (self, "size-changed"); +	} +	g_signal_emit_by_name (self, "scan-line-changed"); +} + + +ScanDirection page_get_scan_direction (Page* self) { +	ScanDirection result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->scan_direction; +	return result; +} + + +static void page_set_scan_direction (Page* self, ScanDirection direction) { +	gint left_steps = 0; +	gint t = 0; +	gboolean size_has_changed; +	gint width = 0; +	gint height = 0; +	gint _tmp0_; +	gint _tmp1_; +	g_return_if_fail (self != NULL); +	size_has_changed = FALSE; +	if (self->priv->scan_direction == direction) { +		return; +	} +	left_steps = (gint) (direction - self->priv->scan_direction); +	if (left_steps < 0) { +		left_steps = left_steps + 4; +	} +	if (left_steps != 2) { +		size_has_changed = TRUE; +	} +	_tmp0_ = page_get_width (self); +	width = _tmp0_; +	_tmp1_ = page_get_height (self); +	height = _tmp1_; +	if (self->priv->has_crop_) { +		switch (left_steps) { +			case 1: +			{ +				t = self->priv->crop_x; +				self->priv->crop_x = self->priv->crop_y; +				self->priv->crop_y = width - (t + self->priv->crop_width); +				t = self->priv->crop_width; +				self->priv->crop_width = self->priv->crop_height; +				self->priv->crop_height = t; +				break; +			} +			case 2: +			{ +				self->priv->crop_x = width - (self->priv->crop_x + self->priv->crop_width); +				self->priv->crop_y = width - (self->priv->crop_y + self->priv->crop_height); +				break; +			} +			case 3: +			{ +				t = self->priv->crop_y; +				self->priv->crop_y = self->priv->crop_x; +				self->priv->crop_x = height - (t + self->priv->crop_height); +				t = self->priv->crop_width; +				self->priv->crop_width = self->priv->crop_height; +				self->priv->crop_height = t; +				break; +			} +			default: +			break; +		} +	} +	self->priv->scan_direction = direction; +	if (size_has_changed) { +		g_signal_emit_by_name (self, "size-changed"); +	} +	g_signal_emit_by_name (self, "scan-direction-changed"); +	if (self->priv->has_crop_) { +		g_signal_emit_by_name (self, "crop-changed"); +	} +} + + +void page_rotate_left (Page* self) { +	ScanDirection direction; +	g_return_if_fail (self != NULL); +	direction = self->priv->scan_direction; +	switch (direction) { +		case SCAN_DIRECTION_TOP_TO_BOTTOM: +		{ +			direction = SCAN_DIRECTION_LEFT_TO_RIGHT; +			break; +		} +		case SCAN_DIRECTION_LEFT_TO_RIGHT: +		{ +			direction = SCAN_DIRECTION_BOTTOM_TO_TOP; +			break; +		} +		case SCAN_DIRECTION_BOTTOM_TO_TOP: +		{ +			direction = SCAN_DIRECTION_RIGHT_TO_LEFT; +			break; +		} +		case SCAN_DIRECTION_RIGHT_TO_LEFT: +		{ +			direction = SCAN_DIRECTION_TOP_TO_BOTTOM; +			break; +		} +		default: +		break; +	} +	page_set_scan_direction (self, direction); +} + + +void page_rotate_right (Page* self) { +	ScanDirection direction; +	g_return_if_fail (self != NULL); +	direction = self->priv->scan_direction; +	switch (direction) { +		case SCAN_DIRECTION_TOP_TO_BOTTOM: +		{ +			direction = SCAN_DIRECTION_RIGHT_TO_LEFT; +			break; +		} +		case SCAN_DIRECTION_LEFT_TO_RIGHT: +		{ +			direction = SCAN_DIRECTION_TOP_TO_BOTTOM; +			break; +		} +		case SCAN_DIRECTION_BOTTOM_TO_TOP: +		{ +			direction = SCAN_DIRECTION_LEFT_TO_RIGHT; +			break; +		} +		case SCAN_DIRECTION_RIGHT_TO_LEFT: +		{ +			direction = SCAN_DIRECTION_BOTTOM_TO_TOP; +			break; +		} +		default: +		break; +	} +	page_set_scan_direction (self, direction); +} + + +gint page_get_dpi (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->dpi; +	return result; +} + + +gboolean page_is_landscape (Page* self) { +	gboolean result = FALSE; +	gint _tmp0_; +	gint _tmp1_; +	g_return_val_if_fail (self != NULL, FALSE); +	_tmp0_ = page_get_width (self); +	_tmp1_ = page_get_height (self); +	result = _tmp0_ > _tmp1_; +	return result; +} + + +gint page_get_width (Page* self) { +	gint result = 0; +	gboolean _tmp0_ = FALSE; +	g_return_val_if_fail (self != NULL, 0); +	if (self->priv->scan_direction == SCAN_DIRECTION_TOP_TO_BOTTOM) { +		_tmp0_ = TRUE; +	} else { +		_tmp0_ = self->priv->scan_direction == SCAN_DIRECTION_BOTTOM_TO_TOP; +	} +	if (_tmp0_) { +		result = self->priv->width; +		return result; +	} else { +		result = self->priv->n_rows; +		return result; +	} +} + + +gint page_get_height (Page* self) { +	gint result = 0; +	gboolean _tmp0_ = FALSE; +	g_return_val_if_fail (self != NULL, 0); +	if (self->priv->scan_direction == SCAN_DIRECTION_TOP_TO_BOTTOM) { +		_tmp0_ = TRUE; +	} else { +		_tmp0_ = self->priv->scan_direction == SCAN_DIRECTION_BOTTOM_TO_TOP; +	} +	if (_tmp0_) { +		result = self->priv->n_rows; +		return result; +	} else { +		result = self->priv->width; +		return result; +	} +} + + +gint page_get_depth (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->depth; +	return result; +} + + +gint page_get_n_channels (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->n_channels; +	return result; +} + + +gint page_get_rowstride (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->rowstride; +	return result; +} -G_DEFINE_TYPE (Page, page, G_TYPE_OBJECT); +gint page_get_scan_width (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->width; +	return result; +} -Page * -page_new (gint width, gint height, gint dpi, ScanDirection scan_direction) -{ -    Page *page; -   -    page = g_object_new (PAGE_TYPE, NULL); -    if (scan_direction == TOP_TO_BOTTOM || scan_direction == BOTTOM_TO_TOP) { -        page->priv->width = width; -        page->priv->n_rows = height; -    } -    else { -        page->priv->width = height; -        page->priv->n_rows = width; -    } -    page->priv->dpi = dpi; -    page->priv->scan_direction = scan_direction; -    return page; +gint page_get_scan_height (Page* self) { +	gint result = 0; +	g_return_val_if_fail (self != NULL, 0); +	result = self->priv->n_rows; +	return result;  } -void -page_set_page_info (Page *page, ScanPageInfo *info) -{ -    g_return_if_fail (page != NULL); +void page_set_color_profile (Page* self, const gchar* color_profile) { +	gchar* _tmp0_; +	g_return_if_fail (self != NULL); +	_tmp0_ = g_strdup (color_profile); +	_g_free0 (self->priv->color_profile); +	self->priv->color_profile = _tmp0_; +} -    page->priv->expected_rows = info->height; -    page->priv->dpi = info->dpi; -    /* Create a white page */ -    page->priv->width = info->width; -    page->priv->n_rows = info->height; -    /* Variable height, try 50% of the width for now */ -    if (page->priv->n_rows < 0) -        page->priv->n_rows = page->priv->width / 2; -    page->priv->depth = info->depth; -    page->priv->n_channels = info->n_channels; -    page->priv->rowstride = (page->priv->width * page->priv->depth * page->priv->n_channels + 7) / 8; -    page->priv->pixels = g_realloc (page->priv->pixels, page->priv->n_rows * page->priv->rowstride); -    g_return_if_fail (page->priv->pixels != NULL); +gchar* page_get_color_profile (Page* self) { +	gchar* result = NULL; +	gchar* _tmp0_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = g_strdup (self->priv->color_profile); +	result = _tmp0_; +	return result; +} -    /* Fill with white */ -    if (page->priv->depth == 1) -        memset (page->priv->pixels, 0x00, page->priv->n_rows * page->priv->rowstride); -    else -        memset (page->priv->pixels, 0xFF, page->priv->n_rows * page->priv->rowstride); -    g_signal_emit (page, signals[SIZE_CHANGED], 0); -    g_signal_emit (page, signals[PIXELS_CHANGED], 0); +void page_set_no_crop (Page* self) { +	g_return_if_fail (self != NULL); +	if (!self->priv->has_crop_) { +		return; +	} +	self->priv->has_crop_ = FALSE; +	g_signal_emit_by_name (self, "crop-changed");  } -void -page_start (Page *page) -{ -    g_return_if_fail (page != NULL); +void page_set_custom_crop (Page* self, gint width, gint height) { +	gboolean _tmp0_ = FALSE; +	gboolean _tmp1_ = FALSE; +	gboolean _tmp2_ = FALSE; +	g_return_if_fail (self != NULL); +	g_return_if_fail (width >= 1); +	g_return_if_fail (height >= 1); +	if (self->priv->crop_name == NULL) { +		_tmp2_ = self->priv->has_crop_; +	} else { +		_tmp2_ = FALSE; +	} +	if (_tmp2_) { +		_tmp1_ = self->priv->crop_width == width; +	} else { +		_tmp1_ = FALSE; +	} +	if (_tmp1_) { +		_tmp0_ = self->priv->crop_height == height; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		return; +	} +	_g_free0 (self->priv->crop_name); +	self->priv->crop_name = NULL; +	self->priv->has_crop_ = TRUE; +	self->priv->crop_width = width; +	self->priv->crop_height = height; +	g_signal_emit_by_name (self, "crop-changed"); +} + -    page->priv->scanning = TRUE; -    g_signal_emit (page, signals[SCAN_LINE_CHANGED], 0); +void page_set_named_crop (Page* self, const gchar* name) { +	gdouble width = 0.0; +	gdouble height = 0.0; +	const gchar* _tmp0_; +	GQuark _tmp1_; +	static GQuark _tmp1__label0 = 0; +	static GQuark _tmp1__label1 = 0; +	static GQuark _tmp1__label2 = 0; +	static GQuark _tmp1__label3 = 0; +	static GQuark _tmp1__label4 = 0; +	static GQuark _tmp1__label5 = 0; +	gchar* _tmp2_; +	gint _tmp3_; +	gint pw; +	gint _tmp4_; +	gint ph; +	g_return_if_fail (self != NULL); +	g_return_if_fail (name != NULL); +	_tmp0_ = name; +	_tmp1_ = (NULL == _tmp0_) ? 0 : g_quark_from_string (_tmp0_); +	if (_tmp1_ == ((0 != _tmp1__label0) ? _tmp1__label0 : (_tmp1__label0 = g_quark_from_static_string ("A4")))) { +		switch (0) { +			default: +			{ +				width = 8.3; +				height = 11.7; +				break; +			} +		} +	} else if (_tmp1_ == ((0 != _tmp1__label1) ? _tmp1__label1 : (_tmp1__label1 = g_quark_from_static_string ("A5")))) { +		switch (0) { +			default: +			{ +				width = 5.8; +				height = 8.3; +				break; +			} +		} +	} else if (_tmp1_ == ((0 != _tmp1__label2) ? _tmp1__label2 : (_tmp1__label2 = g_quark_from_static_string ("A6")))) { +		switch (0) { +			default: +			{ +				width = 4.1; +				height = 5.8; +				break; +			} +		} +	} else if (_tmp1_ == ((0 != _tmp1__label3) ? _tmp1__label3 : (_tmp1__label3 = g_quark_from_static_string ("letter")))) { +		switch (0) { +			default: +			{ +				width = 8.5; +				height = (gdouble) 11; +				break; +			} +		} +	} else if (_tmp1_ == ((0 != _tmp1__label4) ? _tmp1__label4 : (_tmp1__label4 = g_quark_from_static_string ("legal")))) { +		switch (0) { +			default: +			{ +				width = 8.5; +				height = (gdouble) 14; +				break; +			} +		} +	} else if (_tmp1_ == ((0 != _tmp1__label5) ? _tmp1__label5 : (_tmp1__label5 = g_quark_from_static_string ("4x6")))) { +		switch (0) { +			default: +			{ +				width = (gdouble) 4; +				height = (gdouble) 6; +				break; +			} +		} +	} else { +		switch (0) { +			default: +			{ +				g_warning ("page.vala:437: Unknown paper size '%s'", name); +				return; +			} +		} +	} +	_tmp2_ = g_strdup (name); +	_g_free0 (self->priv->crop_name); +	self->priv->crop_name = _tmp2_; +	self->priv->has_crop_ = TRUE; +	_tmp3_ = page_get_width (self); +	pw = _tmp3_; +	_tmp4_ = page_get_height (self); +	ph = _tmp4_; +	if (pw > ph) { +		gdouble t = 0.0; +		t = width; +		width = height; +		height = t; +	} +	self->priv->crop_width = (gint) ((width * self->priv->dpi) + 0.5); +	self->priv->crop_height = (gint) ((height * self->priv->dpi) + 0.5); +	if (self->priv->crop_width < pw) { +		self->priv->crop_x = (pw - self->priv->crop_width) / 2; +	} else { +		self->priv->crop_x = 0; +	} +	if (self->priv->crop_height < ph) { +		self->priv->crop_y = (ph - self->priv->crop_height) / 2; +	} else { +		self->priv->crop_y = 0; +	} +	g_signal_emit_by_name (self, "crop-changed");  } -gboolean -page_is_scanning (Page *page) -{ -    g_return_val_if_fail (page != NULL, FALSE); -   -    return page->priv->scanning; +void page_move_crop (Page* self, gint x, gint y) { +	gint _tmp0_; +	gint _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (x >= 0); +	g_return_if_fail (y >= 0); +	_tmp0_ = page_get_width (self); +	g_return_if_fail (x < _tmp0_); +	_tmp1_ = page_get_height (self); +	g_return_if_fail (y < _tmp1_); +	self->priv->crop_x = x; +	self->priv->crop_y = y; +	g_signal_emit_by_name (self, "crop-changed");  } -gboolean -page_has_data (Page *page) -{ -    g_return_val_if_fail (page != NULL, FALSE); -    return page->priv->has_data; +void page_rotate_crop (Page* self) { +	gint t = 0; +	g_return_if_fail (self != NULL); +	if (!self->priv->has_crop_) { +		return; +	} +	t = self->priv->crop_width; +	self->priv->crop_width = self->priv->crop_height; +	self->priv->crop_height = t; +	if (self->priv->crop_name == NULL) { +		gint w = 0; +		gint h = 0; +		gint _tmp0_; +		gint _tmp1_; +		_tmp0_ = page_get_width (self); +		w = _tmp0_; +		_tmp1_ = page_get_height (self); +		h = _tmp1_; +		if ((self->priv->crop_x + self->priv->crop_width) > w) { +			self->priv->crop_x = w - self->priv->crop_width; +		} +		if (self->priv->crop_x < 0) { +			self->priv->crop_x = 0; +			self->priv->crop_width = w; +		} +		if ((self->priv->crop_y + self->priv->crop_height) > h) { +			self->priv->crop_y = h - self->priv->crop_height; +		} +		if (self->priv->crop_y < 0) { +			self->priv->crop_y = 0; +			self->priv->crop_height = h; +		} +	} +	g_signal_emit_by_name (self, "crop-changed");  } -gboolean -page_is_color (Page *page) -{ -    g_return_val_if_fail (page != NULL, FALSE); -    return page->priv->n_channels > 1; +gboolean page_has_crop (Page* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->has_crop_; +	return result;  } -gint -page_get_scan_line (Page *page) -{ -    g_return_val_if_fail (page != NULL, -1); -    return page->priv->scan_line; +void page_get_crop (Page* self, gint* x, gint* y, gint* width, gint* height) { +	gint _x = 0; +	gint _y = 0; +	gint _width = 0; +	gint _height = 0; +	g_return_if_fail (self != NULL); +	_x = self->priv->crop_x; +	_y = self->priv->crop_y; +	_width = self->priv->crop_width; +	_height = self->priv->crop_height; +	if (x) { +		*x = _x; +	} +	if (y) { +		*y = _y; +	} +	if (width) { +		*width = _width; +	} +	if (height) { +		*height = _height; +	}  } -static void -parse_line (Page *page, ScanLine *line, gint n, gboolean *size_changed) -{ -    gint line_number; +gchar* page_get_named_crop (Page* self) { +	gchar* result = NULL; +	gchar* _tmp0_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = g_strdup (self->priv->crop_name); +	result = _tmp0_; +	return result; +} + + +guchar* page_get_pixels (Page* self, int* result_length1) { +	guchar* result = NULL; +	guchar* _tmp0_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = self->priv->pixels; +	if (result_length1) { +		*result_length1 = self->priv->pixels_length1; +	} +	result = _tmp0_; +	return result; +} + + +static guchar page_get_sample (Page* self, guchar* pixels, int pixels_length1, gint offset, gint x, gint depth, gint n_channels, gint channel) { +	guchar result = '\0'; +	g_return_val_if_fail (self != NULL, '\0'); +	result = (guchar) 0xFF; +	return result; +} + + +static void page_get_pixel (Page* self, gint x, gint y, guchar* pixel, int pixel_length1, gint offset) { +	ScanDirection _tmp0_; +	gint _tmp5_; +	gint depth; +	gint _tmp6_; +	gint n_channels; +	gint _tmp7_; +	gint line_offset; +	gboolean _tmp8_ = FALSE; +	guchar _tmp14_; +	guchar _tmp15_; +	guchar _tmp16_; +	g_return_if_fail (self != NULL); +	_tmp0_ = page_get_scan_direction (self); +	switch (_tmp0_) { +		case SCAN_DIRECTION_TOP_TO_BOTTOM: +		{ +			break; +		} +		case SCAN_DIRECTION_BOTTOM_TO_TOP: +		{ +			gint _tmp1_; +			gint _tmp2_; +			_tmp1_ = page_get_scan_width (self); +			x = (_tmp1_ - x) - 1; +			_tmp2_ = page_get_scan_height (self); +			y = (_tmp2_ - y) - 1; +			break; +		} +		case SCAN_DIRECTION_LEFT_TO_RIGHT: +		{ +			gint t; +			gint _tmp3_; +			t = x; +			_tmp3_ = page_get_scan_width (self); +			x = (_tmp3_ - y) - 1; +			y = t; +			break; +		} +		case SCAN_DIRECTION_RIGHT_TO_LEFT: +		{ +			gint t; +			gint _tmp4_; +			t = x; +			x = y; +			_tmp4_ = page_get_scan_height (self); +			y = (_tmp4_ - t) - 1; +			break; +		} +		default: +		break; +	} +	_tmp5_ = page_get_depth (self); +	depth = _tmp5_; +	_tmp6_ = page_get_n_channels (self); +	n_channels = _tmp6_; +	_tmp7_ = page_get_rowstride (self); +	line_offset = _tmp7_ * y; +	if (depth == 8) { +		_tmp8_ = n_channels == 3; +	} else { +		_tmp8_ = FALSE; +	} +	if (_tmp8_) { +		gint o; +		o = line_offset + (x * n_channels); +		pixel[offset + 0] = self->priv->pixels[o]; +		pixel[offset + 1] = self->priv->pixels[o + 1]; +		pixel[offset + 2] = self->priv->pixels[o + 2]; +		return; +	} else { +		gboolean _tmp9_ = FALSE; +		if (depth == 8) { +			_tmp9_ = n_channels == 1; +		} else { +			_tmp9_ = FALSE; +		} +		if (_tmp9_) { +			guchar p; +			p = self->priv->pixels[line_offset + x]; +			pixel[offset + 2] = p; +			pixel[offset + 1] = pixel[offset + 2]; +			pixel[offset + 0] = pixel[offset + 1]; +			return; +		} else { +			gboolean _tmp10_ = FALSE; +			if (depth == 1) { +				_tmp10_ = n_channels == 1; +			} else { +				_tmp10_ = FALSE; +			} +			if (_tmp10_) { +				guchar p; +				gint _tmp11_ = 0; +				p = self->priv->pixels[line_offset + (x / 8)]; +				if (((gint) (p & (0x80 >> (x % 8)))) != 0) { +					_tmp11_ = 0x00; +				} else { +					_tmp11_ = 0xFF; +				} +				pixel[offset + 2] = (guchar) _tmp11_; +				pixel[offset + 1] = pixel[offset + 2]; +				pixel[offset + 0] = pixel[offset + 1]; +				return; +			} else { +				gboolean _tmp12_ = FALSE; +				if (depth == 2) { +					_tmp12_ = n_channels == 1; +				} else { +					_tmp12_ = FALSE; +				} +				if (_tmp12_) { +					gint _tmp13_[4] = {0}; +					gint block_shift[4]; +					guchar p; +					gint sample; +					_tmp13_[0] = 6; +					_tmp13_[1] = 4; +					_tmp13_[2] = 2; +					_tmp13_[3] = 0; +					memcpy (block_shift, _tmp13_, 4 * sizeof (gint)); +					p = self->priv->pixels[line_offset + (x / 4)]; +					sample = (p >> block_shift[x % 4]) & 0x3; +					sample = (sample * 255) / 3; +					pixel[offset + 2] = (guchar) sample; +					pixel[offset + 1] = pixel[offset + 2]; +					pixel[offset + 0] = pixel[offset + 1]; +					return; +				} +			} +		} +	} +	_tmp14_ = page_get_sample (self, self->priv->pixels, self->priv->pixels_length1, line_offset, x, depth, n_channels, 0); +	pixel[offset + 0] = _tmp14_; +	_tmp15_ = page_get_sample (self, self->priv->pixels, self->priv->pixels_length1, line_offset, x, depth, n_channels, 1); +	pixel[offset + 1] = _tmp15_; +	_tmp16_ = page_get_sample (self, self->priv->pixels, self->priv->pixels_length1, line_offset, x, depth, n_channels, 2); +	pixel[offset + 2] = _tmp16_; +} + + +GdkPixbuf* page_get_image (Page* self, gboolean apply_crop) { +	GdkPixbuf* result = NULL; +	gint l = 0; +	gint r = 0; +	gint t = 0; +	gint b = 0; +	gboolean _tmp0_ = FALSE; +	GdkPixbuf* _tmp7_ = NULL; +	GdkPixbuf* image; +	guint8* _tmp8_ = NULL; +	guint8* image_pixels; +	gint image_pixels_length1; +	gint _image_pixels_size_; +	g_return_val_if_fail (self != NULL, NULL); +	if (apply_crop) { +		_tmp0_ = self->priv->has_crop_; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		gint _tmp1_; +		gint _tmp3_; +		l = self->priv->crop_x; +		r = l + self->priv->crop_width; +		t = self->priv->crop_y; +		b = t + self->priv->crop_height; +		if (l < 0) { +			l = 0; +		} +		_tmp1_ = page_get_width (self); +		if (r > _tmp1_) { +			gint _tmp2_; +			_tmp2_ = page_get_width (self); +			r = _tmp2_; +		} +		if (t < 0) { +			t = 0; +		} +		_tmp3_ = page_get_height (self); +		if (b > _tmp3_) { +			gint _tmp4_; +			_tmp4_ = page_get_height (self); +			b = _tmp4_; +		} +	} else { +		gint _tmp5_; +		gint _tmp6_; +		l = 0; +		_tmp5_ = page_get_width (self); +		r = _tmp5_; +		t = 0; +		_tmp6_ = page_get_height (self); +		b = _tmp6_; +	} +	_tmp7_ = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, r - l, b - t); +	image = _tmp7_; +	_tmp8_ = gdk_pixbuf_get_pixels (image); +	image_pixels = _tmp8_; +	image_pixels_length1 = -1; +	_image_pixels_size_ = image_pixels_length1; +	{ +		gint y; +		y = t; +		{ +			gboolean _tmp9_; +			_tmp9_ = TRUE; +			while (TRUE) { +				gint _tmp10_; +				gint offset; +				if (!_tmp9_) { +					y++; +				} +				_tmp9_ = FALSE; +				if (!(y < b)) { +					break; +				} +				_tmp10_ = gdk_pixbuf_get_rowstride (image); +				offset = _tmp10_ * (y - t); +				{ +					gint x; +					x = l; +					{ +						gboolean _tmp11_; +						_tmp11_ = TRUE; +						while (TRUE) { +							if (!_tmp11_) { +								x++; +							} +							_tmp11_ = FALSE; +							if (!(x < r)) { +								break; +							} +							page_get_pixel (self, x, y, image_pixels, image_pixels_length1, offset + ((x - l) * 3)); +						} +					} +				} +			} +		} +	} +	result = image; +	return result; +} + + +static gchar* string_to_utf8 (const gchar* self, int* result_length1) { +	gchar* result = NULL; +	gint _tmp0_; +	gchar* _tmp1_ = NULL; +	gchar* _result_; +	gint _result__length1; +	gint __result__size_; +	gint _tmp2_; +	gchar* _tmp3_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = strlen (self); +	_tmp1_ = g_new0 (gchar, _tmp0_ + 1); +	_result_ = _tmp1_; +	_result__length1 = _tmp0_ + 1; +	__result__size_ = _result__length1; +	_result__length1--; +	_tmp2_ = strlen (self); +	memcpy (_result_, self, (gsize) _tmp2_); +	_tmp3_ = _result_; +	if (result_length1) { +		*result_length1 = _result__length1; +	} +	result = _tmp3_; +	return result; +} + + +static gchar* page_get_icc_data_encoded (Page* self, const gchar* icc_profile_filename) { +	gchar* result = NULL; +	gchar* contents = NULL; +	gint _tmp1_; +	gchar* _tmp2_ = NULL; +	guchar* _tmp3_; +	gint _tmp3__length1; +	gchar* _tmp4_ = NULL; +	gchar* _tmp5_; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (icc_profile_filename != NULL, NULL); +	{ +		gchar* _tmp0_ = NULL; +		g_file_get_contents (icc_profile_filename, &_tmp0_, NULL, &_inner_error_); +		_g_free0 (contents); +		contents = _tmp0_; +		if (_inner_error_ != NULL) { +			goto __catch2_g_error; +		} +	} +	goto __finally2; +	__catch2_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("page.vala:670: failed to get icc profile data: %s", e->message); +		result = NULL; +		_g_error_free0 (e); +		_g_free0 (contents); +		return result; +	} +	__finally2: +	if (_inner_error_ != NULL) { +		_g_free0 (contents); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return NULL; +	} +	_tmp2_ = string_to_utf8 (contents, &_tmp1_); +	_tmp3_ = (guchar*) _tmp2_; +	_tmp3__length1 = _tmp1_; +	_tmp4_ = g_base64_encode (_tmp3_, _tmp1_); +	_tmp5_ = _tmp4_; +	_tmp3_ = (g_free (_tmp3_), NULL); +	result = _tmp5_; +	_g_free0 (contents); +	return result; +} -    line_number = line->number + n; -    /* Extend image if necessary */ -    while (line_number >= page_get_scan_height (page)) { -        gint rows; +void page_save (Page* self, const gchar* type, GFile* file, GError** error) { +	GFileOutputStream* _tmp0_ = NULL; +	GFileOutputStream* stream; +	PixbufWriter* _tmp1_ = NULL; +	PixbufWriter* writer; +	GdkPixbuf* _tmp2_ = NULL; +	GdkPixbuf* image; +	gchar* icc_profile_data; +	gint _tmp4_; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (type != NULL); +	g_return_if_fail (file != NULL); +	_tmp0_ = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &_inner_error_); +	stream = _tmp0_; +	if (_inner_error_ != NULL) { +		g_propagate_error (error, _inner_error_); +		return; +	} +	_tmp1_ = pixbuf_writer_new (stream); +	writer = _tmp1_; +	_tmp2_ = page_get_image (self, TRUE); +	image = _tmp2_; +	icc_profile_data = NULL; +	if (self->priv->color_profile != NULL) { +		gchar* _tmp3_ = NULL; +		_tmp3_ = page_get_icc_data_encoded (self, self->priv->color_profile); +		_g_free0 (icc_profile_data); +		icc_profile_data = _tmp3_; +	} +	_tmp4_ = g_strcmp0 (type, "jpeg"); +	if (_tmp4_ == 0) { +		gchar* _tmp5_; +		gchar** _tmp6_ = NULL; +		gchar** keys; +		gint keys_length1; +		gint _keys_size_; +		gchar* _tmp7_; +		gchar** _tmp8_ = NULL; +		gchar** values; +		gint values_length1; +		gint _values_size_; +		_tmp5_ = g_strdup ("quality"); +		_tmp6_ = g_new0 (gchar*, 2 + 1); +		_tmp6_[0] = _tmp5_; +		_tmp6_[1] = NULL; +		keys = _tmp6_; +		keys_length1 = 2; +		_keys_size_ = keys_length1; +		_tmp7_ = g_strdup ("90"); +		_tmp8_ = g_new0 (gchar*, 2 + 1); +		_tmp8_[0] = _tmp7_; +		_tmp8_[1] = NULL; +		values = _tmp8_; +		values_length1 = 2; +		_values_size_ = values_length1; +		pixbuf_writer_save (writer, image, "jpeg", keys, keys_length1, values, values_length1, &_inner_error_); +		if (_inner_error_ != NULL) { +			g_propagate_error (error, _inner_error_); +			values = (_vala_array_free (values, values_length1, (GDestroyNotify) g_free), NULL); +			keys = (_vala_array_free (keys, keys_length1, (GDestroyNotify) g_free), NULL); +			_g_free0 (icc_profile_data); +			_g_object_unref0 (image); +			_pixbuf_writer_unref0 (writer); +			_g_object_unref0 (stream); +			return; +		} +		values = (_vala_array_free (values, values_length1, (GDestroyNotify) g_free), NULL); +		keys = (_vala_array_free (keys, keys_length1, (GDestroyNotify) g_free), NULL); +	} else { +		gint _tmp9_; +		_tmp9_ = g_strcmp0 (type, "png"); +		if (_tmp9_ == 0) { +			gchar* _tmp10_; +			gchar** _tmp11_ = NULL; +			gchar** keys; +			gint keys_length1; +			gint _keys_size_; +			gchar* _tmp12_; +			gchar** _tmp13_ = NULL; +			gchar** values; +			gint values_length1; +			gint _values_size_; +			_tmp10_ = g_strdup ("icc-profile"); +			_tmp11_ = g_new0 (gchar*, 2 + 1); +			_tmp11_[0] = _tmp10_; +			_tmp11_[1] = NULL; +			keys = _tmp11_; +			keys_length1 = 2; +			_keys_size_ = keys_length1; +			_tmp12_ = g_strdup (icc_profile_data); +			_tmp13_ = g_new0 (gchar*, 2 + 1); +			_tmp13_[0] = _tmp12_; +			_tmp13_[1] = NULL; +			values = _tmp13_; +			values_length1 = 2; +			_values_size_ = values_length1; +			if (icc_profile_data == NULL) { +				gchar* _tmp14_; +				_tmp14_ = NULL; +				_g_free0 (keys[0]); +				keys[0] = _tmp14_; +			} +			pixbuf_writer_save (writer, image, "png", keys, keys_length1, values, values_length1, &_inner_error_); +			if (_inner_error_ != NULL) { +				g_propagate_error (error, _inner_error_); +				values = (_vala_array_free (values, values_length1, (GDestroyNotify) g_free), NULL); +				keys = (_vala_array_free (keys, keys_length1, (GDestroyNotify) g_free), NULL); +				_g_free0 (icc_profile_data); +				_g_object_unref0 (image); +				_pixbuf_writer_unref0 (writer); +				_g_object_unref0 (stream); +				return; +			} +			values = (_vala_array_free (values, values_length1, (GDestroyNotify) g_free), NULL); +			keys = (_vala_array_free (keys, keys_length1, (GDestroyNotify) g_free), NULL); +		} else { +			gint _tmp15_; +			_tmp15_ = g_strcmp0 (type, "tiff"); +			if (_tmp15_ == 0) { +				gchar* _tmp16_; +				gchar* _tmp17_; +				gchar** _tmp18_ = NULL; +				gchar** keys; +				gint keys_length1; +				gint _keys_size_; +				gchar* _tmp19_; +				gchar* _tmp20_; +				gchar** _tmp21_ = NULL; +				gchar** values; +				gint values_length1; +				gint _values_size_; +				_tmp16_ = g_strdup ("compression"); +				_tmp17_ = g_strdup ("icc-profile"); +				_tmp18_ = g_new0 (gchar*, 3 + 1); +				_tmp18_[0] = _tmp16_; +				_tmp18_[1] = _tmp17_; +				_tmp18_[2] = NULL; +				keys = _tmp18_; +				keys_length1 = 3; +				_keys_size_ = keys_length1; +				_tmp19_ = g_strdup ("8"); +				_tmp20_ = g_strdup (icc_profile_data); +				_tmp21_ = g_new0 (gchar*, 3 + 1); +				_tmp21_[0] = _tmp19_; +				_tmp21_[1] = _tmp20_; +				_tmp21_[2] = NULL; +				values = _tmp21_; +				values_length1 = 3; +				_values_size_ = values_length1; +				if (icc_profile_data == NULL) { +					gchar* _tmp22_; +					_tmp22_ = NULL; +					_g_free0 (keys[1]); +					keys[1] = _tmp22_; +				} +				pixbuf_writer_save (writer, image, "tiff", keys, keys_length1, values, values_length1, &_inner_error_); +				if (_inner_error_ != NULL) { +					g_propagate_error (error, _inner_error_); +					values = (_vala_array_free (values, values_length1, (GDestroyNotify) g_free), NULL); +					keys = (_vala_array_free (keys, keys_length1, (GDestroyNotify) g_free), NULL); +					_g_free0 (icc_profile_data); +					_g_object_unref0 (image); +					_pixbuf_writer_unref0 (writer); +					_g_object_unref0 (stream); +					return; +				} +				values = (_vala_array_free (values, values_length1, (GDestroyNotify) g_free), NULL); +				keys = (_vala_array_free (keys, keys_length1, (GDestroyNotify) g_free), NULL); +			} else { +			} +		} +	} +	_g_free0 (icc_profile_data); +	_g_object_unref0 (image); +	_pixbuf_writer_unref0 (writer); +	_g_object_unref0 (stream); +} -        /* Extend image */ -        rows = page->priv->n_rows; -        page->priv->n_rows = rows + page->priv->width / 2; -        g_debug("Extending image from %d lines to %d lines", rows, page->priv->n_rows); -        page->priv->pixels = g_realloc (page->priv->pixels, page->priv->n_rows * page->priv->rowstride); -        *size_changed = TRUE; -    } +static void value_page_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} -    /* Copy in new row */ -    memcpy (page->priv->pixels + line_number * page->priv->rowstride, line->data + n * line->data_length, line->data_length); -    page->priv->scan_line = line_number; +static void value_page_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		page_unref (value->data[0].v_pointer); +	}  } -void -page_parse_scan_line (Page *page, ScanLine *line) -{ -    gint i; -    gboolean size_changed = FALSE; +static void value_page_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = page_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} -    g_return_if_fail (page != NULL); -    for (i = 0; i < line->n_lines; i++) -        parse_line (page, line, i, &size_changed); +static gpointer value_page_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} -    page->priv->has_data = TRUE; -    if (size_changed) -        g_signal_emit (page, signals[SIZE_CHANGED], 0); -    g_signal_emit (page, signals[SCAN_LINE_CHANGED], 0); -    g_signal_emit (page, signals[PIXELS_CHANGED], 0); +static gchar* value_page_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Page* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = page_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL;  } -void -page_finish (Page *page) -{ -    gboolean size_changed = FALSE; +static gchar* value_page_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Page** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = page_ref (value->data[0].v_pointer); +	} +	return NULL; +} -    g_return_if_fail (page != NULL); -    /* Trim page */ -    if (page->priv->expected_rows < 0 && -        page->priv->scan_line != page_get_scan_height (page)) { -        gint rows; +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecPage* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_PAGE), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + -        rows = page->priv->n_rows; -        page->priv->n_rows = page->priv->scan_line; -        page->priv->pixels = g_realloc (page->priv->pixels, page->priv->n_rows * page->priv->rowstride); -        g_debug("Trimming page from %d lines to %d lines", rows, page->priv->n_rows); +gpointer value_get_page (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PAGE), NULL); +	return value->data[0].v_pointer; +} -        size_changed = TRUE; -    } -    page->priv->scanning = FALSE; -    if (size_changed) -        g_signal_emit (page, signals[SIZE_CHANGED], 0); -    g_signal_emit (page, signals[SCAN_LINE_CHANGED], 0); +void value_set_page (GValue* value, gpointer v_object) { +	Page* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PAGE)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PAGE)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		page_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		page_unref (old); +	}  } -ScanDirection -page_get_scan_direction (Page *page) -{ -    g_return_val_if_fail (page != NULL, TOP_TO_BOTTOM); +void value_take_page (GValue* value, gpointer v_object) { +	Page* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PAGE)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PAGE)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		page_unref (old); +	} +} + -    return page->priv->scan_direction; +static void page_class_init (PageClass * klass) { +	page_parent_class = g_type_class_peek_parent (klass); +	PAGE_CLASS (klass)->finalize = page_finalize; +	g_type_class_add_private (klass, sizeof (PagePrivate)); +	g_signal_new ("pixels_changed", TYPE_PAGE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("size_changed", TYPE_PAGE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("scan_line_changed", TYPE_PAGE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("scan_direction_changed", TYPE_PAGE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("crop_changed", TYPE_PAGE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);  } -static void -page_set_scan_direction (Page *page, ScanDirection scan_direction) -{ -    gint left_steps, t; -    gboolean size_changed = FALSE; -    gint width, height; +static void page_instance_init (Page * self) { +	self->priv = PAGE_GET_PRIVATE (self); +	self->priv->scan_direction = SCAN_DIRECTION_TOP_TO_BOTTOM; +	self->ref_count = 1; +} -    g_return_if_fail (page != NULL); -    if (page->priv->scan_direction == scan_direction) -        return; +static void page_finalize (Page* obj) { +	Page * self; +	self = PAGE (obj); +	_g_free0 (self->priv->color_profile); +	self->priv->pixels = (g_free (self->priv->pixels), NULL); +	_g_free0 (self->priv->crop_name); +} -    /* Work out how many times it has been rotated to the left */ -    left_steps = scan_direction - page->priv->scan_direction; -    if (left_steps < 0) -        left_steps += 4; -    if (left_steps != 2) -        size_changed = TRUE; -   -    width = page_get_width (page); -    height = page_get_height (page); -    /* Rotate crop */ -    if (page->priv->has_crop) { -        switch (left_steps) { -        /* 90 degrees counter-clockwise */ -        case 1: -            t = page->priv->crop_x; -            page->priv->crop_x = page->priv->crop_y; -            page->priv->crop_y = width - (t + page->priv->crop_width); -            t = page->priv->crop_width; -            page->priv->crop_width = page->priv->crop_height; -            page->priv->crop_height = t; -            break; -        /* 180 degrees */ -        case 2: -            page->priv->crop_x = width - (page->priv->crop_x + page->priv->crop_width); -            page->priv->crop_y = width - (page->priv->crop_y + page->priv->crop_height); -            break; -        /* 90 degrees clockwise */ -        case 3: -            t = page->priv->crop_y; -            page->priv->crop_y = page->priv->crop_x; -            page->priv->crop_x = height - (t + page->priv->crop_height); -            t = page->priv->crop_width; -            page->priv->crop_width = page->priv->crop_height; -            page->priv->crop_height = t; -            break; -        } -    } +GType page_get_type (void) { +	static volatile gsize page_type_id__volatile = 0; +	if (g_once_init_enter (&page_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_page_init, value_page_free_value, value_page_copy_value, value_page_peek_pointer, "p", value_page_collect_value, "p", value_page_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (PageClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) page_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Page), 0, (GInstanceInitFunc) page_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType page_type_id; +		page_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Page", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&page_type_id__volatile, page_type_id); +	} +	return page_type_id__volatile; +} + -    page->priv->scan_direction = scan_direction; -    if (size_changed) -        g_signal_emit (page, signals[SIZE_CHANGED], 0); -    g_signal_emit (page, signals[SCAN_DIRECTION_CHANGED], 0); -    if (page->priv->has_crop) -        g_signal_emit (page, signals[CROP_CHANGED], 0); +gpointer page_ref (gpointer instance) { +	Page* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance;  } -void -page_rotate_left (Page *page) -{ -    ScanDirection scan_direction; +void page_unref (gpointer instance) { +	Page* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		PAGE_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} -    g_return_if_fail (page != NULL); -    scan_direction = page_get_scan_direction (page); -    if (scan_direction == RIGHT_TO_LEFT) -        scan_direction = TOP_TO_BOTTOM; -    else -        scan_direction++; -    page_set_scan_direction (page, scan_direction); +static gpointer _g_object_ref0 (gpointer self) { +	return self ? g_object_ref (self) : NULL;  } -void -page_rotate_right (Page *page) -{ -    ScanDirection scan_direction; +PixbufWriter* pixbuf_writer_construct (GType object_type, GFileOutputStream* stream) { +	PixbufWriter* self = NULL; +	GFileOutputStream* _tmp0_; +	g_return_val_if_fail (stream != NULL, NULL); +	self = (PixbufWriter*) g_type_create_instance (object_type); +	_tmp0_ = _g_object_ref0 (stream); +	_g_object_unref0 (self->stream); +	self->stream = _tmp0_; +	return self; +} + -    scan_direction = page_get_scan_direction (page); -    if (scan_direction == TOP_TO_BOTTOM) -        scan_direction = RIGHT_TO_LEFT; -    else -        scan_direction--; -    page_set_scan_direction (page, scan_direction); +PixbufWriter* pixbuf_writer_new (GFileOutputStream* stream) { +	return pixbuf_writer_construct (TYPE_PIXBUF_WRITER, stream);  } -gint -page_get_dpi (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); +static gboolean _pixbuf_writer_write_pixbuf_data_gdk_pixbuf_save_func (guint8* buf, gsize buf_length1, GError** error, gpointer self) { +	gboolean result; +	result = pixbuf_writer_write_pixbuf_data (self, buf, buf_length1, error); +	return result; +} -    return page->priv->dpi; + +void pixbuf_writer_save (PixbufWriter* self, GdkPixbuf* image, const gchar* type, gchar** option_keys, int option_keys_length1, gchar** option_values, int option_values_length1, GError** error) { +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (image != NULL); +	g_return_if_fail (type != NULL); +	gdk_pixbuf_save_to_callbackv (image, _pixbuf_writer_write_pixbuf_data_gdk_pixbuf_save_func, self, type, option_keys, option_values, &_inner_error_); +	if (_inner_error_ != NULL) { +		g_propagate_error (error, _inner_error_); +		return; +	}  } -gboolean -page_is_landscape (Page *page) -{ -   return page_get_width (page) > page_get_height (page); +static gboolean pixbuf_writer_write_pixbuf_data (PixbufWriter* self, guint8* buf, int buf_length1, GError** error) { +	gboolean result = FALSE; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, FALSE); +	g_output_stream_write_all ((GOutputStream*) self->stream, buf, (gsize) buf_length1, NULL, NULL, &_inner_error_); +	if (_inner_error_ != NULL) { +		g_propagate_error (error, _inner_error_); +		return FALSE; +	} +	result = TRUE; +	return result;  } -gint -page_get_width (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); +static void value_pixbuf_writer_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + -    if (page->priv->scan_direction == TOP_TO_BOTTOM || page->priv->scan_direction == BOTTOM_TO_TOP) -        return page->priv->width; -    else -        return page->priv->n_rows; +static void value_pixbuf_writer_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		pixbuf_writer_unref (value->data[0].v_pointer); +	}  } -gint -page_get_height (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); +static void value_pixbuf_writer_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = pixbuf_writer_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + -    if (page->priv->scan_direction == TOP_TO_BOTTOM || page->priv->scan_direction == BOTTOM_TO_TOP) -        return page->priv->n_rows; -    else -        return page->priv->width; +static gpointer value_pixbuf_writer_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer;  } -gint -page_get_depth (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); -    return page->priv->depth; +static gchar* value_pixbuf_writer_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		PixbufWriter* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = pixbuf_writer_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL;  } -gint page_get_n_channels (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); -    return page->priv->n_channels; +static gchar* value_pixbuf_writer_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	PixbufWriter** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = pixbuf_writer_ref (value->data[0].v_pointer); +	} +	return NULL;  } -gint page_get_rowstride (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); -    return page->priv->rowstride; +GParamSpec* param_spec_pixbuf_writer (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecPixbufWriter* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_PIXBUF_WRITER), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec);  } -gint -page_get_scan_width (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); +gpointer value_get_pixbuf_writer (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PIXBUF_WRITER), NULL); +	return value->data[0].v_pointer; +} + -    return page->priv->width; +void value_set_pixbuf_writer (GValue* value, gpointer v_object) { +	PixbufWriter* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PIXBUF_WRITER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PIXBUF_WRITER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		pixbuf_writer_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		pixbuf_writer_unref (old); +	}  } -gint -page_get_scan_height (Page *page) -{ -    g_return_val_if_fail (page != NULL, 0); +void value_take_pixbuf_writer (GValue* value, gpointer v_object) { +	PixbufWriter* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_PIXBUF_WRITER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_PIXBUF_WRITER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		pixbuf_writer_unref (old); +	} +} + -    return page->priv->n_rows; +static void pixbuf_writer_class_init (PixbufWriterClass * klass) { +	pixbuf_writer_parent_class = g_type_class_peek_parent (klass); +	PIXBUF_WRITER_CLASS (klass)->finalize = pixbuf_writer_finalize;  } -void page_set_color_profile (Page *page, const gchar *color_profile) -{ -     g_free (page->priv->color_profile); -     page->priv->color_profile = g_strdup (color_profile); +static void pixbuf_writer_instance_init (PixbufWriter * self) { +	self->ref_count = 1;  } -const gchar *page_get_color_profile (Page *page) -{ -     return page->priv->color_profile; +static void pixbuf_writer_finalize (PixbufWriter* obj) { +	PixbufWriter * self; +	self = PIXBUF_WRITER (obj); +	_g_object_unref0 (self->stream);  } -void -page_set_no_crop (Page *page) -{ -    g_return_if_fail (page != NULL); +GType pixbuf_writer_get_type (void) { +	static volatile gsize pixbuf_writer_type_id__volatile = 0; +	if (g_once_init_enter (&pixbuf_writer_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_pixbuf_writer_init, value_pixbuf_writer_free_value, value_pixbuf_writer_copy_value, value_pixbuf_writer_peek_pointer, "p", value_pixbuf_writer_collect_value, "p", value_pixbuf_writer_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (PixbufWriterClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) pixbuf_writer_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (PixbufWriter), 0, (GInstanceInitFunc) pixbuf_writer_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType pixbuf_writer_type_id; +		pixbuf_writer_type_id = g_type_register_fundamental (g_type_fundamental_next (), "PixbufWriter", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&pixbuf_writer_type_id__volatile, pixbuf_writer_type_id); +	} +	return pixbuf_writer_type_id__volatile; +} + -    if (!page->priv->has_crop) -        return; -    page->priv->has_crop = FALSE; -    g_signal_emit (page, signals[CROP_CHANGED], 0); +gpointer pixbuf_writer_ref (gpointer instance) { +	PixbufWriter* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance;  } -void -page_set_custom_crop (Page *page, gint width, gint height) -{ -    //gint pw, ph; +void pixbuf_writer_unref (gpointer instance) { +	PixbufWriter* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		PIXBUF_WRITER_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + -    g_return_if_fail (page != NULL); -    g_return_if_fail (width >= 1); -    g_return_if_fail (height >= 1); -     -    if (!page->priv->crop_name && -        page->priv->has_crop && -        page->priv->crop_width == width && -        page->priv->crop_height == height) -        return; -    g_free (page->priv->crop_name); -    page->priv->crop_name = NULL; -    page->priv->has_crop = TRUE; +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	if ((array != NULL) && (destroy_func != NULL)) { +		int i; +		for (i = 0; i < array_length; i = i + 1) { +			if (((gpointer*) array)[i] != NULL) { +				destroy_func (((gpointer*) array)[i]); +			} +		} +	} +} -    page->priv->crop_width = width; -    page->priv->crop_height = height; -    /*pw = page_get_width (page); -    ph = page_get_height (page); -    if (page->priv->crop_width < pw) -        page->priv->crop_x = (pw - page->priv->crop_width) / 2; -    else -        page->priv->crop_x = 0; -    if (page->priv->crop_height < ph) -        page->priv->crop_y = (ph - page->priv->crop_height) / 2; -    else -        page->priv->crop_y = 0;*/ -     -    g_signal_emit (page, signals[CROP_CHANGED], 0); -} - - -void -page_set_named_crop (Page *page, const gchar *name) -{ -    struct { -        const gchar *name; -        /* Width and height in inches */ -        gdouble width, height; -    } named_crops[] = -    { -        {"A4", 8.3, 11.7}, -        {"A5", 5.8, 8.3}, -        {"A6", 4.1, 5.8}, -        {"letter", 8.5, 11}, -        {"legal", 8.5, 14}, -        {"4x6", 4, 6}, -        {NULL, 0, 0} -    }; -    gint i; -    gint pw, ph; -    double width, height; - -    g_return_if_fail (page != NULL); -     -    for (i = 0; named_crops[i].name && strcmp (name, named_crops[i].name) != 0; i++); -    width = named_crops[i].width; -    height = named_crops[i].height; - -    if (!named_crops[i].name) { -        g_warning ("Unknown paper size '%s'", name); -        return; -    } - -    g_free (page->priv->crop_name); -    page->priv->crop_name = g_strdup (name); -    page->priv->has_crop = TRUE; -     -    pw = page_get_width (page); -    ph = page_get_height (page); -    -    /* Rotate to match original aspect */ -    if (pw > ph) { -        double t; -        t = width; -        width = height; -        height = t; -    } - -    /* Custom crop, make slightly smaller than original */ -    page->priv->crop_width = (int) (width * page->priv->dpi + 0.5); -    page->priv->crop_height = (int) (height * page->priv->dpi + 0.5); -         -    if (page->priv->crop_width < pw) -        page->priv->crop_x = (pw - page->priv->crop_width) / 2; -    else -        page->priv->crop_x = 0; -    if (page->priv->crop_height < ph) -        page->priv->crop_y = (ph - page->priv->crop_height) / 2; -    else -        page->priv->crop_y = 0; -    g_signal_emit (page, signals[CROP_CHANGED], 0); -} - - -void -page_move_crop (Page *page, gint x, gint y) -{ -    g_return_if_fail (x >= 0); -    g_return_if_fail (y >= 0); -    g_return_if_fail (x < page_get_width (page)); -    g_return_if_fail (y < page_get_height (page)); - -    page->priv->crop_x = x; -    page->priv->crop_y = y; -    g_signal_emit (page, signals[CROP_CHANGED], 0);     -} - - -void -page_rotate_crop (Page *page) -{ -    gint t; -     -    g_return_if_fail (page != NULL); -   -    if (!page->priv->has_crop) -        return; - -    t = page->priv->crop_width; -    page->priv->crop_width = page->priv->crop_height; -    page->priv->crop_height = t; -   -    /* Clip custom crops */ -    if (!page->priv->crop_name) { -        gint w, h; - -        w = page_get_width (page); -        h = page_get_height (page); -         -        if (page->priv->crop_x + page->priv->crop_width > w) -            page->priv->crop_x = w - page->priv->crop_width; -        if (page->priv->crop_x < 0) { -            page->priv->crop_x = 0; -            page->priv->crop_width = w; -        } -        if (page->priv->crop_y + page->priv->crop_height > h) -            page->priv->crop_y = h - page->priv->crop_height; -        if (page->priv->crop_y < 0) { -            page->priv->crop_y = 0; -            page->priv->crop_height = h; -        } -    } - -    g_signal_emit (page, signals[CROP_CHANGED], 0); -} - - -gboolean -page_has_crop (Page *page) -{ -    g_return_val_if_fail (page != NULL, FALSE); -    return page->priv->has_crop; -} - - -void -page_get_crop (Page *page, gint *x, gint *y, gint *width, gint *height) -{ -    g_return_if_fail (page != NULL); - -    if (x) -        *x = page->priv->crop_x; -    if (y) -        *y = page->priv->crop_y; -    if (width) -        *width = page->priv->crop_width; -    if (height) -        *height = page->priv->crop_height; -} - - -gchar * -page_get_named_crop (Page *page) -{ -    g_return_val_if_fail (page != NULL, NULL); - -    if (page->priv->crop_name) -        return g_strdup (page->priv->crop_name); -    else -        return NULL; -} - - -const guchar * -page_get_pixels (Page *page) -{ -    g_return_val_if_fail (page != NULL, NULL); -    return page->priv->pixels; -} - - -// FIXME: Copied from page-view, should be shared code -static guchar -get_sample (const guchar *line, gint x, gint depth, gint n_channels, gint channel) -{ -    // FIXME -    return 0xFF; -} - - -// FIXME: Copied from page-view, should be shared code -static void -get_pixel (Page *page, gint x, gint y, guchar *pixel) -{ -    gint t, depth, n_channels; -    const guchar *p, *line; - -    switch (page_get_scan_direction (page)) -    { -    case TOP_TO_BOTTOM: -        break; -    case BOTTOM_TO_TOP: -        x = page_get_scan_width (page) - x - 1; -        y = page_get_scan_height (page) - y - 1; -        break; -    case LEFT_TO_RIGHT: -        t = x; -        x = page_get_scan_width (page) - y - 1; -        y = t; -        break; -    case RIGHT_TO_LEFT: -        t = x; -        x = y; -        y = page_get_scan_height (page) - t - 1; -        break; -    } - -    depth = page_get_depth (page); -    n_channels = page_get_n_channels (page); -    line = page_get_pixels (page) + page_get_rowstride (page) * y; - -    /* Optimise for 8 bit images */ -    if (depth == 8 && n_channels == 3) { -        p = line + x * n_channels; -        pixel[0] = p[0]; -        pixel[1] = p[1]; -        pixel[2] = p[2]; -        return; -    } -    else if (depth == 8 && n_channels == 1) { -        p = line + x; -        pixel[0] = pixel[1] = pixel[2] = p[0]; -        return; -    } - -    /* Optimise for bitmaps */ -    else if (depth == 1 && n_channels == 1) { -        p = line + (x / 8); -        pixel[0] = pixel[1] = pixel[2] = p[0] & (0x80 >> (x % 8)) ? 0x00 : 0xFF; -        return; -    } - -    /* Optimise for 2 bit images */ -    else if (depth == 2 && n_channels == 1) { -        gint sample; -        gint block_shift[4] = { 6, 4, 2, 0 }; - -        p = line + (x / 4); -        sample = (p[0] >> block_shift[x % 4]) & 0x3; -        sample = sample * 255 / 3; - -        pixel[0] = pixel[1] = pixel[2] = sample; -        return; -    } - -    /* Use slow method */ -    pixel[0] = get_sample (line, x, depth, n_channels, 0); -    pixel[0] = get_sample (line, x, depth, n_channels, 1); -    pixel[0] = get_sample (line, x, depth, n_channels, 2); -} - - -GdkPixbuf * -page_get_image (Page *page, gboolean apply_crop) -{ -    GdkPixbuf *image; -    gint x, y, l, r, t, b; - -    if (apply_crop && page->priv->has_crop) { -        l = page->priv->crop_x; -        r = l + page->priv->crop_width; -        t = page->priv->crop_y; -        b = t + page->priv->crop_height; -       -        if (l < 0) -            l = 0; -        if (r > page_get_width (page)) -            r = page_get_width (page); -        if (t < 0) -            t = 0; -        if (b > page_get_height (page)) -            b = page_get_height (page); -    } -    else { -        l = 0; -        r = page_get_width (page); -        t = 0; -        b = page_get_height (page); -    } - -    image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, r - l, b - t); - -    for (y = t; y < b; y++) { -        guchar *line = gdk_pixbuf_get_pixels (image) + gdk_pixbuf_get_rowstride (image) * (y - t); -        for (x = l; x < r; x++) { -            guchar *pixel; - -            pixel = line + (x - l) * 3; -            get_pixel (page, x, y, pixel); -        } -    } - -    return image; -} - - -static gboolean -write_pixbuf_data (const gchar *buf, gsize count, GError **error, GFileOutputStream *stream) -{ -    return g_output_stream_write_all (G_OUTPUT_STREAM (stream), buf, count, NULL, NULL, error); -} - - -static gchar * -get_icc_data_encoded (const gchar *icc_profile_filename) -{ -    gchar *contents = NULL; -    gchar *contents_encode = NULL; -    gsize length; -    gboolean ret; -    GError *error = NULL; - -    /* Get binary data */ -    ret = g_file_get_contents (icc_profile_filename, &contents, &length, &error); -    if (!ret) { -        g_warning ("failed to get icc profile data: %s", error->message); -        g_error_free (error); -    } -    else { -        /* Encode into base64 */ -        contents_encode = g_base64_encode ((const guchar *) contents, length); -    } -   -    g_free (contents); -    return contents_encode; -} - - -gboolean -page_save (Page *page, const gchar *type, GFile *file, GError **error) -{ -    GFileOutputStream *stream; -    GdkPixbuf *image; -    gboolean result = FALSE; -    gchar *icc_profile_data = NULL; - -    stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error); -    if (!stream) -        return FALSE; - -    image = page_get_image (page, TRUE); - -    if (page->priv->color_profile != NULL) -        icc_profile_data = get_icc_data_encoded (page->priv->color_profile); - -    if (strcmp (type, "jpeg") == 0) { -        /* ICC profile is awaiting review in gtk2+ bugzilla */ -        gchar *keys[] = { "quality", /* "icc-profile", */ NULL }; -        gchar *values[] = { "90", /* icc_profile_data, */ NULL }; -        result = gdk_pixbuf_save_to_callbackv (image, -                                               (GdkPixbufSaveFunc) write_pixbuf_data, stream, -                                               "jpeg", keys, values, error); -    } -    else if (strcmp (type, "png") == 0) { -        gchar *keys[] = { "icc-profile", NULL }; -        gchar *values[] = { icc_profile_data, NULL }; -        if (icc_profile_data == NULL) -            keys[0] = NULL; -        result = gdk_pixbuf_save_to_callbackv (image, -                                               (GdkPixbufSaveFunc) write_pixbuf_data, stream, -                                               "png", keys, values, error); -    } -    else if (strcmp (type, "tiff") == 0) { -        gchar *keys[] = { "compression", "icc-profile", NULL }; -        gchar *values[] = { "8" /* Deflate compression */, icc_profile_data, NULL }; -        if (icc_profile_data == NULL) -            keys[1] = NULL; -        result = gdk_pixbuf_save_to_callbackv (image, -                                               (GdkPixbufSaveFunc) write_pixbuf_data, stream, -                                               "tiff", keys, values, error); -    } -    else -        result = FALSE; // FIXME: Set GError - -    g_free (icc_profile_data); -    g_object_unref (image); -    g_object_unref (stream); - -    return result; -} - - -static void -page_finalize (GObject *object) -{ -    Page *page = PAGE (object); -    g_free (page->priv->pixels); -    G_OBJECT_CLASS (page_parent_class)->finalize (object); -} - - -static void -page_class_init (PageClass *klass) -{ -    GObjectClass *object_class = G_OBJECT_CLASS (klass); - -    object_class->finalize = page_finalize; - -    signals[PIXELS_CHANGED] = -        g_signal_new ("pixels-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageClass, pixels_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[SIZE_CHANGED] = -        g_signal_new ("size-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageClass, size_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[SCAN_LINE_CHANGED] = -        g_signal_new ("scan-line-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageClass, scan_line_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[SCAN_DIRECTION_CHANGED] = -        g_signal_new ("scan-direction-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageClass, scan_direction_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[CROP_CHANGED] = -        g_signal_new ("crop-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (PageClass, crop_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); - -    g_type_class_add_private (klass, sizeof (PagePrivate)); -} - - -static void -page_init (Page *page) -{ -    page->priv = G_TYPE_INSTANCE_GET_PRIVATE (page, PAGE_TYPE, PagePrivate); -    page->priv->scan_direction = TOP_TO_BOTTOM; +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	_vala_array_destroy (array, array_length, destroy_func); +	g_free (array);  } + + + diff --git a/src/page.h b/src/page.h deleted file mode 100644 index 993029f..0000000 --- a/src/page.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2009 Canonical Ltd. - * Author: Robert Ancell <robert.ancell@canonical.com> - *  - * This program 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 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _PAGE_H_ -#define _PAGE_H_ - -#include <glib-object.h> -#include <gio/gio.h> -#include <gdk-pixbuf/gdk-pixbuf.h> -#include "scanner.h" - -G_BEGIN_DECLS - -#define PAGE_TYPE  (page_get_type ()) -#define PAGE(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), PAGE_TYPE, Page)) -     -typedef enum -{ -    TOP_TO_BOTTOM, -    LEFT_TO_RIGHT, -    BOTTOM_TO_TOP, -    RIGHT_TO_LEFT -} ScanDirection; - - -typedef struct PagePrivate PagePrivate; - -typedef struct -{ -    GObject      parent_instance; -    PagePrivate *priv; -} Page; - -typedef struct -{ -    GObjectClass parent_class; - -    void (*pixels_changed) (Page *page); -    void (*size_changed) (Page *page); -    void (*scan_line_changed) (Page *page); -    void (*scan_direction_changed) (Page *page); -    void (*crop_changed) (Page *page); -} PageClass; - - -GType page_get_type (void); - -Page *page_new (gint width, gint height, gint dpi, ScanDirection scan_direction); - -void page_set_page_info (Page *page, ScanPageInfo *info); - -gint page_get_dpi (Page *page); - -gint page_get_width (Page *page); - -gint page_get_height (Page *page); - -gint page_get_depth (Page *page); - -gint page_get_n_channels (Page *page); - -gint page_get_rowstride (Page *page); - -const guchar *page_get_pixels (Page *page); - -guchar *page_get_pixel (Page *page, gint x, gint y); - -gboolean page_is_landscape (Page *page); - -gint page_get_scan_width (Page *page); - -gint page_get_scan_height (Page *page); - -void page_set_color_profile (Page *page, const gchar *color_profile); - -const gchar *page_get_color_profile (Page *page); - -void page_start (Page *page); - -gboolean page_is_scanning (Page *page); - -gboolean page_has_data (Page *page); - -gboolean page_is_color (Page *page); - -gint page_get_scan_line (Page *page); - -void page_parse_scan_line (Page *page, ScanLine *line); - -void page_finish (Page *page); - -ScanDirection page_get_scan_direction (Page *page); - -void page_rotate_left (Page *page); - -void page_rotate_right (Page *page); - -void page_set_no_crop (Page *page); - -void page_set_custom_crop (Page *page, gint width, gint height); - -void page_set_named_crop (Page *page, const gchar *name); - -void page_move_crop (Page *page, gint x, gint y); - -void page_rotate_crop (Page *page); - -gboolean page_has_crop (Page *page); - -void page_get_crop (Page *page, gint *x, gint *y, gint *width, gint *height); - -gchar *page_get_named_crop (Page *page); - -GdkPixbuf *page_get_image (Page *page, gboolean apply_crop); - -gboolean page_save (Page *page, const gchar *type, GFile *file, GError **error); - -#endif /* _PAGE_H_ */ diff --git a/src/page.vala b/src/page.vala new file mode 100644 index 0000000..ef7ddb6 --- /dev/null +++ b/src/page.vala @@ -0,0 +1,735 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +public enum ScanDirection +{ +    TOP_TO_BOTTOM, +    LEFT_TO_RIGHT, +    BOTTOM_TO_TOP, +    RIGHT_TO_LEFT +} + +public class Page +{ +    /* Resolution of page */ +    private int dpi; + +    /* Number of rows in this page or -1 if currently unknown */ +    private int expected_rows; + +    /* Bit depth */ +    private int depth; + +    /* Color profile */ +    private string? color_profile; + +    /* Scanned image data */ +    private int width; +    private int n_rows; +    private int rowstride; +    private int n_channels; +    private uchar[] pixels; + +    /* Page is getting data */ +    private bool scanning; + +    /* true if have some page data */ +    private bool has_data_; + +    /* Expected next scan row */ +    private int scan_line; + +    /* Rotation of scanned data */ +    private ScanDirection scan_direction = ScanDirection.TOP_TO_BOTTOM; + +    /* Crop */ +    private bool has_crop_; +    private string? crop_name; +    private int crop_x; +    private int crop_y; +    private int crop_width; +    private int crop_height; +     +    public signal void pixels_changed (); +    public signal void size_changed (); +    public signal void scan_line_changed (); +    public signal void scan_direction_changed (); +    public signal void crop_changed (); + +    public Page (int width, int height, int dpi, ScanDirection scan_direction) +    { +        if (scan_direction == ScanDirection.TOP_TO_BOTTOM || scan_direction == ScanDirection.BOTTOM_TO_TOP) +        { +            this.width = width; +            n_rows = height; +        } +        else +        { +            this.width = height; +            n_rows = width; +        } +        this.dpi = dpi; +        this.scan_direction = scan_direction; +    } + +    public void set_page_info (ScanPageInfo info) +    { +        expected_rows = info.height; +        dpi = (int) info.dpi; +         +        /* Create a white page */ +        width = info.width; +        n_rows = info.height; +        /* Variable height, try 50% of the width for now */ +        if (n_rows < 0) +            n_rows = width / 2; +        depth = info.depth; +        n_channels = info.n_channels; +        rowstride = (width * depth * n_channels + 7) / 8; +        pixels.resize (n_rows * rowstride); +        return_if_fail (pixels != null); + +        /* Fill with white */ +        if (depth == 1) +            Memory.set (pixels, 0x00, n_rows * rowstride); +        else +            Memory.set (pixels, 0xFF, n_rows * rowstride); + +        size_changed (); +        pixels_changed (); +    } + +    public void start () +    { +        scanning = true; +        scan_line_changed (); +    } + +    public bool is_scanning () +    { +        return scanning; +    } + +    public bool has_data () +    { +        return has_data_; +    } + +    public bool is_color () +    { +        return n_channels > 1; +    } + +    public int get_scan_line () +    { +        return scan_line; +    } + +    private void parse_line (ScanLine line, int n, out bool size_changed) +    { +        int line_number; + +        line_number = line.number + n; + +        /* Extend image if necessary */ +        size_changed = false; +        while (line_number >= get_scan_height ()) +        { +            int rows; + +            /* Extend image */ +            rows = n_rows; +            n_rows = rows + width / 2; +            debug ("Extending image from %d lines to %d lines", rows, n_rows); +            pixels.resize (n_rows * rowstride); + +            size_changed = true; +        } + +        /* Copy in new row */ +        var offset = line_number * rowstride; +        var line_offset = n * line.data_length; +        for (var i = 0; i < line.data_length; i++) +            pixels[offset+i] = line.data[line_offset+i]; + +        scan_line = line_number; +    } + +    public void parse_scan_line (ScanLine line) +    { +        bool size_has_changed = false; +        for (var i = 0; i < line.n_lines; i++) +            parse_line (line, i, out size_has_changed); + +        has_data_ = true; + +        if (size_has_changed) +            size_changed (); +        scan_line_changed (); +        pixels_changed (); +    } + +    public void finish () +    { +        bool size_has_changed = false; + +        /* Trim page */ +        if (expected_rows < 0 && +            scan_line != get_scan_height ()) +        { +            int rows; + +            rows = n_rows; +            n_rows = scan_line; +            pixels.resize (n_rows * rowstride); +            debug ("Trimming page from %d lines to %d lines", rows, n_rows); + +            size_has_changed = true; +        } +        scanning = false; + +        if (size_has_changed) +            size_changed (); +        scan_line_changed (); +    } + +    public ScanDirection get_scan_direction () +    { +        return scan_direction; +    } + +    private void set_scan_direction (ScanDirection direction) +    { +        int left_steps, t; +        bool size_has_changed = false; +        int width, height; + +        if (scan_direction == direction) +            return; + +        /* Work out how many times it has been rotated to the left */ +        left_steps = direction - scan_direction; +        if (left_steps < 0) +            left_steps += 4; +        if (left_steps != 2) +            size_has_changed = true; + +        width = get_width (); +        height = get_height (); + +        /* Rotate crop */ +        if (has_crop_) +        { +            switch (left_steps) +            { +            /* 90 degrees counter-clockwise */ +            case 1: +                t = crop_x; +                crop_x = crop_y; +                crop_y = width - (t + crop_width); +                t = crop_width; +                crop_width = crop_height; +                crop_height = t; +                break; +            /* 180 degrees */ +            case 2: +                crop_x = width - (crop_x + crop_width); +                crop_y = width - (crop_y + crop_height); +                break; +            /* 90 degrees clockwise */ +            case 3: +                t = crop_y; +                crop_y = crop_x; +                crop_x = height - (t + crop_height); +                t = crop_width; +                crop_width = crop_height; +                crop_height = t; +                break; +            } +        } + +        scan_direction = direction; +        if (size_has_changed) +            size_changed (); +        scan_direction_changed (); +        if (has_crop_) +            crop_changed (); +    } + +    public void rotate_left () +    { +        var direction = scan_direction; +        switch (direction) +        { +        case ScanDirection.TOP_TO_BOTTOM: +            direction = ScanDirection.LEFT_TO_RIGHT; +            break; +        case ScanDirection.LEFT_TO_RIGHT: +            direction = ScanDirection.BOTTOM_TO_TOP; +            break; +        case ScanDirection.BOTTOM_TO_TOP: +            direction = ScanDirection.RIGHT_TO_LEFT; +            break; +        case ScanDirection.RIGHT_TO_LEFT: +            direction = ScanDirection.TOP_TO_BOTTOM; +            break; +        } +        set_scan_direction (direction); +    } + +    public void rotate_right () +    { +        var direction = scan_direction; +        switch (direction) +        { +        case ScanDirection.TOP_TO_BOTTOM: +            direction = ScanDirection.RIGHT_TO_LEFT; +            break; +        case ScanDirection.LEFT_TO_RIGHT: +            direction = ScanDirection.TOP_TO_BOTTOM; +            break; +        case ScanDirection.BOTTOM_TO_TOP: +            direction = ScanDirection.LEFT_TO_RIGHT; +            break; +        case ScanDirection.RIGHT_TO_LEFT: +            direction = ScanDirection.BOTTOM_TO_TOP; +            break; +        } +        set_scan_direction (direction); +    } + +    public int get_dpi () +    { +        return dpi; +    } + +    public bool is_landscape () +    { +       return get_width () > get_height (); +    } + +    public int get_width () +    { +        if (scan_direction == ScanDirection.TOP_TO_BOTTOM || scan_direction == ScanDirection.BOTTOM_TO_TOP) +            return width; +        else +            return n_rows; +    } + +    public int get_height () +    { +        if (scan_direction == ScanDirection.TOP_TO_BOTTOM || scan_direction == ScanDirection.BOTTOM_TO_TOP) +            return n_rows; +        else +            return width; +    } + +    public int get_depth () +    { +        return depth; +    } + +    public int get_n_channels () +    { +        return n_channels; +    } + +    public int get_rowstride () +    { +        return rowstride; +    } + +    public int get_scan_width () +    { +        return width; +    } + +    public int get_scan_height () +    { +        return n_rows; +    } + +    public void set_color_profile (string? color_profile) +    { +         this.color_profile = color_profile; +    } + +    public string get_color_profile () +    { +         return color_profile; +    } + +    public void set_no_crop () +    { +        if (!has_crop_) +            return; +        has_crop_ = false; +        crop_changed (); +    } + +    public void set_custom_crop (int width, int height) +    { +        //int pw, ph; + +        return_if_fail (width >= 1); +        return_if_fail (height >= 1); + +        if (crop_name == null && has_crop_ && crop_width == width && crop_height == height) +            return; +        crop_name = null; +        has_crop_ = true; + +        crop_width = width; +        crop_height = height; + +        /*pw = get_width (); +        ph = get_height (); +        if (crop_width < pw) +            crop_x = (pw - crop_width) / 2; +        else +            crop_x = 0; +        if (crop_height < ph) +            crop_y = (ph - crop_height) / 2; +        else +            crop_y = 0;*/ + +        crop_changed (); +    } + +    public void set_named_crop (string name) +    { +        double width, height;         +        switch (name) +        { +        case "A4": +            width = 8.3; +            height = 11.7; +            break;             +        case "A5": +            width = 5.8; +            height = 8.3; +            break; +        case "A6": +            width = 4.1; +            height = 5.8; +            break; +        case "letter": +            width = 8.5; +            height = 11; +            break; +        case "legal": +            width = 8.5; +            height = 14; +            break; +        case "4x6": +            width = 4; +            height = 6; +            break; +        default: +            warning ("Unknown paper size '%s'", name); +            return; +        } + +        crop_name = name; +        has_crop_ = true; + +        var pw = get_width (); +        var ph = get_height (); + +        /* Rotate to match original aspect */ +        if (pw > ph) +        { +            double t; +            t = width; +            width = height; +            height = t; +        } + +        /* Custom crop, make slightly smaller than original */ +        crop_width = (int) (width * dpi + 0.5); +        crop_height = (int) (height * dpi + 0.5); + +        if (crop_width < pw) +            crop_x = (pw - crop_width) / 2; +        else +            crop_x = 0; +        if (crop_height < ph) +            crop_y = (ph - crop_height) / 2; +        else +            crop_y = 0; +        crop_changed (); +    } + +    public void move_crop (int x, int y) +    { +        return_if_fail (x >= 0); +        return_if_fail (y >= 0); +        return_if_fail (x < get_width ()); +        return_if_fail (y < get_height ()); + +        crop_x = x; +        crop_y = y; +        crop_changed (); +    } + +    public void rotate_crop () +    { +        int t; + +        if (!has_crop_) +            return; + +        t = crop_width; +        crop_width = crop_height; +        crop_height = t; + +        /* Clip custom crops */ +        if (crop_name == null) +        { +            int w, h; + +            w = get_width (); +            h = get_height (); + +            if (crop_x + crop_width > w) +                crop_x = w - crop_width; +            if (crop_x < 0) +            { +                crop_x = 0; +                crop_width = w; +            } +            if (crop_y + crop_height > h) +                crop_y = h - crop_height; +            if (crop_y < 0) +            { +                crop_y = 0; +                crop_height = h; +            } +        } + +        crop_changed (); +    } + +    public bool has_crop () +    { +        return has_crop_; +    } + +    public void get_crop (out int x, out int y, out int width, out int height) +    { +        x = crop_x; +        y = crop_y; +        width = crop_width; +        height = crop_height; +    } + +    public string get_named_crop () +    { +        return crop_name; +    } + +    public unowned uchar[] get_pixels () +    { +        return pixels; +    } + +    // FIXME: Copied from page-view, should be shared code +    private uchar get_sample (uchar[] pixels, int offset, int x, int depth, int n_channels, int channel) +    { +        // FIXME +        return 0xFF; +    } + +    // FIXME: Copied from page-view, should be shared code +    private void get_pixel (int x, int y, uchar[] pixel, int offset) +    { +        switch (get_scan_direction ()) +        { +        case ScanDirection.TOP_TO_BOTTOM: +            break; +        case ScanDirection.BOTTOM_TO_TOP: +            x = get_scan_width () - x - 1; +            y = get_scan_height () - y - 1; +            break; +        case ScanDirection.LEFT_TO_RIGHT: +            var t = x; +            x = get_scan_width () - y - 1; +            y = t; +            break; +        case ScanDirection.RIGHT_TO_LEFT: +            var t = x; +            x = y; +            y = get_scan_height () - t - 1; +            break; +        } + +        var depth = get_depth (); +        var n_channels = get_n_channels (); +        var line_offset = get_rowstride () * y; + +        /* Optimise for 8 bit images */ +        if (depth == 8 && n_channels == 3) +        { +            var o = line_offset + x * n_channels; +            pixel[offset+0] = pixels[o]; +            pixel[offset+1] = pixels[o+1]; +            pixel[offset+2] = pixels[o+2]; +            return; +        } +        else if (depth == 8 && n_channels == 1) +        { +            var p = pixels[line_offset + x]; +            pixel[offset+0] = pixel[offset+1] = pixel[offset+2] = p; +            return; +        } + +        /* Optimise for bitmaps */ +        else if (depth == 1 && n_channels == 1) +        { +            var p = pixels[line_offset + (x / 8)]; +            pixel[offset+0] = pixel[offset+1] = pixel[offset+2] = (p & (0x80 >> (x % 8))) != 0 ? 0x00 : 0xFF; +            return; +        } + +        /* Optimise for 2 bit images */ +        else if (depth == 2 && n_channels == 1) +        { +            int block_shift[4] = { 6, 4, 2, 0 }; + +            var p = pixels[line_offset + (x / 4)]; +            var sample = (p >> block_shift[x % 4]) & 0x3; +            sample = sample * 255 / 3; + +            pixel[offset+0] = pixel[offset+1] = pixel[offset+2] = (uchar) sample; +            return; +        } + +        /* Use slow method */ +        pixel[offset+0] = get_sample (pixels, line_offset, x, depth, n_channels, 0); +        pixel[offset+1] = get_sample (pixels, line_offset, x, depth, n_channels, 1); +        pixel[offset+2] = get_sample (pixels, line_offset, x, depth, n_channels, 2); +    } + +    public Gdk.Pixbuf get_image (bool apply_crop) +    { +        int l, r, t, b; +        if (apply_crop && has_crop_) +        { +            l = crop_x; +            r = l + crop_width; +            t = crop_y; +            b = t + crop_height; + +            if (l < 0) +                l = 0; +            if (r > get_width ()) +                r = get_width (); +            if (t < 0) +                t = 0; +            if (b > get_height ()) +                b = get_height (); +        } +        else +        { +            l = 0; +            r = get_width (); +            t = 0; +            b = get_height (); +        } + +        var image = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, r - l, b - t); +        unowned uint8[] image_pixels = image.get_pixels (); +        for (var y = t; y < b; y++) +        { +            var offset = image.get_rowstride () * (y - t); +            for (var x = l; x < r; x++) +                get_pixel (x, y, image_pixels, offset + (x - l) * 3); +        } + +        return image; +    } + +    private string? get_icc_data_encoded (string icc_profile_filename) +    { +        /* Get binary data */ +        string contents; +        try +        { +            FileUtils.get_contents (icc_profile_filename, out contents); +        } +        catch (Error e) +        { +            warning ("failed to get icc profile data: %s", e.message); +            return null; +        } + +        /* Encode into base64 */ +        return Base64.encode ((uchar[]) contents.to_utf8 ()); +    } + +    public void save (string type, File file) throws Error +    { +        var stream = file.replace (null, false, FileCreateFlags.NONE, null); +        var writer = new PixbufWriter (stream); +        var image = get_image (true); + +        string? icc_profile_data = null; +        if (color_profile != null) +            icc_profile_data = get_icc_data_encoded (color_profile); + +        if (strcmp (type, "jpeg") == 0) +        { +            /* ICC profile is awaiting review in gtk2+ bugzilla */ +            string[] keys = { "quality", /* "icc-profile", */ null }; +            string[] values = { "90", /* icc_profile_data, */ null }; +            writer.save (image, "jpeg", keys, values); +        } +        else if (strcmp (type, "png") == 0) +        { +            string[] keys = { "icc-profile", null }; +            string[] values = { icc_profile_data, null }; +            if (icc_profile_data == null) +                keys[0] = null; +            writer.save (image, "png", keys, values); +        } +        else if (strcmp (type, "tiff") == 0) +        { +            string[] keys = { "compression", "icc-profile", null }; +            string[] values = { "8" /* Deflate compression */, icc_profile_data, null }; +            if (icc_profile_data == null) +                keys[1] = null; +            writer.save (image, "tiff", keys, values); +        } +        else +            ; // FIXME: Throw Error +    } +} + +public class PixbufWriter +{ +    public FileOutputStream stream; + +    public PixbufWriter (FileOutputStream stream) +    { +        this.stream = stream; +    } + +    public void save (Gdk.Pixbuf image, string type, string[] option_keys, string[] option_values) throws Error +    { +        image.save_to_callbackv (write_pixbuf_data, type, option_keys, option_values); +    } + +    private bool write_pixbuf_data (uint8[] buf) throws Error +    { +        stream.write_all (buf, null, null); +        return true; +    } +} diff --git a/src/sane.vapi b/src/sane.vapi new file mode 100644 index 0000000..ae69940 --- /dev/null +++ b/src/sane.vapi @@ -0,0 +1,757 @@ +[CCode (cprefix = "SANE_", lower_case_cprefix = "sane_", cheader_filename = "sane/sane.h")] +namespace Sane { +    [SimpleType] +    [BooleanType] +    public struct Bool +    { +    } + +    [SimpleType] +    [IntegerType] +    public struct Int +    { +    } + +    [SimpleType] +    [IntegerType] +    public struct Fixed +    { +    } + +    [SimpleType] +    [IntegerType] +    public struct Word +    { +    } + +    [CCode (ref_function = "", unref_function = "")] +    public class Device +    { +        public string name; +        public string vendor; +        public string model; +        public string type; +    } + +    public enum Status +    { +        GOOD, +        UNSUPPORTED, +        CANCELLED, +        DEVICE_BUSY, +        INVAL, +        EOF, +        JAMMED, +        NO_DOCS, +        COVER_OPEN, +        IO_ERROR, +        NO_MEM, +        ACCESS_DENIED +    } +      +    public static string status_to_string (Status status) +    { +        switch (status) +        { +        case Status.GOOD: +            return "SANE_STATUS_GOOD"; +        case Status.UNSUPPORTED: +            return "SANE_STATUS_UNSUPPORTED"; +        case Status.CANCELLED: +            return "SANE_STATUS_CANCELLED"; +        case Status.DEVICE_BUSY: +            return "SANE_STATUS_DEVICE_BUSY"; +        case Status.INVAL: +            return "SANE_STATUS_INVAL"; +        case Status.EOF: +            return "SANE_STATUS_EOF"; +        case Status.JAMMED: +            return "SANE_STATUS_JAMMED"; +        case Status.NO_DOCS: +            return "SANE_STATUS_NO_DOCS"; +        case Status.COVER_OPEN: +            return "SANE_STATUS_COVER_OPEN"; +        case Status.IO_ERROR: +            return "SANE_STATUS_IO_ERROR"; +        case Status.NO_MEM: +            return "SANE_STATUS_NO_MEM"; +        case Status.ACCESS_DENIED: +            return "SANE_STATUS_ACCESS_DENIED"; +        default: +            return "SANE_STATUS(%d)".printf (status); +        } +    } + +    public enum Action +    { +        GET_VALUE, +        SET_VALUE, +        SET_AUTO +    } +     +    public enum Frame +    { +        GRAY, +        RGB, +        RED, +        GREEN, +        BLUE +    } + +    public static string frame_to_string (Frame frame) +    { +        switch (frame) +        { +        case Frame.GRAY: +            return "SANE_FRAME_GRAY"; +        case Frame.RGB: +            return "SANE_FRAME_RGB"; +        case Frame.RED: +            return "SANE_FRAME_RED"; +        case Frame.GREEN: +            return "SANE_FRAME_GREEN"; +        case Frame.BLUE: +            return "SANE_FRAME_BLUE"; +        default: +            return "SANE_FRAME(%d)".printf (frame); +        } +    } + +    public struct Parameters +    { +        Frame format; +        bool last_frame; +        int bytes_per_line; +        int pixels_per_line; +        int lines; +        int depth; +    } + +    [CCode (cname = "SANE_MAX_USERNAME_LEN")] +    public int MAX_USERNAME_LEN; + +    [CCode (cname = "SANE_MAX_USERNAME_LEN")] +    public int MAX_PASSWORD_LEN; + +    [CCode (cname = "SANE_Value_Type", cprefix = "SANE_TYPE_")] +    public enum ValueType +    { +        BOOL, +        INT, +        FIXED, +        STRING, +        BUTTON, +        GROUP +    } + +    public enum Unit +    { +        NONE, +        PIXEL, +        BIT, +        MM, +        DPI, +        PERCENT, +        MICROSECOND +    } +     +    [CCode (cname = "const SANE_Constraint_Type", cprefix = "SANE_CONSTRAINT_")] +    public enum ConstraintType +    { +        NONE, +        RANGE, +        WORD_LIST, +        STRING_LIST +    } +     +    public class Range +    { +        public Word min; +        public Word max; +        public Word quant; +    } + +    [CCode (cprefix = "SANE_CAP_")] +    public enum Capability +    { +        SOFT_SELECT, +        HARD_SELECT, +        SOFT_DETECT, +        EMULATED, +        AUTOMATIC, +        INACTIVE, +        ADVANCED +    } + +    [CCode (cname = "const SANE_Option_Descriptor", ref_function = "", unref_function = "")] +    public class OptionDescriptor +    { +        public string name; +        public string title; +        public string desc; +        public ValueType type; +        public Unit unit; +        public Int size; +        public Int cap; + +        public ConstraintType constraint_type; +        public struct _Constraint +        { +            [CCode (array_length = false, null_terminated = true)] +            public string[] string_list; +            public Word[] word_list; +            public Range range; +        } +        public _Constraint constraint; +    } + +    [CCode (type = "Int", cprefix = "SANE_INFO_")] +    public enum Info +    { +        INEXACT, +        RELOAD_OPTIONS, +        RELOAD_PARAMS +    } + +    [SimpleType] +    public struct Handle +    { +    } + +    [CCode (has_target = false)] +    public delegate void AuthCallback (string resource, [CCode (array_length = false)] char[] username, [CCode (array_length = false)] char[] password); + +    [CCode (cname = "SANE_VERSION_MAJOR")] +    public int VERSION_MAJOR (Int code); +    [CCode (cname = "SANE_VERSION_MINOR")] +    public int VERSION_MINOR (Int code); +    [CCode (cname = "SANE_VERSION_BUILD")] +    public int VERSION_BUILD (Int code); +     +    [CCode (cname = "SANE_FIX")] +    public Fixed FIX (double d); +    [CCode (cname = "SANE_UNFIX")] +    public double UNFIX (Fixed w); + +    [CCode (cname = "SANE_I18N")] +    public unowned string I18N (string value); + +    public Status init (out Int version_code, AuthCallback callback); +    public void exit (); +    public Status get_devices ([CCode (array_length = false, null_terminated = true)] out unowned Device[] device_list, bool local_only); +    public unowned string strstatus (Status status); +    public Status open (string devicename, out Handle handle); +    public void close (Handle handle); +    public unowned OptionDescriptor? get_option_descriptor (Handle handle, Int option); +    public Status control_option (Handle handle, Int option, Action action, void *value, out Info? info = null); +    public Status get_parameters (Handle handle, out Parameters params); +    public Status start (Handle handle); +    public Status read (Handle handle, uint8* data, Int max_length, out Int length); +    public void cancel (Handle handle); +    public Status set_io_mode (Handle handle, bool non_blocking); +    public Status get_select_fd (Handle handle, out int fd); + +    [CCode (cname = "SANE_NAME_STANDARD", cheader_filename = "sane/saneopts.h")] +    public static string NAME_STANDARD; +    [CCode (cname = "SANE_NAME_GEOMETRY", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GEOMETRY; +    [CCode (cname = "SANE_NAME_ENHANCEMENT", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ENHANCEMENT; +    [CCode (cname = "SANE_NAME_ADVANCED", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ADVANCED; +    [CCode (cname = "SANE_NAME_SENSORS", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SENSORS; +    [CCode (cname = "SANE_NAME_PREVIEW", cheader_filename = "sane/saneopts.h")] +    public static string NAME_PREVIEW; +    [CCode (cname = "SANE_NAME_GRAY_PREVIEW", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GRAY_PREVIEW; +    [CCode (cname = "SANE_NAME_BIT_DEPTH", cheader_filename = "sane/saneopts.h")] +    public static string NAME_BIT_DEPTH; +    [CCode (cname = "SANE_NAME_SCAN_MODE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_MODE; +    [CCode (cname = "SANE_NAME_SCAN_SPEED", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_SPEED; +    [CCode (cname = "SANE_NAME_SCAN_SOURCE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_SOURCE; +    [CCode (cname = "SANE_NAME_BACKTRACK", cheader_filename = "sane/saneopts.h")] +    public static string NAME_BACKTRACK; +    [CCode (cname = "SANE_NAME_SCAN_TL_X", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_TL_X; +    [CCode (cname = "SANE_NAME_SCAN_TL_Y", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_TL_Y; +    [CCode (cname = "SANE_NAME_SCAN_BR_X", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_BR_X; +    [CCode (cname = "SANE_NAME_SCAN_BR_Y", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_BR_Y; +    [CCode (cname = "SANE_NAME_SCAN_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_RESOLUTION; +    [CCode (cname = "SANE_NAME_SCAN_X_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_X_RESOLUTION; +    [CCode (cname = "SANE_NAME_SCAN_Y_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_Y_RESOLUTION; +    [CCode (cname = "SANE_NAME_PAGE_WIDTH", cheader_filename = "sane/saneopts.h")] +    public static string NAME_PAGE_WIDTH; +    [CCode (cname = "SANE_NAME_PAGE_HEIGHT", cheader_filename = "sane/saneopts.h")] +    public static string NAME_PAGE_HEIGHT; +    [CCode (cname = "SANE_NAME_CUSTOM_GAMMA", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CUSTOM_GAMMA; +    [CCode (cname = "SANE_NAME_GAMMA_VECTOR", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GAMMA_VECTOR; +    [CCode (cname = "SANE_NAME_GAMMA_VECTOR_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GAMMA_VECTOR_R; +    [CCode (cname = "SANE_NAME_GAMMA_VECTOR_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GAMMA_VECTOR_G; +    [CCode (cname = "SANE_NAME_GAMMA_VECTOR_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GAMMA_VECTOR_B; +    [CCode (cname = "SANE_NAME_BRIGHTNESS", cheader_filename = "sane/saneopts.h")] +    public static string NAME_BRIGHTNESS; +    [CCode (cname = "SANE_NAME_CONTRAST", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CONTRAST; +    [CCode (cname = "SANE_NAME_GRAIN_SIZE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_GRAIN_SIZE; +    [CCode (cname = "SANE_NAME_HALFTONE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HALFTONE; +    [CCode (cname = "SANE_NAME_BLACK_LEVEL", cheader_filename = "sane/saneopts.h")] +    public static string NAME_BLACK_LEVEL; +    [CCode (cname = "SANE_NAME_WHITE_LEVEL", cheader_filename = "sane/saneopts.h")] +    public static string NAME_WHITE_LEVEL; +    [CCode (cname = "SANE_NAME_WHITE_LEVEL_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_WHITE_LEVEL_R; +    [CCode (cname = "SANE_NAME_WHITE_LEVEL_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_WHITE_LEVEL_G; +    [CCode (cname = "SANE_NAME_WHITE_LEVEL_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_WHITE_LEVEL_B; +    [CCode (cname = "SANE_NAME_SHADOW", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SHADOW; +    [CCode (cname = "SANE_NAME_SHADOW_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SHADOW_R; +    [CCode (cname = "SANE_NAME_SHADOW_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SHADOW_G; +    [CCode (cname = "SANE_NAME_SHADOW_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SHADOW_B; +    [CCode (cname = "SANE_NAME_HIGHLIGHT", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HIGHLIGHT; +    [CCode (cname = "SANE_NAME_HIGHLIGHT_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HIGHLIGHT_R; +    [CCode (cname = "SANE_NAME_HIGHLIGHT_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HIGHLIGHT_G; +    [CCode (cname = "SANE_NAME_HIGHLIGHT_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HIGHLIGHT_B; +    [CCode (cname = "SANE_NAME_HUE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HUE; +    [CCode (cname = "SANE_NAME_SATURATION", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SATURATION; +    [CCode (cname = "SANE_NAME_FILE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_FILE; +    [CCode (cname = "SANE_NAME_HALFTONE_DIMENSION", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HALFTONE_DIMENSION; +    [CCode (cname = "SANE_NAME_HALFTONE_PATTERN", cheader_filename = "sane/saneopts.h")] +    public static string NAME_HALFTONE_PATTERN; +    [CCode (cname = "SANE_NAME_RESOLUTION_BIND", cheader_filename = "sane/saneopts.h")] +    public static string NAME_RESOLUTION_BIND; +    [CCode (cname = "SANE_NAME_NEGATIVE", cheader_filename = "sane/saneopts.h")] +    public static string NAME_NEGATIVE; +    [CCode (cname = "SANE_NAME_QUALITY_CAL", cheader_filename = "sane/saneopts.h")] +    public static string NAME_QUALITY_CAL; +    [CCode (cname = "SANE_NAME_DOR", cheader_filename = "sane/saneopts.h")] +    public static string NAME_DOR; +    [CCode (cname = "SANE_NAME_RGB_BIND", cheader_filename = "sane/saneopts.h")] +    public static string NAME_RGB_BIND; +    [CCode (cname = "SANE_NAME_THRESHOLD", cheader_filename = "sane/saneopts.h")] +    public static string NAME_THRESHOLD; +    [CCode (cname = "SANE_NAME_ANALOG_GAMMA", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ANALOG_GAMMA; +    [CCode (cname = "SANE_NAME_ANALOG_GAMMA_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ANALOG_GAMMA_R; +    [CCode (cname = "SANE_NAME_ANALOG_GAMMA_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ANALOG_GAMMA_G; +    [CCode (cname = "SANE_NAME_ANALOG_GAMMA_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ANALOG_GAMMA_B; +    [CCode (cname = "SANE_NAME_ANALOG_GAMMA_BIND", cheader_filename = "sane/saneopts.h")] +    public static string NAME_ANALOG_GAMMA_BIND; +    [CCode (cname = "SANE_NAME_WARMUP", cheader_filename = "sane/saneopts.h")] +    public static string NAME_WARMUP; +    [CCode (cname = "SANE_NAME_CAL_EXPOS_TIME", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CAL_EXPOS_TIME; +    [CCode (cname = "SANE_NAME_CAL_EXPOS_TIME_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CAL_EXPOS_TIME_R; +    [CCode (cname = "SANE_NAME_CAL_EXPOS_TIME_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CAL_EXPOS_TIME_G; +    [CCode (cname = "SANE_NAME_CAL_EXPOS_TIME_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CAL_EXPOS_TIME_B; +    [CCode (cname = "SANE_NAME_SCAN_EXPOS_TIME", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_EXPOS_TIME; +    [CCode (cname = "SANE_NAME_SCAN_EXPOS_TIME_R", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_EXPOS_TIME_R; +    [CCode (cname = "SANE_NAME_SCAN_EXPOS_TIME_G", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_EXPOS_TIME_G; +    [CCode (cname = "SANE_NAME_SCAN_EXPOS_TIME_B", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_EXPOS_TIME_B; +    [CCode (cname = "SANE_NAME_SELECT_EXPOSURE_TIME", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SELECT_EXPOSURE_TIME; +    [CCode (cname = "SANE_NAME_CAL_LAMP_DEN", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CAL_LAMP_DEN; +    [CCode (cname = "SANE_NAME_SCAN_LAMP_DEN", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN_LAMP_DEN; +    [CCode (cname = "SANE_NAME_SELECT_LAMP_DENSITY", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SELECT_LAMP_DENSITY; +    [CCode (cname = "SANE_NAME_LAMP_OFF_AT_EXIT", cheader_filename = "sane/saneopts.h")] +    public static string NAME_LAMP_OFF_AT_EXIT; +    [CCode (cname = "SANE_NAME_SCAN", cheader_filename = "sane/saneopts.h")] +    public static string NAME_SCAN; +    [CCode (cname = "SANE_NAME_EMAIL", cheader_filename = "sane/saneopts.h")] +    public static string NAME_EMAIL; +    [CCode (cname = "SANE_NAME_FAX", cheader_filename = "sane/saneopts.h")] +    public static string NAME_FAX; +    [CCode (cname = "SANE_NAME_COPY", cheader_filename = "sane/saneopts.h")] +    public static string NAME_COPY; +    [CCode (cname = "SANE_NAME_PDF", cheader_filename = "sane/saneopts.h")] +    public static string NAME_PDF; +    [CCode (cname = "SANE_NAME_CANCEL", cheader_filename = "sane/saneopts.h")] +    public static string NAME_CANCEL; +    [CCode (cname = "SANE_NAME_PAGE_LOADED", cheader_filename = "sane/saneopts.h")] +    public static string NAME_PAGE_LOADED; +    [CCode (cname = "SANE_NAME_COVER_OPEN", cheader_filename = "sane/saneopts.h")] +    public static string NAME_COVER_OPEN; +    [CCode (cname = "SANE_TITLE_NUM_OPTIONS", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_NUM_OPTIONS; +    [CCode (cname = "SANE_TITLE_STANDARD", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_STANDARD; +    [CCode (cname = "SANE_TITLE_GEOMETRY", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GEOMETRY; +    [CCode (cname = "SANE_TITLE_ENHANCEMENT", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ENHANCEMENT; +    [CCode (cname = "SANE_TITLE_ADVANCED", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ADVANCED; +    [CCode (cname = "SANE_TITLE_SENSORS", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SENSORS; +    [CCode (cname = "SANE_TITLE_PREVIEW", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_PREVIEW; +    [CCode (cname = "SANE_TITLE_GRAY_PREVIEW", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GRAY_PREVIEW; +    [CCode (cname = "SANE_TITLE_BIT_DEPTH", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_BIT_DEPTH; +    [CCode (cname = "SANE_TITLE_SCAN_MODE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_MODE; +    [CCode (cname = "SANE_TITLE_SCAN_SPEED", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_SPEED; +    [CCode (cname = "SANE_TITLE_SCAN_SOURCE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_SOURCE; +    [CCode (cname = "SANE_TITLE_BACKTRACK", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_BACKTRACK; +    [CCode (cname = "SANE_TITLE_SCAN_TL_X", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_TL_X; +    [CCode (cname = "SANE_TITLE_SCAN_TL_Y", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_TL_Y; +    [CCode (cname = "SANE_TITLE_SCAN_BR_X", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_BR_X; +    [CCode (cname = "SANE_TITLE_SCAN_BR_Y", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_BR_Y; +    [CCode (cname = "SANE_TITLE_SCAN_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_RESOLUTION; +    [CCode (cname = "SANE_TITLE_SCAN_X_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_X_RESOLUTION; +    [CCode (cname = "SANE_TITLE_SCAN_Y_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_Y_RESOLUTION; +    [CCode (cname = "SANE_TITLE_PAGE_WIDTH", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_PAGE_WIDTH; +    [CCode (cname = "SANE_TITLE_PAGE_HEIGHT", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_PAGE_HEIGHT; +    [CCode (cname = "SANE_TITLE_CUSTOM_GAMMA", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CUSTOM_GAMMA; +    [CCode (cname = "SANE_TITLE_GAMMA_VECTOR", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GAMMA_VECTOR; +    [CCode (cname = "SANE_TITLE_GAMMA_VECTOR_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GAMMA_VECTOR_R; +    [CCode (cname = "SANE_TITLE_GAMMA_VECTOR_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GAMMA_VECTOR_G; +    [CCode (cname = "SANE_TITLE_GAMMA_VECTOR_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GAMMA_VECTOR_B; +    [CCode (cname = "SANE_TITLE_BRIGHTNESS", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_BRIGHTNESS; +    [CCode (cname = "SANE_TITLE_CONTRAST", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CONTRAST; +    [CCode (cname = "SANE_TITLE_GRAIN_SIZE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_GRAIN_SIZE; +    [CCode (cname = "SANE_TITLE_HALFTONE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HALFTONE; +    [CCode (cname = "SANE_TITLE_BLACK_LEVEL", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_BLACK_LEVEL; +    [CCode (cname = "SANE_TITLE_WHITE_LEVEL", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_WHITE_LEVEL; +    [CCode (cname = "SANE_TITLE_WHITE_LEVEL_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_WHITE_LEVEL_R; +    [CCode (cname = "SANE_TITLE_WHITE_LEVEL_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_WHITE_LEVEL_G; +    [CCode (cname = "SANE_TITLE_WHITE_LEVEL_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_WHITE_LEVEL_B; +    [CCode (cname = "SANE_TITLE_SHADOW", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SHADOW; +    [CCode (cname = "SANE_TITLE_SHADOW_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SHADOW_R; +    [CCode (cname = "SANE_TITLE_SHADOW_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SHADOW_G; +    [CCode (cname = "SANE_TITLE_SHADOW_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SHADOW_B; +    [CCode (cname = "SANE_TITLE_HIGHLIGHT", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HIGHLIGHT; +    [CCode (cname = "SANE_TITLE_HIGHLIGHT_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HIGHLIGHT_R; +    [CCode (cname = "SANE_TITLE_HIGHLIGHT_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HIGHLIGHT_G; +    [CCode (cname = "SANE_TITLE_HIGHLIGHT_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HIGHLIGHT_B; +    [CCode (cname = "SANE_TITLE_HUE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HUE; +    [CCode (cname = "SANE_TITLE_SATURATION", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SATURATION; +    [CCode (cname = "SANE_TITLE_FILE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_FILE; +    [CCode (cname = "SANE_TITLE_HALFTONE_DIMENSION", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HALFTONE_DIMENSION; +    [CCode (cname = "SANE_TITLE_HALFTONE_PATTERN", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_HALFTONE_PATTERN; +    [CCode (cname = "SANE_TITLE_RESOLUTION_BIND", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_RESOLUTION_BIND; +    [CCode (cname = "SANE_TITLE_NEGATIVE", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_NEGATIVE; +    [CCode (cname = "SANE_TITLE_QUALITY_CAL", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_QUALITY_CAL; +    [CCode (cname = "SANE_TITLE_DOR", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_DOR; +    [CCode (cname = "SANE_TITLE_RGB_BIND", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_RGB_BIND; +    [CCode (cname = "SANE_TITLE_THRESHOLD", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_THRESHOLD; +    [CCode (cname = "SANE_TITLE_ANALOG_GAMMA", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ANALOG_GAMMA; +    [CCode (cname = "SANE_TITLE_ANALOG_GAMMA_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ANALOG_GAMMA_R; +    [CCode (cname = "SANE_TITLE_ANALOG_GAMMA_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ANALOG_GAMMA_G; +    [CCode (cname = "SANE_TITLE_ANALOG_GAMMA_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ANALOG_GAMMA_B; +    [CCode (cname = "SANE_TITLE_ANALOG_GAMMA_BIND", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_ANALOG_GAMMA_BIND; +    [CCode (cname = "SANE_TITLE_WARMUP", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_WARMUP; +    [CCode (cname = "SANE_TITLE_CAL_EXPOS_TIME", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CAL_EXPOS_TIME; +    [CCode (cname = "SANE_TITLE_CAL_EXPOS_TIME_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CAL_EXPOS_TIME_R; +    [CCode (cname = "SANE_TITLE_CAL_EXPOS_TIME_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CAL_EXPOS_TIME_G; +    [CCode (cname = "SANE_TITLE_CAL_EXPOS_TIME_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CAL_EXPOS_TIME_B; +    [CCode (cname = "SANE_TITLE_SCAN_EXPOS_TIME", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_EXPOS_TIME; +    [CCode (cname = "SANE_TITLE_SCAN_EXPOS_TIME_R", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_EXPOS_TIME_R; +    [CCode (cname = "SANE_TITLE_SCAN_EXPOS_TIME_G", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_EXPOS_TIME_G; +    [CCode (cname = "SANE_TITLE_SCAN_EXPOS_TIME_B", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_EXPOS_TIME_B; +    [CCode (cname = "SANE_TITLE_SELECT_EXPOSURE_TIME", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SELECT_EXPOSURE_TIME; +    [CCode (cname = "SANE_TITLE_CAL_LAMP_DEN", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CAL_LAMP_DEN; +    [CCode (cname = "SANE_TITLE_SCAN_LAMP_DEN", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN_LAMP_DEN; +    [CCode (cname = "SANE_TITLE_SELECT_LAMP_DENSITY", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SELECT_LAMP_DENSITY; +    [CCode (cname = "SANE_TITLE_LAMP_OFF_AT_EXIT", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_LAMP_OFF_AT_EXIT; +    [CCode (cname = "SANE_TITLE_SCAN", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_SCAN; +    [CCode (cname = "SANE_TITLE_EMAIL", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_EMAIL; +    [CCode (cname = "SANE_TITLE_FAX", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_FAX; +    [CCode (cname = "SANE_TITLE_COPY", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_COPY; +    [CCode (cname = "SANE_TITLE_PDF", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_PDF; +    [CCode (cname = "SANE_TITLE_CANCEL", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_CANCEL; +    [CCode (cname = "SANE_TITLE_PAGE_LOADED", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_PAGE_LOADED; +    [CCode (cname = "SANE_TITLE_COVER_OPEN", cheader_filename = "sane/saneopts.h")] +    public static string TITLE_COVER_OPEN; +    [CCode (cname = "SANE_DESC_NUM_OPTIONS", cheader_filename = "sane/saneopts.h")] +    public static string DESC_NUM_OPTIONS; +    [CCode (cname = "SANE_DESC_STANDARD", cheader_filename = "sane/saneopts.h")] +    public static string DESC_STANDARD; +    [CCode (cname = "SANE_DESC_GEOMETRY", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GEOMETRY; +    [CCode (cname = "SANE_DESC_ENHANCEMENT", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ENHANCEMENT; +    [CCode (cname = "SANE_DESC_ADVANCED", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ADVANCED; +    [CCode (cname = "SANE_DESC_SENSORS", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SENSORS; +    [CCode (cname = "SANE_DESC_PREVIEW", cheader_filename = "sane/saneopts.h")] +    public static string DESC_PREVIEW; +    [CCode (cname = "SANE_DESC_GRAY_PREVIEW", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GRAY_PREVIEW; +    [CCode (cname = "SANE_DESC_BIT_DEPTH", cheader_filename = "sane/saneopts.h")] +    public static string DESC_BIT_DEPTH; +    [CCode (cname = "SANE_DESC_SCAN_MODE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_MODE; +    [CCode (cname = "SANE_DESC_SCAN_SPEED", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_SPEED; +    [CCode (cname = "SANE_DESC_SCAN_SOURCE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_SOURCE; +    [CCode (cname = "SANE_DESC_BACKTRACK", cheader_filename = "sane/saneopts.h")] +    public static string DESC_BACKTRACK; +    [CCode (cname = "SANE_DESC_SCAN_TL_X", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_TL_X; +    [CCode (cname = "SANE_DESC_SCAN_TL_Y", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_TL_Y; +    [CCode (cname = "SANE_DESC_SCAN_BR_X", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_BR_X; +    [CCode (cname = "SANE_DESC_SCAN_BR_Y", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_BR_Y; +    [CCode (cname = "SANE_DESC_SCAN_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_RESOLUTION; +    [CCode (cname = "SANE_DESC_SCAN_X_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_X_RESOLUTION; +    [CCode (cname = "SANE_DESC_SCAN_Y_RESOLUTION", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_Y_RESOLUTION; +    [CCode (cname = "SANE_DESC_PAGE_WIDTH", cheader_filename = "sane/saneopts.h")] +    public static string DESC_PAGE_WIDTH; +    [CCode (cname = "SANE_DESC_PAGE_HEIGHT", cheader_filename = "sane/saneopts.h")] +    public static string DESC_PAGE_HEIGHT; +    [CCode (cname = "SANE_DESC_CUSTOM_GAMMA", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CUSTOM_GAMMA; +    [CCode (cname = "SANE_DESC_GAMMA_VECTOR", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GAMMA_VECTOR; +    [CCode (cname = "SANE_DESC_GAMMA_VECTOR_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GAMMA_VECTOR_R; +    [CCode (cname = "SANE_DESC_GAMMA_VECTOR_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GAMMA_VECTOR_G; +    [CCode (cname = "SANE_DESC_GAMMA_VECTOR_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GAMMA_VECTOR_B; +    [CCode (cname = "SANE_DESC_BRIGHTNESS", cheader_filename = "sane/saneopts.h")] +    public static string DESC_BRIGHTNESS; +    [CCode (cname = "SANE_DESC_CONTRAST", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CONTRAST; +    [CCode (cname = "SANE_DESC_GRAIN_SIZE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_GRAIN_SIZE; +    [CCode (cname = "SANE_DESC_HALFTONE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HALFTONE; +    [CCode (cname = "SANE_DESC_BLACK_LEVEL", cheader_filename = "sane/saneopts.h")] +    public static string DESC_BLACK_LEVEL; +    [CCode (cname = "SANE_DESC_WHITE_LEVEL", cheader_filename = "sane/saneopts.h")] +    public static string DESC_WHITE_LEVEL; +    [CCode (cname = "SANE_DESC_WHITE_LEVEL_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_WHITE_LEVEL_R; +    [CCode (cname = "SANE_DESC_WHITE_LEVEL_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_WHITE_LEVEL_G; +    [CCode (cname = "SANE_DESC_WHITE_LEVEL_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_WHITE_LEVEL_B; +    [CCode (cname = "SANE_DESC_SHADOW", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SHADOW; +    [CCode (cname = "SANE_DESC_SHADOW_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SHADOW_R; +    [CCode (cname = "SANE_DESC_SHADOW_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SHADOW_G; +    [CCode (cname = "SANE_DESC_SHADOW_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SHADOW_B; +    [CCode (cname = "SANE_DESC_HIGHLIGHT", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HIGHLIGHT; +    [CCode (cname = "SANE_DESC_HIGHLIGHT_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HIGHLIGHT_R; +    [CCode (cname = "SANE_DESC_HIGHLIGHT_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HIGHLIGHT_G; +    [CCode (cname = "SANE_DESC_HIGHLIGHT_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HIGHLIGHT_B; +    [CCode (cname = "SANE_DESC_HUE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HUE; +    [CCode (cname = "SANE_DESC_SATURATION", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SATURATION; +    [CCode (cname = "SANE_DESC_FILE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_FILE; +    [CCode (cname = "SANE_DESC_HALFTONE_DIMENSION", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HALFTONE_DIMENSION; +    [CCode (cname = "SANE_DESC_HALFTONE_PATTERN", cheader_filename = "sane/saneopts.h")] +    public static string DESC_HALFTONE_PATTERN; +    [CCode (cname = "SANE_DESC_RESOLUTION_BIND", cheader_filename = "sane/saneopts.h")] +    public static string DESC_RESOLUTION_BIND; +    [CCode (cname = "SANE_DESC_NEGATIVE", cheader_filename = "sane/saneopts.h")] +    public static string DESC_NEGATIVE; +    [CCode (cname = "SANE_DESC_QUALITY_CAL", cheader_filename = "sane/saneopts.h")] +    public static string DESC_QUALITY_CAL; +    [CCode (cname = "SANE_DESC_DOR", cheader_filename = "sane/saneopts.h")] +    public static string DESC_DOR; +    [CCode (cname = "SANE_DESC_RGB_BIND", cheader_filename = "sane/saneopts.h")] +    public static string DESC_RGB_BIND; +    [CCode (cname = "SANE_DESC_THRESHOLD", cheader_filename = "sane/saneopts.h")] +    public static string DESC_THRESHOLD; +    [CCode (cname = "SANE_DESC_ANALOG_GAMMA", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ANALOG_GAMMA; +    [CCode (cname = "SANE_DESC_ANALOG_GAMMA_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ANALOG_GAMMA_R; +    [CCode (cname = "SANE_DESC_ANALOG_GAMMA_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ANALOG_GAMMA_G; +    [CCode (cname = "SANE_DESC_ANALOG_GAMMA_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ANALOG_GAMMA_B; +    [CCode (cname = "SANE_DESC_ANALOG_GAMMA_BIND", cheader_filename = "sane/saneopts.h")] +    public static string DESC_ANALOG_GAMMA_BIND; +    [CCode (cname = "SANE_DESC_WARMUP", cheader_filename = "sane/saneopts.h")] +    public static string DESC_WARMUP; +    [CCode (cname = "SANE_DESC_CAL_EXPOS_TIME", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CAL_EXPOS_TIME; +    [CCode (cname = "SANE_DESC_CAL_EXPOS_TIME_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CAL_EXPOS_TIME_R; +    [CCode (cname = "SANE_DESC_CAL_EXPOS_TIME_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CAL_EXPOS_TIME_G; +    [CCode (cname = "SANE_DESC_CAL_EXPOS_TIME_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CAL_EXPOS_TIME_B; +    [CCode (cname = "SANE_DESC_SCAN_EXPOS_TIME", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_EXPOS_TIME; +    [CCode (cname = "SANE_DESC_SCAN_EXPOS_TIME_R", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_EXPOS_TIME_R; +    [CCode (cname = "SANE_DESC_SCAN_EXPOS_TIME_G", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_EXPOS_TIME_G; +    [CCode (cname = "SANE_DESC_SCAN_EXPOS_TIME_B", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_EXPOS_TIME_B; +    [CCode (cname = "SANE_DESC_SELECT_EXPOSURE_TIME", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SELECT_EXPOSURE_TIME; +    [CCode (cname = "SANE_DESC_CAL_LAMP_DEN", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CAL_LAMP_DEN; +    [CCode (cname = "SANE_DESC_SCAN_LAMP_DEN", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN_LAMP_DEN; +    [CCode (cname = "SANE_DESC_SELECT_LAMP_DENSITY", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SELECT_LAMP_DENSITY; +    [CCode (cname = "SANE_DESC_LAMP_OFF_AT_EXIT", cheader_filename = "sane/saneopts.h")] +    public static string DESC_LAMP_OFF_AT_EXIT; +    [CCode (cname = "SANE_DESC_SCAN", cheader_filename = "sane/saneopts.h")] +    public static string DESC_SCAN; +    [CCode (cname = "SANE_DESC_EMAIL", cheader_filename = "sane/saneopts.h")] +    public static string DESC_EMAIL; +    [CCode (cname = "SANE_DESC_FAX", cheader_filename = "sane/saneopts.h")] +    public static string DESC_FAX; +    [CCode (cname = "SANE_DESC_COPY", cheader_filename = "sane/saneopts.h")] +    public static string DESC_COPY; +    [CCode (cname = "SANE_DESC_PDF", cheader_filename = "sane/saneopts.h")] +    public static string DESC_PDF; +    [CCode (cname = "SANE_DESC_CANCEL", cheader_filename = "sane/saneopts.h")] +    public static string DESC_CANCEL; +    [CCode (cname = "SANE_DESC_PAGE_LOADED", cheader_filename = "sane/saneopts.h")] +    public static string DESC_PAGE_LOADED; +    [CCode (cname = "SANE_DESC_COVER_OPEN", cheader_filename = "sane/saneopts.h")] +    public static string DESC_COVER_OPEN; +    [CCode (cname = "SANE_VALUE_SCAN_MODE_COLOR", cheader_filename = "sane/saneopts.h")] +    public static string VALUE_SCAN_MODE_COLOR; +    [CCode (cname = "SANE_VALUE_SCAN_MODE_COLOR_LINEART", cheader_filename = "sane/saneopts.h")] +    public static string VALUE_SCAN_MODE_COLOR_LINEART; +    [CCode (cname = "SANE_VALUE_SCAN_MODE_COLOR_HALFTONE", cheader_filename = "sane/saneopts.h")] +    public static string VALUE_SCAN_MODE_COLOR_HALFTONE; +    [CCode (cname = "SANE_VALUE_SCAN_MODE_GRAY", cheader_filename = "sane/saneopts.h")] +    public static string VALUE_SCAN_MODE_GRAY; +    [CCode (cname = "SANE_VALUE_SCAN_MODE_HALFTONE", cheader_filename = "sane/saneopts.h")] +    public static string VALUE_SCAN_MODE_HALFTONE; +    [CCode (cname = "SANE_VALUE_SCAN_MODE_LINEART", cheader_filename = "sane/saneopts.h")] +    public static string VALUE_SCAN_MODE_LINEART; +} + diff --git a/src/scanner.c b/src/scanner.c index ff8a994..e7e83cc 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -1,1714 +1,6089 @@ +/* scanner.c generated by valac 0.13.1, the Vala compiler + * generated from scanner.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later   * version. See http://www.gnu.org/copyleft/gpl.html the full text of the   * license.   */ +/* TODO: Could indicate the start of the next page immediately after the last page is received (i.e. before the sane_cancel()) */ +#include <glib.h> +#include <glib-object.h>  #include <stdlib.h>  #include <string.h> +#include <float.h>  #include <math.h>  #include <sane/sane.h> +#include <glib/gi18n-lib.h>  #include <sane/saneopts.h> -#include <glib/gi18n.h> +#include <gobject/gvaluecollector.h> + + +#define TYPE_SCAN_DEVICE (scan_device_get_type ()) +#define SCAN_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_DEVICE, ScanDevice)) +#define SCAN_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_DEVICE, ScanDeviceClass)) +#define IS_SCAN_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_DEVICE)) +#define IS_SCAN_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_DEVICE)) +#define SCAN_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_DEVICE, ScanDeviceClass)) + +typedef struct _ScanDevice ScanDevice; +typedef struct _ScanDeviceClass ScanDeviceClass; +typedef struct _ScanDevicePrivate ScanDevicePrivate; +#define _g_free0(var) (var = (g_free (var), NULL)) +typedef struct _ParamSpecScanDevice ParamSpecScanDevice; + +#define TYPE_SCAN_PAGE_INFO (scan_page_info_get_type ()) +#define SCAN_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_PAGE_INFO, ScanPageInfo)) +#define SCAN_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_PAGE_INFO, ScanPageInfoClass)) +#define IS_SCAN_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_PAGE_INFO)) +#define IS_SCAN_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_PAGE_INFO)) +#define SCAN_PAGE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_PAGE_INFO, ScanPageInfoClass)) + +typedef struct _ScanPageInfo ScanPageInfo; +typedef struct _ScanPageInfoClass ScanPageInfoClass; +typedef struct _ScanPageInfoPrivate ScanPageInfoPrivate; +typedef struct _ParamSpecScanPageInfo ParamSpecScanPageInfo; + +#define TYPE_SCAN_LINE (scan_line_get_type ()) +#define SCAN_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_LINE, ScanLine)) +#define SCAN_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_LINE, ScanLineClass)) +#define IS_SCAN_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_LINE)) +#define IS_SCAN_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_LINE)) +#define SCAN_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_LINE, ScanLineClass)) + +typedef struct _ScanLine ScanLine; +typedef struct _ScanLineClass ScanLineClass; +typedef struct _ScanLinePrivate ScanLinePrivate; +typedef struct _ParamSpecScanLine ParamSpecScanLine; + +#define TYPE_SCAN_MODE (scan_mode_get_type ()) + +#define TYPE_SCAN_TYPE (scan_type_get_type ()) + +#define TYPE_SCAN_OPTIONS (scan_options_get_type ()) +#define SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_OPTIONS, ScanOptions)) +#define SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_OPTIONS, ScanOptionsClass)) +#define IS_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_OPTIONS)) +#define IS_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_OPTIONS)) +#define SCAN_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_OPTIONS, ScanOptionsClass)) + +typedef struct _ScanOptions ScanOptions; +typedef struct _ScanOptionsClass ScanOptionsClass; +typedef struct _ScanOptionsPrivate ScanOptionsPrivate; +typedef struct _ParamSpecScanOptions ParamSpecScanOptions; + +#define TYPE_SCAN_JOB (scan_job_get_type ()) +#define SCAN_JOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_JOB, ScanJob)) +#define SCAN_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_JOB, ScanJobClass)) +#define IS_SCAN_JOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_JOB)) +#define IS_SCAN_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_JOB)) +#define SCAN_JOB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_JOB, ScanJobClass)) + +typedef struct _ScanJob ScanJob; +typedef struct _ScanJobClass ScanJobClass; +typedef struct _ScanJobPrivate ScanJobPrivate; +typedef struct _ParamSpecScanJob ParamSpecScanJob; + +#define TYPE_REQUEST (request_get_type ()) +#define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_REQUEST, Request)) +#define REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_REQUEST, RequestClass)) +#define IS_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_REQUEST)) +#define IS_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_REQUEST)) +#define REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_REQUEST, RequestClass)) + +typedef struct _Request Request; +typedef struct _RequestClass RequestClass; +typedef struct _RequestPrivate RequestPrivate; +typedef struct _ParamSpecRequest ParamSpecRequest; + +#define TYPE_REQUEST_REDETECT (request_redetect_get_type ()) +#define REQUEST_REDETECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_REQUEST_REDETECT, RequestRedetect)) +#define REQUEST_REDETECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_REQUEST_REDETECT, RequestRedetectClass)) +#define IS_REQUEST_REDETECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_REQUEST_REDETECT)) +#define IS_REQUEST_REDETECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_REQUEST_REDETECT)) +#define REQUEST_REDETECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_REQUEST_REDETECT, RequestRedetectClass)) + +typedef struct _RequestRedetect RequestRedetect; +typedef struct _RequestRedetectClass RequestRedetectClass; +typedef struct _RequestRedetectPrivate RequestRedetectPrivate; + +#define TYPE_REQUEST_CANCEL (request_cancel_get_type ()) +#define REQUEST_CANCEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_REQUEST_CANCEL, RequestCancel)) +#define REQUEST_CANCEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_REQUEST_CANCEL, RequestCancelClass)) +#define IS_REQUEST_CANCEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_REQUEST_CANCEL)) +#define IS_REQUEST_CANCEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_REQUEST_CANCEL)) +#define REQUEST_CANCEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_REQUEST_CANCEL, RequestCancelClass)) + +typedef struct _RequestCancel RequestCancel; +typedef struct _RequestCancelClass RequestCancelClass; +typedef struct _RequestCancelPrivate RequestCancelPrivate; + +#define TYPE_REQUEST_START_SCAN (request_start_scan_get_type ()) +#define REQUEST_START_SCAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_REQUEST_START_SCAN, RequestStartScan)) +#define REQUEST_START_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_REQUEST_START_SCAN, RequestStartScanClass)) +#define IS_REQUEST_START_SCAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_REQUEST_START_SCAN)) +#define IS_REQUEST_START_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_REQUEST_START_SCAN)) +#define REQUEST_START_SCAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_REQUEST_START_SCAN, RequestStartScanClass)) + +typedef struct _RequestStartScan RequestStartScan; +typedef struct _RequestStartScanClass RequestStartScanClass; +typedef struct _RequestStartScanPrivate RequestStartScanPrivate; +#define _scan_job_unref0(var) ((var == NULL) ? NULL : (var = (scan_job_unref (var), NULL))) + +#define TYPE_REQUEST_QUIT (request_quit_get_type ()) +#define REQUEST_QUIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_REQUEST_QUIT, RequestQuit)) +#define REQUEST_QUIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_REQUEST_QUIT, RequestQuitClass)) +#define IS_REQUEST_QUIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_REQUEST_QUIT)) +#define IS_REQUEST_QUIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_REQUEST_QUIT)) +#define REQUEST_QUIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_REQUEST_QUIT, RequestQuitClass)) + +typedef struct _RequestQuit RequestQuit; +typedef struct _RequestQuitClass RequestQuitClass; +typedef struct _RequestQuitPrivate RequestQuitPrivate; + +#define TYPE_CREDENTIALS (credentials_get_type ()) +#define CREDENTIALS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CREDENTIALS, Credentials)) +#define CREDENTIALS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CREDENTIALS, CredentialsClass)) +#define IS_CREDENTIALS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CREDENTIALS)) +#define IS_CREDENTIALS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CREDENTIALS)) +#define CREDENTIALS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CREDENTIALS, CredentialsClass)) + +typedef struct _Credentials Credentials; +typedef struct _CredentialsClass CredentialsClass; +typedef struct _CredentialsPrivate CredentialsPrivate; +typedef struct _ParamSpecCredentials ParamSpecCredentials; + +#define TYPE_SCAN_STATE (scan_state_get_type ()) + +#define TYPE_NOTIFY (notify_get_type ()) +#define NOTIFY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY, Notify)) +#define NOTIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY, NotifyClass)) +#define IS_NOTIFY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY)) +#define IS_NOTIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY)) +#define NOTIFY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY, NotifyClass)) + +typedef struct _Notify Notify; +typedef struct _NotifyClass NotifyClass; +typedef struct _NotifyPrivate NotifyPrivate; + +#define TYPE_SCANNER (scanner_get_type ()) +#define SCANNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCANNER, Scanner)) +#define SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCANNER, ScannerClass)) +#define IS_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCANNER)) +#define IS_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCANNER)) +#define SCANNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCANNER, ScannerClass)) + +typedef struct _Scanner Scanner; +typedef struct _ScannerClass ScannerClass; +typedef struct _ParamSpecNotify ParamSpecNotify; + +#define TYPE_NOTIFY_SCANNING_CHANGED (notify_scanning_changed_get_type ()) +#define NOTIFY_SCANNING_CHANGED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_SCANNING_CHANGED, NotifyScanningChanged)) +#define NOTIFY_SCANNING_CHANGED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_SCANNING_CHANGED, NotifyScanningChangedClass)) +#define IS_NOTIFY_SCANNING_CHANGED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_SCANNING_CHANGED)) +#define IS_NOTIFY_SCANNING_CHANGED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_SCANNING_CHANGED)) +#define NOTIFY_SCANNING_CHANGED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_SCANNING_CHANGED, NotifyScanningChangedClass)) + +typedef struct _NotifyScanningChanged NotifyScanningChanged; +typedef struct _NotifyScanningChangedClass NotifyScanningChangedClass; +typedef struct _NotifyScanningChangedPrivate NotifyScanningChangedPrivate; + +#define TYPE_NOTIFY_UPDATE_DEVICES (notify_update_devices_get_type ()) +#define NOTIFY_UPDATE_DEVICES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_UPDATE_DEVICES, NotifyUpdateDevices)) +#define NOTIFY_UPDATE_DEVICES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_UPDATE_DEVICES, NotifyUpdateDevicesClass)) +#define IS_NOTIFY_UPDATE_DEVICES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_UPDATE_DEVICES)) +#define IS_NOTIFY_UPDATE_DEVICES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_UPDATE_DEVICES)) +#define NOTIFY_UPDATE_DEVICES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_UPDATE_DEVICES, NotifyUpdateDevicesClass)) + +typedef struct _NotifyUpdateDevices NotifyUpdateDevices; +typedef struct _NotifyUpdateDevicesClass NotifyUpdateDevicesClass; +typedef struct _NotifyUpdateDevicesPrivate NotifyUpdateDevicesPrivate; +#define __g_list_free__scan_device_unref0_0(var) ((var == NULL) ? NULL : (var = (_g_list_free__scan_device_unref0_ (var), NULL))) + +#define TYPE_NOTIFY_REQUEST_AUTHORIZATION (notify_request_authorization_get_type ()) +#define NOTIFY_REQUEST_AUTHORIZATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_REQUEST_AUTHORIZATION, NotifyRequestAuthorization)) +#define NOTIFY_REQUEST_AUTHORIZATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_REQUEST_AUTHORIZATION, NotifyRequestAuthorizationClass)) +#define IS_NOTIFY_REQUEST_AUTHORIZATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_REQUEST_AUTHORIZATION)) +#define IS_NOTIFY_REQUEST_AUTHORIZATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_REQUEST_AUTHORIZATION)) +#define NOTIFY_REQUEST_AUTHORIZATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_REQUEST_AUTHORIZATION, NotifyRequestAuthorizationClass)) + +typedef struct _NotifyRequestAuthorization NotifyRequestAuthorization; +typedef struct _NotifyRequestAuthorizationClass NotifyRequestAuthorizationClass; +typedef struct _NotifyRequestAuthorizationPrivate NotifyRequestAuthorizationPrivate; + +#define TYPE_NOTIFY_SCAN_FAILED (notify_scan_failed_get_type ()) +#define NOTIFY_SCAN_FAILED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_SCAN_FAILED, NotifyScanFailed)) +#define NOTIFY_SCAN_FAILED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_SCAN_FAILED, NotifyScanFailedClass)) +#define IS_NOTIFY_SCAN_FAILED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_SCAN_FAILED)) +#define IS_NOTIFY_SCAN_FAILED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_SCAN_FAILED)) +#define NOTIFY_SCAN_FAILED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_SCAN_FAILED, NotifyScanFailedClass)) + +typedef struct _NotifyScanFailed NotifyScanFailed; +typedef struct _NotifyScanFailedClass NotifyScanFailedClass; +typedef struct _NotifyScanFailedPrivate NotifyScanFailedPrivate; + +#define TYPE_NOTIFY_DOCUMENT_DONE (notify_document_done_get_type ()) +#define NOTIFY_DOCUMENT_DONE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_DOCUMENT_DONE, NotifyDocumentDone)) +#define NOTIFY_DOCUMENT_DONE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_DOCUMENT_DONE, NotifyDocumentDoneClass)) +#define IS_NOTIFY_DOCUMENT_DONE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_DOCUMENT_DONE)) +#define IS_NOTIFY_DOCUMENT_DONE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_DOCUMENT_DONE)) +#define NOTIFY_DOCUMENT_DONE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_DOCUMENT_DONE, NotifyDocumentDoneClass)) + +typedef struct _NotifyDocumentDone NotifyDocumentDone; +typedef struct _NotifyDocumentDoneClass NotifyDocumentDoneClass; +typedef struct _NotifyDocumentDonePrivate NotifyDocumentDonePrivate; + +#define TYPE_NOTIFY_EXPECT_PAGE (notify_expect_page_get_type ()) +#define NOTIFY_EXPECT_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_EXPECT_PAGE, NotifyExpectPage)) +#define NOTIFY_EXPECT_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_EXPECT_PAGE, NotifyExpectPageClass)) +#define IS_NOTIFY_EXPECT_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_EXPECT_PAGE)) +#define IS_NOTIFY_EXPECT_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_EXPECT_PAGE)) +#define NOTIFY_EXPECT_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_EXPECT_PAGE, NotifyExpectPageClass)) + +typedef struct _NotifyExpectPage NotifyExpectPage; +typedef struct _NotifyExpectPageClass NotifyExpectPageClass; +typedef struct _NotifyExpectPagePrivate NotifyExpectPagePrivate; + +#define TYPE_NOTIFY_GOT_PAGE_INFO (notify_got_page_info_get_type ()) +#define NOTIFY_GOT_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_GOT_PAGE_INFO, NotifyGotPageInfo)) +#define NOTIFY_GOT_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_GOT_PAGE_INFO, NotifyGotPageInfoClass)) +#define IS_NOTIFY_GOT_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_GOT_PAGE_INFO)) +#define IS_NOTIFY_GOT_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_GOT_PAGE_INFO)) +#define NOTIFY_GOT_PAGE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_GOT_PAGE_INFO, NotifyGotPageInfoClass)) + +typedef struct _NotifyGotPageInfo NotifyGotPageInfo; +typedef struct _NotifyGotPageInfoClass NotifyGotPageInfoClass; +typedef struct _NotifyGotPageInfoPrivate NotifyGotPageInfoPrivate; +#define _scan_page_info_unref0(var) ((var == NULL) ? NULL : (var = (scan_page_info_unref (var), NULL))) + +#define TYPE_NOTIFY_PAGE_DONE (notify_page_done_get_type ()) +#define NOTIFY_PAGE_DONE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_PAGE_DONE, NotifyPageDone)) +#define NOTIFY_PAGE_DONE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_PAGE_DONE, NotifyPageDoneClass)) +#define IS_NOTIFY_PAGE_DONE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_PAGE_DONE)) +#define IS_NOTIFY_PAGE_DONE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_PAGE_DONE)) +#define NOTIFY_PAGE_DONE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_PAGE_DONE, NotifyPageDoneClass)) + +typedef struct _NotifyPageDone NotifyPageDone; +typedef struct _NotifyPageDoneClass NotifyPageDoneClass; +typedef struct _NotifyPageDonePrivate NotifyPageDonePrivate; + +#define TYPE_NOTIFY_GOT_LINE (notify_got_line_get_type ()) +#define NOTIFY_GOT_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_NOTIFY_GOT_LINE, NotifyGotLine)) +#define NOTIFY_GOT_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_NOTIFY_GOT_LINE, NotifyGotLineClass)) +#define IS_NOTIFY_GOT_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_NOTIFY_GOT_LINE)) +#define IS_NOTIFY_GOT_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_NOTIFY_GOT_LINE)) +#define NOTIFY_GOT_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_NOTIFY_GOT_LINE, NotifyGotLineClass)) + +typedef struct _NotifyGotLine NotifyGotLine; +typedef struct _NotifyGotLineClass NotifyGotLineClass; +typedef struct _NotifyGotLinePrivate NotifyGotLinePrivate; +#define _scan_line_unref0(var) ((var == NULL) ? NULL : (var = (scan_line_unref (var), NULL))) +typedef struct _ScannerPrivate ScannerPrivate; +#define _g_async_queue_unref0(var) ((var == NULL) ? NULL : (var = (g_async_queue_unref (var), NULL))) +#define __g_list_free__scan_job_unref0_0(var) ((var == NULL) ? NULL : (var = (_g_list_free__scan_job_unref0_ (var), NULL))) +#define _scanner_unref0(var) ((var == NULL) ? NULL : (var = (scanner_unref (var), NULL))) +#define _notify_unref0(var) ((var == NULL) ? NULL : (var = (notify_unref (var), NULL))) +#define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL))) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) +#define _scan_device_unref0(var) ((var == NULL) ? NULL : (var = (scan_device_unref (var), NULL))) +#define _credentials_unref0(var) ((var == NULL) ? NULL : (var = (credentials_unref (var), NULL))) +#define _request_unref0(var) ((var == NULL) ? NULL : (var = (request_unref (var), NULL))) +typedef struct _ParamSpecScanner ParamSpecScanner; + +struct _ScanDevice { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanDevicePrivate * priv; +	gchar* name; +	gchar* label; +}; -#include "scanner.h" +struct _ScanDeviceClass { +	GTypeClass parent_class; +	void (*finalize) (ScanDevice *self); +}; -/* TODO: Could indicate the start of the next page immediately after the last page is received (i.e. before the sane_cancel()) */ +struct _ParamSpecScanDevice { +	GParamSpec parent_instance; +}; + +struct _ScanPageInfo { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanPageInfoPrivate * priv; +	gint width; +	gint height; +	gint depth; +	gint n_channels; +	gdouble dpi; +	gchar* device; +}; + +struct _ScanPageInfoClass { +	GTypeClass parent_class; +	void (*finalize) (ScanPageInfo *self); +}; + +struct _ParamSpecScanPageInfo { +	GParamSpec parent_instance; +}; + +struct _ScanLine { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanLinePrivate * priv; +	gint number; +	gint n_lines; +	gint width; +	gint depth; +	gint channel; +	guchar* data; +	gint data_length1; +	gint data_length; +}; + +struct _ScanLineClass { +	GTypeClass parent_class; +	void (*finalize) (ScanLine *self); +}; + +struct _ParamSpecScanLine { +	GParamSpec parent_instance; +}; + +typedef enum  { +	SCAN_MODE_DEFAULT, +	SCAN_MODE_COLOR, +	SCAN_MODE_GRAY, +	SCAN_MODE_LINEART +} ScanMode; + +typedef enum  { +	SCAN_TYPE_SINGLE, +	SCAN_TYPE_ADF_FRONT, +	SCAN_TYPE_ADF_BACK, +	SCAN_TYPE_ADF_BOTH +} ScanType; + +struct _ScanOptions { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanOptionsPrivate * priv; +	gint dpi; +	ScanMode scan_mode; +	gint depth; +	ScanType type; +	gint paper_width; +	gint paper_height; +}; + +struct _ScanOptionsClass { +	GTypeClass parent_class; +	void (*finalize) (ScanOptions *self); +}; + +struct _ParamSpecScanOptions { +	GParamSpec parent_instance; +}; + +struct _ScanJob { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanJobPrivate * priv; +	gchar* device; +	gdouble dpi; +	ScanMode scan_mode; +	gint depth; +	ScanType type; +	gint page_width; +	gint page_height; +}; + +struct _ScanJobClass { +	GTypeClass parent_class; +	void (*finalize) (ScanJob *self); +}; + +struct _ParamSpecScanJob { +	GParamSpec parent_instance; +}; + +struct _Request { +	GTypeInstance parent_instance; +	volatile int ref_count; +	RequestPrivate * priv; +}; + +struct _RequestClass { +	GTypeClass parent_class; +	void (*finalize) (Request *self); +}; -enum { -    UPDATE_DEVICES, -    AUTHORIZE, -    EXPECT_PAGE, -    GOT_PAGE_INFO, -    GOT_LINE, -    SCAN_FAILED, -    PAGE_DONE, -    DOCUMENT_DONE, -    SCANNING_CHANGED, -    LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0, }; - -typedef struct -{ -    Scanner *instance; -    guint sig; -    gpointer data; -} SignalInfo; - -typedef struct -{ -    gchar *device; -    gdouble dpi; -    ScanMode scan_mode; -    gint depth; -    gboolean type; -    gint page_width, page_height; -} ScanJob; - -typedef struct -{ -    enum -    { -       REQUEST_CANCEL, -       REQUEST_REDETECT, -       REQUEST_START_SCAN, -       REQUEST_QUIT -    } type; -    ScanJob *job; -} ScanRequest; - -typedef struct -{ -    gchar *username, *password; -} Credentials; - -typedef enum -{ -    STATE_IDLE = 0, -    STATE_REDETECT, -    STATE_OPEN, -    STATE_GET_OPTION, -    STATE_START, -    STATE_GET_PARAMETERS, -    STATE_READ +struct _ParamSpecRequest { +	GParamSpec parent_instance; +}; + +struct _RequestRedetect { +	Request parent_instance; +	RequestRedetectPrivate * priv; +}; + +struct _RequestRedetectClass { +	RequestClass parent_class; +}; + +struct _RequestCancel { +	Request parent_instance; +	RequestCancelPrivate * priv; +}; + +struct _RequestCancelClass { +	RequestClass parent_class; +}; + +struct _RequestStartScan { +	Request parent_instance; +	RequestStartScanPrivate * priv; +	ScanJob* job; +}; + +struct _RequestStartScanClass { +	RequestClass parent_class; +}; + +struct _RequestQuit { +	Request parent_instance; +	RequestQuitPrivate * priv; +}; + +struct _RequestQuitClass { +	RequestClass parent_class; +}; + +struct _Credentials { +	GTypeInstance parent_instance; +	volatile int ref_count; +	CredentialsPrivate * priv; +	gchar* username; +	gchar* password; +}; + +struct _CredentialsClass { +	GTypeClass parent_class; +	void (*finalize) (Credentials *self); +}; + +struct _ParamSpecCredentials { +	GParamSpec parent_instance; +}; + +typedef enum  { +	SCAN_STATE_IDLE = 0, +	SCAN_STATE_REDETECT, +	SCAN_STATE_OPEN, +	SCAN_STATE_GET_OPTION, +	SCAN_STATE_START, +	SCAN_STATE_GET_PARAMETERS, +	SCAN_STATE_READ  } ScanState; -struct ScannerPrivate -{ -    GAsyncQueue *scan_queue, *authorize_queue; -    GThread *thread; - -    gchar *default_device; - -    ScanState state; -    gboolean redetect; -   -    GList *job_queue; - -    /* Handle to SANE device */ -    SANE_Handle handle; -    gchar *current_device; -   -    SANE_Parameters parameters; - -    /* Last option read */ -    SANE_Int option_index; -   -    /* Option index for scan area */ -    SANE_Int br_x_option_index, br_y_option_index; - -    /* Buffer for received line */ -    SANE_Byte *buffer; -    SANE_Int buffer_size, n_used; - -    SANE_Int bytes_remaining, line_count, pass_number, page_number, notified_page; - -    gboolean scanning; -}; - -G_DEFINE_TYPE (Scanner, scanner, G_TYPE_OBJECT); - - -/* Table of scanner objects for each thread (required for authorization callback) */ -static GHashTable *scanners; - - -static gboolean -send_signal (SignalInfo *info) -{ -    g_signal_emit (info->instance, signals[info->sig], 0, info->data); - -    switch (info->sig) { -    case UPDATE_DEVICES: -        { -            GList *iter, *devices = info->data; -            for (iter = devices; iter; iter = iter->next) { -                ScanDevice *device = iter->data; -                g_free (device->name); -                g_free (device->label); -                g_free (device); -            } -            g_list_free (devices); -        } -        break; -    case AUTHORIZE: -        { -            gchar *resource = info->data; -            g_free (resource); -        } -        break; -    case GOT_PAGE_INFO: -        { -            ScanPageInfo *page_info = info->data; -            g_free (page_info); -        } -        break; -    case GOT_LINE: -        { -            ScanLine *line = info->data; -            g_free(line->data); -            g_free(line); -        } -        break; -    case SCAN_FAILED: -        { -            GError *error = info->data; -            g_error_free (error); -        } -        break; -    default: -    case EXPECT_PAGE: -    case PAGE_DONE: -    case DOCUMENT_DONE: -    case LAST_SIGNAL: -        g_assert (info->data == NULL); -        break; -    } -    g_free (info); - -    return FALSE; -} - - -/* Emit signals in main loop */ -static void -emit_signal (Scanner *scanner, guint sig, gpointer data) -{ -    SignalInfo *info; -     -    info = g_malloc(sizeof(SignalInfo)); -    info->instance = scanner; -    info->sig = sig; -    info->data = data; -    g_idle_add ((GSourceFunc) send_signal, info); -} - - -static void -set_scanning (Scanner *scanner, gboolean is_scanning) -{ -    if ((scanner->priv->scanning && !is_scanning) || (!scanner->priv->scanning && is_scanning)) { -        scanner->priv->scanning = is_scanning; -        emit_signal (scanner, SCANNING_CHANGED, NULL); -    } -} - - -static gint -get_device_weight (const gchar *device) -{ -    /* NOTE: This is using trends in the naming of SANE devices, SANE should be able to provide this information better */ -   -    /* Use webcams as a last resort */ -    if (g_str_has_prefix (device, "vfl:")) -       return 2; - -    /* Use locally connected devices first */ -    if (strstr (device, "usb")) -       return 0; - -    return 1; -} - - -static gint -compare_devices (ScanDevice *device1, ScanDevice *device2) -{ -    gint weight1, weight2; -   -    /* TODO: Should do some fuzzy matching on the last selected device and set that to the default */ - -    weight1 = get_device_weight (device1->name); -    weight2 = get_device_weight (device2->name); -    if (weight1 != weight2) -        return weight1 - weight2; -    -    return strcmp (device1->label, device2->label); -} - - -static const char * -get_status_string (SANE_Status status) -{ -    struct { -        SANE_Status status; -        const char *name; -    } status_names[] = { -        { SANE_STATUS_GOOD,          "SANE_STATUS_GOOD"}, -        { SANE_STATUS_UNSUPPORTED,   "SANE_STATUS_UNSUPPORTED"}, -        { SANE_STATUS_CANCELLED,     "SANE_STATUS_CANCELLED"}, -        { SANE_STATUS_DEVICE_BUSY,   "SANE_STATUS_DEVICE_BUSY"}, -        { SANE_STATUS_INVAL,         "SANE_STATUS_INVAL"}, -        { SANE_STATUS_EOF,           "SANE_STATUS_EOF"}, -        { SANE_STATUS_JAMMED,        "SANE_STATUS_JAMMED"}, -        { SANE_STATUS_NO_DOCS,       "SANE_STATUS_NO_DOCS"}, -        { SANE_STATUS_COVER_OPEN,    "SANE_STATUS_COVER_OPEN"}, -        { SANE_STATUS_IO_ERROR,      "SANE_STATUS_IO_ERROR"}, -        { SANE_STATUS_NO_MEM,        "SANE_STATUS_NO_MEM"}, -        { SANE_STATUS_ACCESS_DENIED, "SANE_STATUS_ACCESS_DENIED"}, -        { -1,                        NULL} -    }; -    static char *unknown_string = NULL; -    int i; - -    for (i = 0; status_names[i].name != NULL && status_names[i].status != status; i++); - -    if (status_names[i].name == NULL) { -        g_free (unknown_string); -        unknown_string = g_strdup_printf ("SANE_STATUS(%d)", status); -        return unknown_string; /* Note result is undefined on second call to this function */ -    } -   -    return status_names[i].name; -} - - -static const char * -get_action_string (SANE_Action action) -{ -    struct { -        SANE_Action action; -        const char *name; -    } action_names[] = { -        { SANE_ACTION_GET_VALUE, "SANE_ACTION_GET_VALUE" }, -        { SANE_ACTION_SET_VALUE, "SANE_ACTION_SET_VALUE" }, -        { SANE_ACTION_SET_AUTO,  "SANE_ACTION_SET_AUTO" }, -        { -1,                    NULL} -    }; -    static char *unknown_string = NULL; -    int i; - -    for (i = 0; action_names[i].name != NULL && action_names[i].action != action; i++); - -    if (action_names[i].name == NULL) { -        g_free (unknown_string); -        unknown_string = g_strdup_printf ("SANE_ACTION(%d)", action); -        return unknown_string; /* Note result is undefined on second call to this function */ -    } -   -    return action_names[i].name; -} - - -static const char * -get_frame_string (SANE_Frame frame) -{ -    struct { -        SANE_Frame frame; -        const char *name; -    } frame_names[] = { -        { SANE_FRAME_GRAY,  "SANE_FRAME_GRAY" }, -        { SANE_FRAME_RGB,   "SANE_FRAME_RGB" },       -        { SANE_FRAME_RED,   "SANE_FRAME_RED" }, -        { SANE_FRAME_GREEN, "SANE_FRAME_GREEN" }, -        { SANE_FRAME_BLUE,  "SANE_FRAME_BLUE" }, -        { -1,               NULL} -    }; -    static char *unknown_string = NULL; -    int i; - -    for (i = 0; frame_names[i].name != NULL && frame_names[i].frame != frame; i++); - -    if (frame_names[i].name == NULL) { -        g_free (unknown_string); -        unknown_string = g_strdup_printf ("SANE_FRAME(%d)", frame); -        return unknown_string; /* Note result is undefined on second call to this function */ -    } -   -    return frame_names[i].name; -} - - -static void -do_redetect (Scanner *scanner) -{ -    const SANE_Device **device_list, **device_iter; -    SANE_Status status; -    GList *devices = NULL; - -    status = sane_get_devices (&device_list, SANE_FALSE); -    g_debug ("sane_get_devices () -> %s", get_status_string (status)); -    if (status != SANE_STATUS_GOOD) { -        g_warning ("Unable to get SANE devices: %s", sane_strstatus(status)); -        scanner->priv->state = STATE_IDLE;         -        return; -    } - -    for (device_iter = device_list; *device_iter; device_iter++) { -        const SANE_Device *device = *device_iter; -        ScanDevice *scan_device; -        gchar *c, *label; - -        g_debug ("Device: name=\"%s\" vendor=\"%s\" model=\"%s\" type=\"%s\"", -                 device->name, device->vendor, device->model, device->type); -         -        scan_device = g_malloc0 (sizeof (ScanDevice)); - -        scan_device->name = g_strdup (device->name); - -        /* Abbreviate HP as it is a long string and does not match what is on the physical scanner */ -        if (strcmp (device->vendor, "Hewlett-Packard") == 0) -            label = g_strdup_printf ("HP %s", device->model); -        else -            label = g_strdup_printf ("%s %s", device->vendor, device->model); -         -        /* Replace underscored in name */ -        for (c = label; *c; c++) -            if (*c == '_') -                *c = ' '; - -        scan_device->label = label; - -        devices = g_list_append (devices, scan_device); -    } - -    /* Sort devices by priority */ -    devices = g_list_sort (devices, (GCompareFunc) compare_devices); - -    scanner->priv->redetect = FALSE; -    scanner->priv->state = STATE_IDLE; - -    g_free (scanner->priv->default_device); -    if (devices) { -        ScanDevice *device = g_list_nth_data (devices, 0); -        scanner->priv->default_device = g_strdup (device->name); -    } -    else -        scanner->priv->default_device = NULL; - -    emit_signal (scanner, UPDATE_DEVICES, devices); -} - - -static gboolean -control_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int index, SANE_Action action, void *value) -{ -    SANE_Status status; -    gchar *old_value; - -    switch (option->type) { -    case SANE_TYPE_BOOL: -        old_value = g_strdup_printf (*((SANE_Bool *) value) ? "SANE_TRUE" : "SANE_FALSE"); -        break; -    case SANE_TYPE_INT: -        old_value = g_strdup_printf ("%d", *((SANE_Int *) value)); -        break; -    case SANE_TYPE_FIXED: -        old_value = g_strdup_printf ("%f", SANE_UNFIX (*((SANE_Fixed *) value))); -        break; -    case SANE_TYPE_STRING: -        old_value = g_strdup_printf ("\"%s\"", (char *) value); -        break; -    default: -        old_value = g_strdup ("?"); -        break; -    } - -    status = sane_control_option (handle, index, action, value, NULL); -    switch (option->type) { -    case SANE_TYPE_BOOL: -        g_debug ("sane_control_option (%d, %s, %s) -> (%s, %s)", -                 index, get_action_string (action), -                 *((SANE_Bool *) value) ? "SANE_TRUE" : "SANE_FALSE", -                 get_status_string (status), -                 old_value); -        break; -    case SANE_TYPE_INT: -        g_debug ("sane_control_option (%d, %s, %d) -> (%s, %s)", -                 index, get_action_string (action), -                 *((SANE_Int *) value), -                 get_status_string (status), -                 old_value); -        break; -    case SANE_TYPE_FIXED: -        g_debug ("sane_control_option (%d, %s, %f) -> (%s, %s)", -                 index, get_action_string (action), -                 SANE_UNFIX (*((SANE_Fixed *) value)), -                 get_status_string (status), -                 old_value); -        break; -    case SANE_TYPE_STRING: -        g_debug ("sane_control_option (%d, %s, \"%s\") -> (%s, %s)", -                 index, get_action_string (action), -                 (char *) value, -                 get_status_string (status), -                 old_value); -        break; -    default: -        break; -    } -    g_free (old_value); - -    if (status != SANE_STATUS_GOOD) -        g_warning ("Error setting option %s: %s", option->name, sane_strstatus(status)); - -    return status == SANE_STATUS_GOOD; -} - - -static gboolean -set_default_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int option_index) -{ -    SANE_Status status; - -    /* Check if supports automatic option */ -    if ((option->cap & SANE_CAP_AUTOMATIC) == 0) -        return FALSE; - -    status = sane_control_option (handle, option_index, SANE_ACTION_SET_AUTO, NULL, NULL); -    g_debug ("sane_control_option (%d, SANE_ACTION_SET_AUTO) -> %s", -             option_index, get_status_string (status)); -    if (status != SANE_STATUS_GOOD) -        g_warning ("Error setting default option %s: %s", option->name, sane_strstatus(status)); - -    return status == SANE_STATUS_GOOD; -} - - -static void -set_bool_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int option_index, SANE_Bool value, SANE_Bool *result) -{ -    SANE_Bool v = value; -    g_return_if_fail (option->type == SANE_TYPE_BOOL); -    control_option (handle, option, option_index, SANE_ACTION_SET_VALUE, &v); -    if (result) -        *result = v; -} - - -static void -set_int_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int option_index, SANE_Int value, SANE_Int *result) -{ -    SANE_Int v = value; - -    g_return_if_fail (option->type == SANE_TYPE_INT); - -    if (option->constraint_type == SANE_CONSTRAINT_RANGE) { -        if (option->constraint.range->quant) -            v *= option->constraint.range->quant; -        if (v < option->constraint.range->min) -            v = option->constraint.range->min; -        if (v > option->constraint.range->max) -            v = option->constraint.range->max; -    } -    else if (option->constraint_type == SANE_CONSTRAINT_WORD_LIST) { -        int i; -        SANE_Int distance = INT_MAX, nearest = 0; - -        /* Find nearest value to requested */ -        for (i = 0; i < option->constraint.word_list[0]; i++) { -            SANE_Int x = option->constraint.word_list[i+1]; -            if (abs (x - v) < distance) { -                distance = abs (x - v); -                nearest = x; -            } -        } -        v = nearest; -    } - -    control_option (handle, option, option_index, SANE_ACTION_SET_VALUE, &v); -    if (result) -        *result = v; -} - - -static void -set_fixed_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int option_index, gdouble value, gdouble *result) -{ -    gdouble v = value; -    SANE_Fixed v_fixed; - -    g_return_if_fail (option->type == SANE_TYPE_FIXED); - -    if (option->constraint_type == SANE_CONSTRAINT_RANGE) { -        double min = SANE_UNFIX (option->constraint.range->min); -        double max = SANE_UNFIX (option->constraint.range->max); - -        if (v < min) -            v = min; -        if (v > max) -            v = max; -    } -    else if (option->constraint_type == SANE_CONSTRAINT_WORD_LIST) { -        int i; -        double distance = DBL_MAX, nearest = 0.0; - -        /* Find nearest value to requested */ -        for (i = 0; i < option->constraint.word_list[0]; i++) { -            double x = SANE_UNFIX (option->constraint.word_list[i+1]); -            if (fabs (x - v) < distance) { -                distance = fabs (x - v); -                nearest = x; -            } -        } -        v = nearest; -    } - -    v_fixed = SANE_FIX (v); -    control_option (handle, option, option_index, SANE_ACTION_SET_VALUE, &v_fixed); -    if (result) -        *result = SANE_UNFIX (v_fixed); -} - - -static gboolean -set_string_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int option_index, const char *value, char **result) -{ -    char *string; -    gsize value_size, size; -    gboolean error; - -    g_return_val_if_fail (option->type == SANE_TYPE_STRING, FALSE); -     -    value_size = strlen (value) + 1; -    size = option->size > value_size ? option->size : value_size; -    string = g_malloc(sizeof(char) * size); -    strcpy (string, value); -    error = control_option (handle, option, option_index, SANE_ACTION_SET_VALUE, string); -    if (result) -        *result = string; -    else -        g_free (string); -    -    return error; -} - - -static gboolean -set_constrained_string_option (SANE_Handle handle, const SANE_Option_Descriptor *option, SANE_Int option_index, const char *values[], char **result) -{ -    gint i, j; - -    g_return_val_if_fail (option->type == SANE_TYPE_STRING, FALSE);   -    g_return_val_if_fail (option->constraint_type == SANE_CONSTRAINT_STRING_LIST, FALSE); -   -    for (i = 0; values[i] != NULL; i++) { -        for (j = 0; option->constraint.string_list[j]; j++) { -            if (strcmp (values[i], option->constraint.string_list[j]) == 0) -               break; -        } - -        if (option->constraint.string_list[j] != NULL) -            return set_string_option (handle, option, option_index, values[i], result); -    } -   -    return FALSE; -} - - -static void -log_option (SANE_Int index, const SANE_Option_Descriptor *option) -{ -    GString *string; -    SANE_Word i; -    SANE_Int cap; -     -    string = g_string_new (""); - -    g_string_append_printf (string, "Option %d:", index); -     -    if (option->name)     -        g_string_append_printf (string, " name='%s'", option->name); -     -    if (option->title) -        g_string_append_printf (string, " title='%s'", option->title); - -    switch (option->type) { -    case SANE_TYPE_BOOL: -        g_string_append (string, " type=bool"); -        break; -    case SANE_TYPE_INT: -        g_string_append (string, " type=int"); -        break; -    case SANE_TYPE_FIXED: -        g_string_append (string, " type=fixed");         -        break; -    case SANE_TYPE_STRING: -        g_string_append (string, " type=string");         -        break; -    case SANE_TYPE_BUTTON: -        g_string_append (string, " type=button");         -        break; -    case SANE_TYPE_GROUP: -        g_string_append (string, " type=group"); -        break; -    default: -        g_string_append_printf (string, " type=%d", option->type); -        break; -    } -     -    g_string_append_printf (string, " size=%d", option->size); - -    switch (option->unit) { -    case SANE_UNIT_NONE: -        break; -    case SANE_UNIT_PIXEL: -        g_string_append (string, " unit=pixels"); -        break; -    case SANE_UNIT_BIT: -        g_string_append (string, " unit=bits"); -        break; -    case SANE_UNIT_MM: -        g_string_append (string, " unit=mm"); -        break; -    case SANE_UNIT_DPI: -        g_string_append (string, " unit=dpi"); -        break; -    case SANE_UNIT_PERCENT: -        g_string_append (string, " unit=percent"); -        break; -    case SANE_UNIT_MICROSECOND: -        g_string_append (string, " unit=microseconds"); -        break; -    default: -        g_string_append_printf (string, " unit=%d", option->unit); -        break; -    } - -    switch (option->constraint_type) { -    case SANE_CONSTRAINT_RANGE: -        if (option->type == SANE_TYPE_FIXED) -            g_string_append_printf (string, " min=%f, max=%f, quant=%d", -                                    SANE_UNFIX (option->constraint.range->min), SANE_UNFIX (option->constraint.range->max), -                                    option->constraint.range->quant); -        else -            g_string_append_printf (string, " min=%d, max=%d, quant=%d", -                                    option->constraint.range->min, option->constraint.range->max, -                                    option->constraint.range->quant); -        break; -    case SANE_CONSTRAINT_WORD_LIST: -        g_string_append (string, " values=["); -        for (i = 0; i < option->constraint.word_list[0]; i++) { -            if (i != 0) -                g_string_append (string, ", "); -            if (option->type == SANE_TYPE_INT) -                g_string_append_printf (string, "%d", option->constraint.word_list[i+1]); -            else -                g_string_append_printf (string, "%f", SANE_UNFIX (option->constraint.word_list[i+1])); -        } -        g_string_append (string, "]"); -        break; -    case SANE_CONSTRAINT_STRING_LIST: -        g_string_append (string, " values=["); -        for (i = 0; option->constraint.string_list[i]; i++) { -            if (i != 0) -                g_string_append (string, ", "); -            g_string_append_printf (string, "\"%s\"", option->constraint.string_list[i]); -        } -        g_string_append (string, "]"); -        break; -    default: -        break; -    } -     -    cap = option->cap; -    if (cap) { -        struct { -            SANE_Int cap; -            const char *name; -        } caps[] = { -            { SANE_CAP_SOFT_SELECT,     "soft-select"}, -            { SANE_CAP_HARD_SELECT,     "hard-select"}, -            { SANE_CAP_SOFT_DETECT,     "soft-detect"}, -            { SANE_CAP_EMULATED,        "emulated"}, -            { SANE_CAP_AUTOMATIC,       "automatic"}, -            { SANE_CAP_INACTIVE,        "inactive"}, -            { SANE_CAP_ADVANCED,        "advanced"}, -            { 0,                        NULL} -        }; -        int i, n = 0; -         -        g_string_append (string, " cap="); -        for (i = 0; caps[i].cap > 0; i++) { -            if (cap & caps[i].cap) { -                cap &= ~caps[i].cap; -                if (n != 0) -                    g_string_append (string, ","); -                g_string_append (string, caps[i].name); -                n++; -            } -        } -        /* Unknown capabilities */ -        if (cap) { -            if (n != 0) -                g_string_append (string, ","); -            g_string_append_printf (string, "%x", cap); -        } -    } - -    g_debug ("%s", string->str); -    g_string_free (string, TRUE); - -    if (option->desc) -        g_debug ("  Description: %s", option->desc); -} - - -static void -authorization_cb (SANE_String_Const resource, SANE_Char username[SANE_MAX_USERNAME_LEN], SANE_Char password[SANE_MAX_PASSWORD_LEN]) -{ -    Scanner *scanner; -    Credentials *credentials; -    -    scanner = g_hash_table_lookup (scanners, g_thread_self ()); - -    emit_signal (scanner, AUTHORIZE, g_strdup (resource)); - -    credentials = g_async_queue_pop (scanner->priv->authorize_queue); -    strncpy (username, credentials->username, SANE_MAX_USERNAME_LEN); -    strncpy (password, credentials->password, SANE_MAX_PASSWORD_LEN); -    g_free (credentials); -} - - -void -scanner_authorize (Scanner *scanner, const gchar *username, const gchar *password) -{ -    Credentials *credentials; - -    credentials = g_malloc (sizeof (Credentials)); -    credentials->username = g_strdup (username); -    credentials->password = g_strdup (password); -    g_async_queue_push (scanner->priv->authorize_queue, credentials); -} - - -static void -close_device (Scanner *scanner) -{ -    GList *iter; - -    if (scanner->priv->handle) { -        sane_cancel (scanner->priv->handle); -        g_debug ("sane_cancel ()"); - -        sane_close (scanner->priv->handle); -        g_debug ("sane_close ()"); -        scanner->priv->handle = NULL; -    } - -    g_free (scanner->priv->buffer); -    scanner->priv->buffer = NULL; - -    for (iter = scanner->priv->job_queue; iter; iter = iter->next) { -        ScanJob *job = (ScanJob *) iter->data; -        g_free (job->device); -        g_free (job); -    } -    g_list_free (scanner->priv->job_queue); -    scanner->priv->job_queue = NULL; -   -    set_scanning (scanner, FALSE); -} - -static void -fail_scan (Scanner *scanner, gint error_code, const gchar *error_string) -{ -    close_device (scanner); -    scanner->priv->state = STATE_IDLE; -    emit_signal (scanner, SCAN_FAILED, g_error_new (SCANNER_TYPE, error_code, "%s", error_string)); -} - - -static gboolean -handle_requests (Scanner *scanner) -{ -    gint request_count = 0; -   -    /* Redetect when idle */ -    if (scanner->priv->state == STATE_IDLE && scanner->priv->redetect) -        scanner->priv->state = STATE_REDETECT; -   -    /* Process all requests */ -    while (TRUE) { -        ScanRequest *request = NULL; - -        if ((scanner->priv->state == STATE_IDLE && request_count == 0) || -            g_async_queue_length (scanner->priv->scan_queue) > 0) -            request = g_async_queue_pop (scanner->priv->scan_queue); -        else -            return TRUE; - -         g_debug ("Processing request"); -         request_count++; - -         switch (request->type) { -         case REQUEST_REDETECT: -             break; - -         case REQUEST_START_SCAN: -             scanner->priv->job_queue = g_list_append (scanner->priv->job_queue, request->job); -             break; - -         case REQUEST_CANCEL: -             fail_scan (scanner, SANE_STATUS_CANCELLED, "Scan cancelled - do not report this error"); -             break; - -         case REQUEST_QUIT: -             close_device (scanner); -             g_free (request); -             return FALSE; -         } - -         g_free (request); -    } -   -    return TRUE; -} - - -static void -do_open (Scanner *scanner) -{ -    SANE_Status status; -    ScanJob *job; - -    job = (ScanJob *) scanner->priv->job_queue->data; - -    scanner->priv->line_count = 0; -    scanner->priv->pass_number = 0; -    scanner->priv->page_number = 0; -    scanner->priv->notified_page = -1; -    scanner->priv->option_index = 0; -    scanner->priv->br_x_option_index = 0; -    scanner->priv->br_y_option_index = 0; - -    if (!job->device && scanner->priv->default_device) -        job->device = g_strdup (scanner->priv->default_device); - -    if (!job->device) { -        g_warning ("No scan device available"); -        fail_scan (scanner, 0, -                   /* Error displayed when no scanners to scan with */ -                   _("No scanners available.  Please connect a scanner.")); -        return; -    } -  -    /* See if we can use the already open device */ -    if (scanner->priv->handle) { -        if (strcmp (scanner->priv->current_device, job->device) == 0) { -            scanner->priv->state = STATE_GET_OPTION; -            return; -        } - -        sane_close (scanner->priv->handle); -        g_debug ("sane_close ()"); -        scanner->priv->handle = NULL; -    } -   -    g_free (scanner->priv->current_device); -    scanner->priv->current_device = NULL; - -    status = sane_open (job->device, &scanner->priv->handle); -    g_debug ("sane_open (\"%s\") -> %s", job->device, get_status_string (status)); - -    if (status != SANE_STATUS_GOOD) { -        g_warning ("Unable to get open device: %s", sane_strstatus (status)); -        scanner->priv->handle = NULL; -        fail_scan (scanner, status, -                   /* Error displayed when cannot connect to scanner */ -                   _("Unable to connect to scanner")); -        return; -    } - -    scanner->priv->current_device = g_strdup (job->device); -    scanner->priv->state = STATE_GET_OPTION; -} - - -static void -do_get_option (Scanner *scanner) -{ -    const SANE_Option_Descriptor *option; -    SANE_Int option_index; -    ScanJob *job; - -    job = (ScanJob *) scanner->priv->job_queue->data;   - -    option = sane_get_option_descriptor (scanner->priv->handle, scanner->priv->option_index); -    g_debug ("sane_get_option_descriptor (%d)", scanner->priv->option_index); -    option_index = scanner->priv->option_index; -    scanner->priv->option_index++; - -    if (!option) { -        /* Always use maximum scan area - some scanners default to using partial areas.  This should be patched in sane-backends */ -        if (scanner->priv->br_x_option_index) { -            option = sane_get_option_descriptor (scanner->priv->handle, scanner->priv->br_x_option_index); -            g_debug ("sane_get_option_descriptor (%d)", scanner->priv->br_x_option_index); -            if (option->constraint_type == SANE_CONSTRAINT_RANGE) { -                if (option->type == SANE_TYPE_FIXED) -                    set_fixed_option (scanner->priv->handle, option, scanner->priv->br_x_option_index, SANE_UNFIX (option->constraint.range->max), NULL); -                else -                    set_int_option (scanner->priv->handle, option, scanner->priv->br_x_option_index, option->constraint.range->max, NULL); -            } -        } -        if (scanner->priv->br_y_option_index) { -            option = sane_get_option_descriptor (scanner->priv->handle, scanner->priv->br_y_option_index); -            g_debug ("sane_get_option_descriptor (%d)", scanner->priv->br_y_option_index); -            if (option->constraint_type == SANE_CONSTRAINT_RANGE) { -                if (option->type == SANE_TYPE_FIXED) -                    set_fixed_option (scanner->priv->handle, option, scanner->priv->br_y_option_index, SANE_UNFIX (option->constraint.range->max), NULL); -                else -                    set_int_option (scanner->priv->handle, option, scanner->priv->br_y_option_index, option->constraint.range->max, NULL); -            } -        } - -        scanner->priv->state = STATE_START; -        return; -    } - -    log_option (option_index, option); -   -    /* Ignore groups */ -    if (option->type == SANE_TYPE_GROUP) -        return; - -    /* Option disabled */ -    if (option->cap & SANE_CAP_INACTIVE) -        return; -   -    /* Some options are unnammed (e.g. Option 0) */ -    if (option->name == NULL) -        return; - -    if (strcmp (option->name, SANE_NAME_SCAN_RESOLUTION) == 0) { -        if (option->type == SANE_TYPE_FIXED) { -            set_fixed_option (scanner->priv->handle, option, option_index, job->dpi, &job->dpi); -        } -        else { -            SANE_Int dpi; -            set_int_option (scanner->priv->handle, option, option_index, job->dpi, &dpi); -            job->dpi = dpi; -        } -    } -    else if (strcmp (option->name, SANE_NAME_SCAN_SOURCE) == 0) { -        const char *flatbed_sources[] = -        { -            "Auto", -            SANE_I18N ("Auto"), -            "Flatbed", -            SANE_I18N ("Flatbed"), -            "FlatBed", -            "Normal", -            SANE_I18N ("Normal"), -            NULL -        }; - -        const char *adf_sources[] = -        { -            "Automatic Document Feeder", -            SANE_I18N ("Automatic Document Feeder"), -            "ADF", -            "Automatic Document Feeder(left aligned)", /* Seen in the proprietary brother3 driver */ -            "Automatic Document Feeder(centrally aligned)", /* Seen in the proprietary brother3 driver */ -            NULL -        }; - -        const char *adf_front_sources[] = -        { -            "ADF Front", -            SANE_I18N ("ADF Front"), -            NULL -        }; - -        const char *adf_back_sources[] = -        { -            "ADF Back", -            SANE_I18N ("ADF Back"), -            NULL -        }; - -        const char *adf_duplex_sources[] = -        { -            "ADF Duplex", -            SANE_I18N ("ADF Duplex"), -            NULL -        }; - -        switch (job->type) { -        case SCAN_SINGLE: -            if (!set_default_option (scanner->priv->handle, option, option_index)) -                if (!set_constrained_string_option (scanner->priv->handle, option, option_index, flatbed_sources, NULL)) -                    g_warning ("Unable to set single page source, please file a bug"); -            break; -        case SCAN_ADF_FRONT: -            if (!set_constrained_string_option (scanner->priv->handle, option, option_index, adf_front_sources, NULL)) -                if (!!set_constrained_string_option (scanner->priv->handle, option, option_index, adf_sources, NULL))                 -                    g_warning ("Unable to set front ADF source, please file a bug"); -            break; -        case SCAN_ADF_BACK: -            if (!set_constrained_string_option (scanner->priv->handle, option, option_index, adf_back_sources, NULL)) -                if (!set_constrained_string_option (scanner->priv->handle, option, option_index, adf_sources, NULL)) -                    g_warning ("Unable to set back ADF source, please file a bug"); -            break; -        case SCAN_ADF_BOTH: -            if (!set_constrained_string_option (scanner->priv->handle, option, option_index, adf_duplex_sources, NULL)) -                if (!set_constrained_string_option (scanner->priv->handle, option, option_index, adf_sources, NULL)) -                    g_warning ("Unable to set duplex ADF source, please file a bug"); -            break; -        } -    } -    else if (strcmp (option->name, "duplex") == 0) { -        if (option->type == SANE_TYPE_BOOL) -            set_bool_option (scanner->priv->handle, option, option_index, job->type == SCAN_ADF_BOTH, NULL); -    } -    else if (strcmp (option->name, "batch-scan") == 0) { -        if (option->type == SANE_TYPE_BOOL) -            set_bool_option (scanner->priv->handle, option, option_index, job->type != SCAN_SINGLE, NULL); -    } -    else if (strcmp (option->name, SANE_NAME_BIT_DEPTH) == 0) { -        if (job->depth > 0) -            set_int_option (scanner->priv->handle, option, option_index, job->depth, NULL); -    } -    else if (strcmp (option->name, SANE_NAME_SCAN_MODE) == 0) { -        /* The names of scan modes often used in drivers, as taken from the sane-backends source */ -        const char *color_scan_modes[] = -        { -            SANE_VALUE_SCAN_MODE_COLOR, -            "Color", -            "24bit Color", /* Seen in the proprietary brother3 driver */ -            NULL -        }; -        const char *gray_scan_modes[] = -        { -            SANE_VALUE_SCAN_MODE_GRAY, -            "Gray", -            "Grayscale", -            SANE_I18N ("Grayscale"), -            "True Gray", /* Seen in the proprietary brother3 driver */ -            NULL -        }; -        const char *lineart_scan_modes[] = -        { -            SANE_VALUE_SCAN_MODE_LINEART, -            "Lineart", -            "LineArt", -            SANE_I18N ("LineArt"), -            "Black & White", -            SANE_I18N ("Black & White"), -            "Binary", -            SANE_I18N ("Binary"), -            "Thresholded", -            SANE_VALUE_SCAN_MODE_GRAY, -            "Gray", -            "Grayscale", -            SANE_I18N ("Grayscale"), -            "True Gray", /* Seen in the proprietary brother3 driver */ -            NULL -        }; -             -        switch (job->scan_mode) { -        case SCAN_MODE_COLOR: -            if (!set_constrained_string_option (scanner->priv->handle, option, option_index, color_scan_modes, NULL)) -                g_warning ("Unable to set Color mode, please file a bug"); -            break; -        case SCAN_MODE_GRAY: -            if (!set_constrained_string_option (scanner->priv->handle, option, option_index, gray_scan_modes, NULL)) -                g_warning ("Unable to set Gray mode, please file a bug"); -            break; -        case SCAN_MODE_LINEART: -            if (!set_constrained_string_option (scanner->priv->handle, option, option_index, lineart_scan_modes, NULL)) -                g_warning ("Unable to set Lineart mode, please file a bug"); -            break; -        default: -            break; -        } -    } -    /* Disable compression, we will compress after scanning */ -    else if (strcmp (option->name, "compression") == 0) { -        const char *disable_compression_names[] = -        { -            SANE_I18N ("None"), -            SANE_I18N ("none"), -            "None", -            "none", -            NULL -        }; -             -        if (!set_constrained_string_option (scanner->priv->handle, option, option_index, disable_compression_names, NULL)) -            g_warning ("Unable to disable compression, please file a bug"); -    } -    else if (strcmp (option->name, SANE_NAME_SCAN_BR_X) == 0) -        scanner->priv->br_x_option_index = option_index; -    else if (strcmp (option->name, SANE_NAME_SCAN_BR_Y) == 0) -        scanner->priv->br_y_option_index = option_index; -    else if (strcmp (option->name, SANE_NAME_PAGE_WIDTH) == 0) { -        if (job->page_width > 0.0) { -            if (option->type == SANE_TYPE_FIXED) -                set_fixed_option (scanner->priv->handle, option, option_index, job->page_width / 10.0, NULL); -            else -                set_int_option (scanner->priv->handle, option, option_index, job->page_width / 10, NULL); -        } -    } -    else if (strcmp (option->name, SANE_NAME_PAGE_HEIGHT) == 0) { -        if (job->page_height > 0.0) { -            if (option->type == SANE_TYPE_FIXED) -                set_fixed_option (scanner->priv->handle, option, option_index, job->page_height / 10.0, NULL); -            else  -                set_int_option (scanner->priv->handle, option, option_index, job->page_height / 10, NULL); -        } -    } - -    /* Test scanner options (hoping will not effect other scanners...) */ -    if (strcmp (scanner->priv->current_device, "test") == 0) { -        if (strcmp (option->name, "hand-scanner") == 0) { -            set_bool_option (scanner->priv->handle, option, option_index, FALSE, NULL); -        } -        else if (strcmp (option->name, "three-pass") == 0) { -            set_bool_option (scanner->priv->handle, option, option_index, FALSE, NULL); -        } -        else if (strcmp (option->name, "test-picture") == 0) { -            set_string_option (scanner->priv->handle, option, option_index, "Color pattern", NULL); -        } -        else if (strcmp (option->name, "read-delay") == 0) { -            set_bool_option (scanner->priv->handle, option, option_index, TRUE, NULL); -        } -        else if (strcmp (option->name, "read-delay-duration") == 0) { -            set_int_option (scanner->priv->handle, option, option_index, 200000, NULL); -        } -    } -} - - -static void -do_complete_document (Scanner *scanner) -{ -    ScanJob *job; - -    job = (ScanJob *) scanner->priv->job_queue->data; -    g_free (job->device); -    g_free (job); -    scanner->priv->job_queue = g_list_remove_link (scanner->priv->job_queue, scanner->priv->job_queue); - -    scanner->priv->state = STATE_IDLE; -   -    /* Continue onto the next job */ -    if (scanner->priv->job_queue) { -        scanner->priv->state = STATE_OPEN; -        return; -    } - -    /* Trigger timeout to close */ -    // TODO - -    emit_signal (scanner, DOCUMENT_DONE, NULL); -    set_scanning (scanner, FALSE); -} - - -static void -do_start (Scanner *scanner) -{ -    SANE_Status status; - -    emit_signal (scanner, EXPECT_PAGE, NULL); - -    status = sane_start (scanner->priv->handle); -    g_debug ("sane_start (page=%d, pass=%d) -> %s", scanner->priv->page_number, scanner->priv->pass_number, get_status_string (status)); -    if (status == SANE_STATUS_GOOD) { -        scanner->priv->state = STATE_GET_PARAMETERS; -    } -    else if (status == SANE_STATUS_NO_DOCS) { -        do_complete_document (scanner); -    } -    else { -        g_warning ("Unable to start device: %s", sane_strstatus (status)); -        fail_scan (scanner, status, -                   /* Error display when unable to start scan */ -                   _("Unable to start scan")); -    } -} - - -static void -do_get_parameters (Scanner *scanner) -{ -    SANE_Status status; -    ScanPageInfo *info; -    ScanJob *job; - -    status = sane_get_parameters (scanner->priv->handle, &scanner->priv->parameters); -    g_debug ("sane_get_parameters () -> %s", get_status_string (status)); -    if (status != SANE_STATUS_GOOD) { -        g_warning ("Unable to get device parameters: %s", sane_strstatus (status)); -        fail_scan (scanner, status, -                   /* Error displayed when communication with scanner broken */ -                   _("Error communicating with scanner")); -        return; -    } -   -    job = (ScanJob *) scanner->priv->job_queue->data; - -    g_debug ("Parameters: format=%s last_frame=%s bytes_per_line=%d pixels_per_line=%d lines=%d depth=%d", -             get_frame_string (scanner->priv->parameters.format), -             scanner->priv->parameters.last_frame ? "SANE_TRUE" : "SANE_FALSE", -             scanner->priv->parameters.bytes_per_line, -             scanner->priv->parameters.pixels_per_line, -             scanner->priv->parameters.lines, -             scanner->priv->parameters.depth); - -    info = g_malloc(sizeof(ScanPageInfo)); -    info->width = scanner->priv->parameters.pixels_per_line; -    info->height = scanner->priv->parameters.lines; -    info->depth = scanner->priv->parameters.depth; -    /* Reduce bit depth if requested lower than received */ -    // FIXME: This a hack and only works on 8 bit gray to 2 bit gray -    if (scanner->priv->parameters.depth == 8 && scanner->priv->parameters.format == SANE_FRAME_GRAY && job->depth == 2 && job->scan_mode == SCAN_MODE_GRAY) -        info->depth = job->depth; -    info->n_channels = scanner->priv->parameters.format == SANE_FRAME_GRAY ? 1 : 3; -    info->dpi = job->dpi; // FIXME: This is the requested DPI, not the actual DPI -    info->device = g_strdup (scanner->priv->current_device); - -    if (scanner->priv->page_number != scanner->priv->notified_page) { -        emit_signal (scanner, GOT_PAGE_INFO, info); -        scanner->priv->notified_page = scanner->priv->page_number; -    } - -    /* Prepare for read */ -    scanner->priv->buffer_size = scanner->priv->parameters.bytes_per_line + 1; /* Use +1 so buffer is not resized if driver returns one line per read */ -    scanner->priv->buffer = g_malloc (sizeof(SANE_Byte) * scanner->priv->buffer_size); -    scanner->priv->n_used = 0; -    scanner->priv->line_count = 0; -    scanner->priv->pass_number = 0; -    scanner->priv->state = STATE_READ; -} - - -static void -do_complete_page (Scanner *scanner) -{ -    ScanJob *job; - -    emit_signal (scanner, PAGE_DONE, NULL); -   -    job = (ScanJob *) scanner->priv->job_queue->data; - -    /* If multi-pass then scan another page */ -    if (!scanner->priv->parameters.last_frame) { -        scanner->priv->pass_number++; -        scanner->priv->state = STATE_START; -        return; -    } - -    /* Go back for another page */ -    if (job->type != SCAN_SINGLE) { -        scanner->priv->page_number++; -        scanner->priv->pass_number = 0; -        emit_signal (scanner, PAGE_DONE, NULL); -        scanner->priv->state = STATE_START; -        return; -    } - -    sane_cancel (scanner->priv->handle); -    g_debug ("sane_cancel ()"); - -    do_complete_document (scanner); -} - - -static void -do_read (Scanner *scanner) -{ -    ScanJob *job; -    SANE_Status status; -    SANE_Int n_to_read, n_read; -    gboolean full_read = FALSE; - -    job = (ScanJob *) scanner->priv->job_queue->data; - -    /* Read as many bytes as we expect */ -    n_to_read = scanner->priv->buffer_size - scanner->priv->n_used; - -    status = sane_read (scanner->priv->handle, -                        scanner->priv->buffer + scanner->priv->n_used, -                        n_to_read, &n_read); -    g_debug ("sane_read (%d) -> (%s, %d)", n_to_read, get_status_string (status), n_read); - -    /* Completed read */ -    if (status == SANE_STATUS_EOF) { -        if (scanner->priv->parameters.lines > 0 && scanner->priv->line_count != scanner->priv->parameters.lines) -            g_warning ("Scan completed with %d lines, expected %d lines", scanner->priv->parameters.lines, scanner->priv->parameters.lines); -        if (scanner->priv->n_used > 0) -            g_warning ("Scan complete with %d bytes of unused data", scanner->priv->n_used); -        do_complete_page (scanner); -        return; -    } -             -    /* Communication error */ -    if (status != SANE_STATUS_GOOD) { -        g_warning ("Unable to read frame from device: %s", sane_strstatus (status)); -        fail_scan (scanner, status, -                   /* Error displayed when communication with scanner broken */ -                   _("Error communicating with scanner")); -        return; -    } - -    if (scanner->priv->n_used == 0 && n_read == scanner->priv->buffer_size) -        full_read = TRUE; -    scanner->priv->n_used += n_read; -   -    /* Feed out lines */ -    if (scanner->priv->n_used >= scanner->priv->parameters.bytes_per_line) { -        ScanLine *line; -        int i, n_remaining; - -        line = g_malloc(sizeof(ScanLine)); -        switch (scanner->priv->parameters.format) { -        case SANE_FRAME_GRAY: -            line->channel = 0; -            break; -        case SANE_FRAME_RGB: -            line->channel = -1; -            break; -        case SANE_FRAME_RED: -            line->channel = 0; -            break; -        case SANE_FRAME_GREEN: -            line->channel = 1; -            break; -        case SANE_FRAME_BLUE: -            line->channel = 2; -            break; -        } -        line->width = scanner->priv->parameters.pixels_per_line; -        line->depth = scanner->priv->parameters.depth; -        line->data = scanner->priv->buffer; -        line->data_length = scanner->priv->parameters.bytes_per_line; -        line->number = scanner->priv->line_count; -        line->n_lines = scanner->priv->n_used / line->data_length; - -        scanner->priv->buffer = NULL; -        scanner->priv->line_count += line->n_lines; - -        /* Increase buffer size if did full read */ -        if (full_read) -            scanner->priv->buffer_size += scanner->priv->parameters.bytes_per_line; - -        scanner->priv->buffer = g_malloc(sizeof(SANE_Byte) * scanner->priv->buffer_size); -        n_remaining = scanner->priv->n_used - (line->n_lines * line->data_length); -        scanner->priv->n_used = 0; -        for (i = 0; i < n_remaining; i++) { -            scanner->priv->buffer[i] = line->data[i + (line->n_lines * line->data_length)]; -            scanner->priv->n_used++; -        } - -        /* Reduce bit depth if requested lower than received */ -        // FIXME: This a hack and only works on 8 bit gray to 2 bit gray -        if (scanner->priv->parameters.depth == 8 && scanner->priv->parameters.format == SANE_FRAME_GRAY && -            job->depth == 2 && job->scan_mode == SCAN_MODE_GRAY) { -            gint block_shift = 6; -            guchar block = 0; -            guchar *write_ptr = line->data; - -            for (i = 0; i < line->n_lines; i++) { -                guchar *in_line = line->data + i * line->data_length; -                gint x; - -                for (x = 0; x < line->width; x++) { -                     guchar *p = in_line + x; -                     guchar sample; - -                     if (p[0] >= 192) -                         sample = 3; -                     else if (p[0] >= 128) -                         sample = 2; -                     else if (p[0] >= 64) -                         sample = 1; -                     else -                         sample = 0; - -                     block |= sample << block_shift; -                     if (block_shift == 0) { -                         *write_ptr = block; -                         write_ptr++; -                         block = 0; -                         block_shift = 6; -                     } -                     else { -                         block_shift -= 2; -                     } -                } - -                /* Finish each line on a byte boundary */ -                if (block_shift != 6)  { -                    *write_ptr = block; -                    write_ptr++; -                    block = 0; -                    block_shift = 6; -                } -            } - -            line->data_length = (line->width * 2 + 7) / 8; -        } - -        emit_signal (scanner, GOT_LINE, line); -    } -} - - -static gpointer -scan_thread (Scanner *scanner) -{ -    SANE_Status status; -    SANE_Int version_code; -   -    g_hash_table_insert (scanners, g_thread_self (), scanner); -   -    scanner->priv->state = STATE_IDLE; - -    status = sane_init (&version_code, authorization_cb); -    g_debug ("sane_init () -> %s", get_status_string (status)); -    if (status != SANE_STATUS_GOOD) { -        g_warning ("Unable to initialize SANE backend: %s", sane_strstatus(status)); -        return FALSE; -    } -    g_debug ("SANE version %d.%d.%d", -             SANE_VERSION_MAJOR(version_code), -             SANE_VERSION_MINOR(version_code), -             SANE_VERSION_BUILD(version_code)); - -    /* Scan for devices on first start */ -    scanner_redetect (scanner); - -    while (handle_requests (scanner)) { -        switch (scanner->priv->state) { -        case STATE_IDLE: -             if (scanner->priv->job_queue) { -                 set_scanning (scanner, TRUE); -                 scanner->priv->state = STATE_OPEN; -             } -             break; -        case STATE_REDETECT: -            do_redetect (scanner); -            break; -        case STATE_OPEN: -            do_open (scanner); -            break; -        case STATE_GET_OPTION: -            do_get_option (scanner); -            break;             -        case STATE_START: -            do_start (scanner); -            break; -        case STATE_GET_PARAMETERS: -            do_get_parameters (scanner); -            break; -        case STATE_READ: -            do_read (scanner); -            break; -        } -    } -     -    return NULL; -} - - -Scanner * -scanner_new () -{ -    return g_object_new (SCANNER_TYPE, NULL); -} - - -void -scanner_start (Scanner *scanner) -{ -    GError *error = NULL; -    scanner->priv->thread = g_thread_create ((GThreadFunc) scan_thread, scanner, TRUE, &error); -    if (error) { -        g_critical ("Unable to create thread: %s", error->message); -        g_error_free (error); -    }     -} - - -void -scanner_redetect (Scanner *scanner) -{ -    ScanRequest *request; - -    if (scanner->priv->redetect) -        return; -    scanner->priv->redetect = TRUE; - -    g_debug ("Requesting redetection of scan devices"); - -    request = g_malloc0 (sizeof (ScanRequest)); -    request->type = REQUEST_REDETECT; -    g_async_queue_push (scanner->priv->scan_queue, request); -} - - -gboolean -scanner_is_scanning (Scanner *scanner) -{ -    return scanner->priv->scanning; -} - - -void -scanner_scan (Scanner *scanner, const char *device, ScanOptions *options) -{ -    ScanRequest *request; -    const gchar *type_string; -   -    switch (options->type) { -    case SCAN_SINGLE: -        type_string = "SCAN_SINGLE"; -        break; -    case SCAN_ADF_FRONT: -        type_string = "SCAN_ADF_FRONT"; -        break; -    case SCAN_ADF_BACK: -        type_string = "SCAN_ADF_BACK"; -        break; -    case SCAN_ADF_BOTH: -        type_string = "SCAN_ADF_BOTH"; -        break; -    default: -        g_assert (FALSE); -        return; -    } - -    g_debug ("scanner_scan (\"%s\", %d, %s)", device ? device : "(null)", options->dpi, type_string); -    request = g_malloc0 (sizeof (ScanRequest)); -    request->type = REQUEST_START_SCAN; -    request->job = g_malloc0 (sizeof (ScanJob)); -    request->job->device = g_strdup (device); -    request->job->dpi = options->dpi; -    request->job->scan_mode = options->scan_mode; -    request->job->depth = options->depth; -    request->job->type = options->type; -    request->job->page_width = options->paper_width; -    request->job->page_height = options->paper_height; -    g_async_queue_push (scanner->priv->scan_queue, request); -} - - -void -scanner_cancel (Scanner *scanner) -{ -    ScanRequest *request; -   -    request = g_malloc0 (sizeof (ScanRequest)); -    request->type = REQUEST_CANCEL; -    g_async_queue_push (scanner->priv->scan_queue, request); -} - - -void scanner_free (Scanner *scanner) -{ -    ScanRequest *request; - -    g_debug ("Stopping scan thread"); - -    request = g_malloc0 (sizeof (ScanRequest)); -    request->type = REQUEST_QUIT; -    g_async_queue_push (scanner->priv->scan_queue, request); - -    if (scanner->priv->thread) -        g_thread_join (scanner->priv->thread); - -    g_async_queue_unref (scanner->priv->scan_queue); -    g_object_unref (scanner); - -    sane_exit (); -    g_debug ("sane_exit ()"); -} - - -static void -scanner_class_init (ScannerClass *klass) -{ -    signals[AUTHORIZE] = -        g_signal_new ("authorize", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, authorize), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__STRING, -                      G_TYPE_NONE, 1, G_TYPE_STRING); -    signals[UPDATE_DEVICES] = -        g_signal_new ("update-devices", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, update_devices), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__POINTER, -                      G_TYPE_NONE, 1, G_TYPE_POINTER); -    signals[EXPECT_PAGE] = -        g_signal_new ("expect-page", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, expect_page), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[GOT_PAGE_INFO] = -        g_signal_new ("got-page-info", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, got_page_info), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__POINTER, -                      G_TYPE_NONE, 1, G_TYPE_POINTER); -    signals[GOT_LINE] = -        g_signal_new ("got-line", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, got_line), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__POINTER, -                      G_TYPE_NONE, 1, G_TYPE_POINTER); -    signals[SCAN_FAILED] = -        g_signal_new ("scan-failed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, scan_failed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__POINTER, -                      G_TYPE_NONE, 1, G_TYPE_POINTER); -    signals[PAGE_DONE] = -        g_signal_new ("page-done", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, page_done), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[DOCUMENT_DONE] = -        g_signal_new ("document-done", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, document_done), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[SCANNING_CHANGED] = -        g_signal_new ("scanning-changed", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (ScannerClass, scanning_changed), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); - -    g_type_class_add_private (klass, sizeof (ScannerPrivate)); - -    scanners = g_hash_table_new (g_direct_hash, g_direct_equal); -} - - -static void -scanner_init (Scanner *scanner) -{ -    scanner->priv = G_TYPE_INSTANCE_GET_PRIVATE (scanner, SCANNER_TYPE, ScannerPrivate); -    scanner->priv->scan_queue = g_async_queue_new (); -    scanner->priv->authorize_queue = g_async_queue_new (); +struct _Notify { +	GTypeInstance parent_instance; +	volatile int ref_count; +	NotifyPrivate * priv; +}; + +struct _NotifyClass { +	GTypeClass parent_class; +	void (*finalize) (Notify *self); +	void (*run) (Notify* self, Scanner* scanner); +}; + +struct _ParamSpecNotify { +	GParamSpec parent_instance; +}; + +struct _NotifyScanningChanged { +	Notify parent_instance; +	NotifyScanningChangedPrivate * priv; +}; + +struct _NotifyScanningChangedClass { +	NotifyClass parent_class; +}; + +struct _NotifyUpdateDevices { +	Notify parent_instance; +	NotifyUpdateDevicesPrivate * priv; +}; + +struct _NotifyUpdateDevicesClass { +	NotifyClass parent_class; +}; + +struct _NotifyUpdateDevicesPrivate { +	GList* devices; +}; + +struct _NotifyRequestAuthorization { +	Notify parent_instance; +	NotifyRequestAuthorizationPrivate * priv; +}; + +struct _NotifyRequestAuthorizationClass { +	NotifyClass parent_class; +}; + +struct _NotifyRequestAuthorizationPrivate { +	gchar* resource; +}; + +struct _NotifyScanFailed { +	Notify parent_instance; +	NotifyScanFailedPrivate * priv; +}; + +struct _NotifyScanFailedClass { +	NotifyClass parent_class; +}; + +struct _NotifyScanFailedPrivate { +	gint error_code; +	gchar* error_string; +}; + +struct _NotifyDocumentDone { +	Notify parent_instance; +	NotifyDocumentDonePrivate * priv; +}; + +struct _NotifyDocumentDoneClass { +	NotifyClass parent_class; +}; + +struct _NotifyExpectPage { +	Notify parent_instance; +	NotifyExpectPagePrivate * priv; +}; + +struct _NotifyExpectPageClass { +	NotifyClass parent_class; +}; + +struct _NotifyGotPageInfo { +	Notify parent_instance; +	NotifyGotPageInfoPrivate * priv; +}; + +struct _NotifyGotPageInfoClass { +	NotifyClass parent_class; +}; + +struct _NotifyGotPageInfoPrivate { +	ScanPageInfo* info; +}; + +struct _NotifyPageDone { +	Notify parent_instance; +	NotifyPageDonePrivate * priv; +}; + +struct _NotifyPageDoneClass { +	NotifyClass parent_class; +}; + +struct _NotifyGotLine { +	Notify parent_instance; +	NotifyGotLinePrivate * priv; +}; + +struct _NotifyGotLineClass { +	NotifyClass parent_class; +}; + +struct _NotifyGotLinePrivate { +	ScanLine* line; +}; + +struct _Scanner { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScannerPrivate * priv; +}; + +struct _ScannerClass { +	GTypeClass parent_class; +	void (*finalize) (Scanner *self); +}; + +struct _ScannerPrivate { +	GThread* thread; +	GAsyncQueue* request_queue; +	GAsyncQueue* notify_queue; +	GAsyncQueue* authorize_queue; +	gchar* default_device; +	ScanState state; +	gboolean need_redetect; +	GList* job_queue; +	SANE_Handle handle; +	gboolean have_handle; +	gchar* current_device; +	SANE_Parameters parameters; +	SANE_Int option_index; +	SANE_Int br_x_option_index; +	SANE_Int br_y_option_index; +	guchar* buffer; +	gint buffer_length1; +	gint _buffer_size_; +	gint n_used; +	gint line_count; +	gint pass_number; +	gint page_number; +	gint notified_page; +	gboolean scanning; +}; + +struct _ParamSpecScanner { +	GParamSpec parent_instance; +}; + + +static gpointer scan_device_parent_class = NULL; +static gpointer scan_page_info_parent_class = NULL; +static gpointer scan_line_parent_class = NULL; +static gpointer scan_options_parent_class = NULL; +static gpointer scan_job_parent_class = NULL; +static gpointer request_parent_class = NULL; +static gpointer request_redetect_parent_class = NULL; +static gpointer request_cancel_parent_class = NULL; +static gpointer request_start_scan_parent_class = NULL; +static gpointer request_quit_parent_class = NULL; +static gpointer credentials_parent_class = NULL; +static gpointer notify_parent_class = NULL; +static gpointer notify_scanning_changed_parent_class = NULL; +static gpointer notify_update_devices_parent_class = NULL; +static gpointer notify_request_authorization_parent_class = NULL; +static gpointer notify_scan_failed_parent_class = NULL; +static gpointer notify_document_done_parent_class = NULL; +static gpointer notify_expect_page_parent_class = NULL; +static gpointer notify_got_page_info_parent_class = NULL; +static gpointer notify_page_done_parent_class = NULL; +static gpointer notify_got_line_parent_class = NULL; +static gpointer scanner_parent_class = NULL; +static Scanner* scanner_scanner_object; +static Scanner* scanner_scanner_object = NULL; + +gpointer scan_device_ref (gpointer instance); +void scan_device_unref (gpointer instance); +GParamSpec* param_spec_scan_device (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_device (GValue* value, gpointer v_object); +void value_take_scan_device (GValue* value, gpointer v_object); +gpointer value_get_scan_device (const GValue* value); +GType scan_device_get_type (void) G_GNUC_CONST; +enum  { +	SCAN_DEVICE_DUMMY_PROPERTY +}; +ScanDevice* scan_device_new (void); +ScanDevice* scan_device_construct (GType object_type); +static void scan_device_finalize (ScanDevice* obj); +gpointer scan_page_info_ref (gpointer instance); +void scan_page_info_unref (gpointer instance); +GParamSpec* param_spec_scan_page_info (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_page_info (GValue* value, gpointer v_object); +void value_take_scan_page_info (GValue* value, gpointer v_object); +gpointer value_get_scan_page_info (const GValue* value); +GType scan_page_info_get_type (void) G_GNUC_CONST; +enum  { +	SCAN_PAGE_INFO_DUMMY_PROPERTY +}; +ScanPageInfo* scan_page_info_new (void); +ScanPageInfo* scan_page_info_construct (GType object_type); +static void scan_page_info_finalize (ScanPageInfo* obj); +gpointer scan_line_ref (gpointer instance); +void scan_line_unref (gpointer instance); +GParamSpec* param_spec_scan_line (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_line (GValue* value, gpointer v_object); +void value_take_scan_line (GValue* value, gpointer v_object); +gpointer value_get_scan_line (const GValue* value); +GType scan_line_get_type (void) G_GNUC_CONST; +enum  { +	SCAN_LINE_DUMMY_PROPERTY +}; +ScanLine* scan_line_new (void); +ScanLine* scan_line_construct (GType object_type); +static void scan_line_finalize (ScanLine* obj); +GType scan_mode_get_type (void) G_GNUC_CONST; +GType scan_type_get_type (void) G_GNUC_CONST; +gpointer scan_options_ref (gpointer instance); +void scan_options_unref (gpointer instance); +GParamSpec* param_spec_scan_options (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_options (GValue* value, gpointer v_object); +void value_take_scan_options (GValue* value, gpointer v_object); +gpointer value_get_scan_options (const GValue* value); +GType scan_options_get_type (void) G_GNUC_CONST; +enum  { +	SCAN_OPTIONS_DUMMY_PROPERTY +}; +ScanOptions* scan_options_new (void); +ScanOptions* scan_options_construct (GType object_type); +static void scan_options_finalize (ScanOptions* obj); +gpointer scan_job_ref (gpointer instance); +void scan_job_unref (gpointer instance); +GParamSpec* param_spec_scan_job (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_job (GValue* value, gpointer v_object); +void value_take_scan_job (GValue* value, gpointer v_object); +gpointer value_get_scan_job (const GValue* value); +GType scan_job_get_type (void) G_GNUC_CONST; +enum  { +	SCAN_JOB_DUMMY_PROPERTY +}; +ScanJob* scan_job_new (void); +ScanJob* scan_job_construct (GType object_type); +static void scan_job_finalize (ScanJob* obj); +gpointer request_ref (gpointer instance); +void request_unref (gpointer instance); +GParamSpec* param_spec_request (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_request (GValue* value, gpointer v_object); +void value_take_request (GValue* value, gpointer v_object); +gpointer value_get_request (const GValue* value); +GType request_get_type (void) G_GNUC_CONST; +enum  { +	REQUEST_DUMMY_PROPERTY +}; +Request* request_new (void); +Request* request_construct (GType object_type); +static void request_finalize (Request* obj); +GType request_redetect_get_type (void) G_GNUC_CONST; +enum  { +	REQUEST_REDETECT_DUMMY_PROPERTY +}; +RequestRedetect* request_redetect_new (void); +RequestRedetect* request_redetect_construct (GType object_type); +GType request_cancel_get_type (void) G_GNUC_CONST; +enum  { +	REQUEST_CANCEL_DUMMY_PROPERTY +}; +RequestCancel* request_cancel_new (void); +RequestCancel* request_cancel_construct (GType object_type); +GType request_start_scan_get_type (void) G_GNUC_CONST; +enum  { +	REQUEST_START_SCAN_DUMMY_PROPERTY +}; +RequestStartScan* request_start_scan_new (void); +RequestStartScan* request_start_scan_construct (GType object_type); +static void request_start_scan_finalize (Request* obj); +GType request_quit_get_type (void) G_GNUC_CONST; +enum  { +	REQUEST_QUIT_DUMMY_PROPERTY +}; +RequestQuit* request_quit_new (void); +RequestQuit* request_quit_construct (GType object_type); +gpointer credentials_ref (gpointer instance); +void credentials_unref (gpointer instance); +GParamSpec* param_spec_credentials (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_credentials (GValue* value, gpointer v_object); +void value_take_credentials (GValue* value, gpointer v_object); +gpointer value_get_credentials (const GValue* value); +GType credentials_get_type (void) G_GNUC_CONST; +enum  { +	CREDENTIALS_DUMMY_PROPERTY +}; +Credentials* credentials_new (void); +Credentials* credentials_construct (GType object_type); +static void credentials_finalize (Credentials* obj); +GType scan_state_get_type (void) G_GNUC_CONST; +gpointer notify_ref (gpointer instance); +void notify_unref (gpointer instance); +GParamSpec* param_spec_notify (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_notify (GValue* value, gpointer v_object); +void value_take_notify (GValue* value, gpointer v_object); +gpointer value_get_notify (const GValue* value); +GType notify_get_type (void) G_GNUC_CONST; +gpointer scanner_ref (gpointer instance); +void scanner_unref (gpointer instance); +GParamSpec* param_spec_scanner (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scanner (GValue* value, gpointer v_object); +void value_take_scanner (GValue* value, gpointer v_object); +gpointer value_get_scanner (const GValue* value); +GType scanner_get_type (void) G_GNUC_CONST; +enum  { +	NOTIFY_DUMMY_PROPERTY +}; +void notify_run (Notify* self, Scanner* scanner); +static void notify_real_run (Notify* self, Scanner* scanner); +Notify* notify_new (void); +Notify* notify_construct (GType object_type); +static void notify_finalize (Notify* obj); +GType notify_scanning_changed_get_type (void) G_GNUC_CONST; +enum  { +	NOTIFY_SCANNING_CHANGED_DUMMY_PROPERTY +}; +static void notify_scanning_changed_real_run (Notify* base, Scanner* scanner); +NotifyScanningChanged* notify_scanning_changed_new (void); +NotifyScanningChanged* notify_scanning_changed_construct (GType object_type); +GType notify_update_devices_get_type (void) G_GNUC_CONST; +#define NOTIFY_UPDATE_DEVICES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_NOTIFY_UPDATE_DEVICES, NotifyUpdateDevicesPrivate)) +enum  { +	NOTIFY_UPDATE_DEVICES_DUMMY_PROPERTY +}; +static void _scan_device_unref0_ (gpointer var); +static void _g_list_free__scan_device_unref0_ (GList* self); +NotifyUpdateDevices* notify_update_devices_new (GList* devices); +NotifyUpdateDevices* notify_update_devices_construct (GType object_type, GList* devices); +static void notify_update_devices_real_run (Notify* base, Scanner* scanner); +static void notify_update_devices_finalize (Notify* obj); +GType notify_request_authorization_get_type (void) G_GNUC_CONST; +#define NOTIFY_REQUEST_AUTHORIZATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_NOTIFY_REQUEST_AUTHORIZATION, NotifyRequestAuthorizationPrivate)) +enum  { +	NOTIFY_REQUEST_AUTHORIZATION_DUMMY_PROPERTY +}; +NotifyRequestAuthorization* notify_request_authorization_new (const gchar* resource); +NotifyRequestAuthorization* notify_request_authorization_construct (GType object_type, const gchar* resource); +static void notify_request_authorization_real_run (Notify* base, Scanner* scanner); +static void notify_request_authorization_finalize (Notify* obj); +GType notify_scan_failed_get_type (void) G_GNUC_CONST; +#define NOTIFY_SCAN_FAILED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_NOTIFY_SCAN_FAILED, NotifyScanFailedPrivate)) +enum  { +	NOTIFY_SCAN_FAILED_DUMMY_PROPERTY +}; +NotifyScanFailed* notify_scan_failed_new (gint error_code, const gchar* error_string); +NotifyScanFailed* notify_scan_failed_construct (GType object_type, gint error_code, const gchar* error_string); +static void notify_scan_failed_real_run (Notify* base, Scanner* scanner); +static void notify_scan_failed_finalize (Notify* obj); +GType notify_document_done_get_type (void) G_GNUC_CONST; +enum  { +	NOTIFY_DOCUMENT_DONE_DUMMY_PROPERTY +}; +static void notify_document_done_real_run (Notify* base, Scanner* scanner); +NotifyDocumentDone* notify_document_done_new (void); +NotifyDocumentDone* notify_document_done_construct (GType object_type); +GType notify_expect_page_get_type (void) G_GNUC_CONST; +enum  { +	NOTIFY_EXPECT_PAGE_DUMMY_PROPERTY +}; +static void notify_expect_page_real_run (Notify* base, Scanner* scanner); +NotifyExpectPage* notify_expect_page_new (void); +NotifyExpectPage* notify_expect_page_construct (GType object_type); +GType notify_got_page_info_get_type (void) G_GNUC_CONST; +#define NOTIFY_GOT_PAGE_INFO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_NOTIFY_GOT_PAGE_INFO, NotifyGotPageInfoPrivate)) +enum  { +	NOTIFY_GOT_PAGE_INFO_DUMMY_PROPERTY +}; +NotifyGotPageInfo* notify_got_page_info_new (ScanPageInfo* info); +NotifyGotPageInfo* notify_got_page_info_construct (GType object_type, ScanPageInfo* info); +static void notify_got_page_info_real_run (Notify* base, Scanner* scanner); +static void notify_got_page_info_finalize (Notify* obj); +GType notify_page_done_get_type (void) G_GNUC_CONST; +enum  { +	NOTIFY_PAGE_DONE_DUMMY_PROPERTY +}; +static void notify_page_done_real_run (Notify* base, Scanner* scanner); +NotifyPageDone* notify_page_done_new (void); +NotifyPageDone* notify_page_done_construct (GType object_type); +GType notify_got_line_get_type (void) G_GNUC_CONST; +#define NOTIFY_GOT_LINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_NOTIFY_GOT_LINE, NotifyGotLinePrivate)) +enum  { +	NOTIFY_GOT_LINE_DUMMY_PROPERTY +}; +NotifyGotLine* notify_got_line_new (ScanLine* line); +NotifyGotLine* notify_got_line_construct (GType object_type, ScanLine* line); +static void notify_got_line_real_run (Notify* base, Scanner* scanner); +static void notify_got_line_finalize (Notify* obj); +#define SCANNER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_SCANNER, ScannerPrivate)) +enum  { +	SCANNER_DUMMY_PROPERTY +}; +static void _scan_job_unref0_ (gpointer var); +static void _g_list_free__scan_job_unref0_ (GList* self); +static Scanner* scanner_new (void); +static Scanner* scanner_construct (GType object_type); +Scanner* scanner_get_instance (void); +static gboolean scanner_notify_idle_cb (Scanner* self); +static void scanner_notify (Scanner* self, Notify* notification); +static gboolean _scanner_notify_idle_cb_gsource_func (gpointer self); +static void scanner_set_scanning (Scanner* self, gboolean is_scanning); +static gint scanner_get_device_weight (const gchar* device); +static gint scanner_compare_devices (ScanDevice* device1, ScanDevice* device2); +static void scanner_do_redetect (Scanner* self); +static gint _scanner_compare_devices_gcompare_func (gconstpointer a, gconstpointer b); +static gboolean scanner_set_default_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index); +static void scanner_set_bool_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gboolean value, gboolean* _result_); +static void scanner_set_int_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gint value, gint* _result_); +static void scanner_set_fixed_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gdouble value, gdouble* _result_); +static gboolean scanner_set_string_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, const gchar* value, gchar** _result_); +static gboolean scanner_set_constrained_string_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gchar** values, int values_length1, gchar** _result_); +static void scanner_log_option (Scanner* self, SANE_Int index, const SANE_Option_Descriptor* option); +static void scanner_authorization_cb (const gchar* resource, gchar* username, int username_length1, gchar* password, int password_length1); +void scanner_authorize (Scanner* self, const gchar* username, const gchar* password); +static void scanner_close_device (Scanner* self); +static void scanner_fail_scan (Scanner* self, gint error_code, const gchar* error_string); +static gboolean scanner_handle_requests (Scanner* self); +static void scanner_do_open (Scanner* self); +static void scanner_do_get_option (Scanner* self); +static void scanner_do_complete_document (Scanner* self); +static void scanner_do_start (Scanner* self); +static void scanner_do_get_parameters (Scanner* self); +static void scanner_do_complete_page (Scanner* self); +static void scanner_do_read (Scanner* self); +static void* scanner_scan_thread (Scanner* self); +static void _scanner_authorization_cb_sane_authcallback (const gchar* resource, gchar* username, gchar* password); +void scanner_redetect (Scanner* self); +void scanner_start (Scanner* self); +static gpointer _scanner_scan_thread_gthread_func (gpointer self); +gboolean scanner_is_scanning (Scanner* self); +static gchar* scanner_get_scan_mode_string (Scanner* self, ScanMode mode); +static gchar* scanner_get_scan_type_string (Scanner* self, ScanType type); +void scanner_scan (Scanner* self, const gchar* device, ScanOptions* options); +void scanner_cancel (Scanner* self); +void scanner_free (Scanner* self); +static void g_cclosure_user_marshal_VOID__SCAN_PAGE_INFO (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); +static void g_cclosure_user_marshal_VOID__SCAN_LINE (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); +static void g_cclosure_user_marshal_VOID__INT_STRING (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); +static void scanner_finalize (Scanner* obj); +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func); +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func); + + +ScanDevice* scan_device_construct (GType object_type) { +	ScanDevice* self = NULL; +	self = (ScanDevice*) g_type_create_instance (object_type); +	return self; +} + + +ScanDevice* scan_device_new (void) { +	return scan_device_construct (TYPE_SCAN_DEVICE); +} + + +static void value_scan_device_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_scan_device_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		scan_device_unref (value->data[0].v_pointer); +	} +} + + +static void value_scan_device_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = scan_device_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_scan_device_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_scan_device_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		ScanDevice* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = scan_device_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_scan_device_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	ScanDevice** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = scan_device_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_scan_device (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecScanDevice* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SCAN_DEVICE), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_scan_device (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_DEVICE), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_scan_device (GValue* value, gpointer v_object) { +	ScanDevice* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_DEVICE)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_DEVICE)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		scan_device_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_device_unref (old); +	} +} + + +void value_take_scan_device (GValue* value, gpointer v_object) { +	ScanDevice* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_DEVICE)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_DEVICE)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_device_unref (old); +	} +} + + +static void scan_device_class_init (ScanDeviceClass * klass) { +	scan_device_parent_class = g_type_class_peek_parent (klass); +	SCAN_DEVICE_CLASS (klass)->finalize = scan_device_finalize; +} + + +static void scan_device_instance_init (ScanDevice * self) { +	self->ref_count = 1; +} + + +static void scan_device_finalize (ScanDevice* obj) { +	ScanDevice * self; +	self = SCAN_DEVICE (obj); +	_g_free0 (self->name); +	_g_free0 (self->label); +} + + +GType scan_device_get_type (void) { +	static volatile gsize scan_device_type_id__volatile = 0; +	if (g_once_init_enter (&scan_device_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_scan_device_init, value_scan_device_free_value, value_scan_device_copy_value, value_scan_device_peek_pointer, "p", value_scan_device_collect_value, "p", value_scan_device_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ScanDeviceClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) scan_device_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ScanDevice), 0, (GInstanceInitFunc) scan_device_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType scan_device_type_id; +		scan_device_type_id = g_type_register_fundamental (g_type_fundamental_next (), "ScanDevice", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&scan_device_type_id__volatile, scan_device_type_id); +	} +	return scan_device_type_id__volatile; +} + + +gpointer scan_device_ref (gpointer instance) { +	ScanDevice* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void scan_device_unref (gpointer instance) { +	ScanDevice* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SCAN_DEVICE_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +ScanPageInfo* scan_page_info_construct (GType object_type) { +	ScanPageInfo* self = NULL; +	self = (ScanPageInfo*) g_type_create_instance (object_type); +	return self; +} + + +ScanPageInfo* scan_page_info_new (void) { +	return scan_page_info_construct (TYPE_SCAN_PAGE_INFO); +} + + +static void value_scan_page_info_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_scan_page_info_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		scan_page_info_unref (value->data[0].v_pointer); +	} +} + + +static void value_scan_page_info_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = scan_page_info_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_scan_page_info_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_scan_page_info_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		ScanPageInfo* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = scan_page_info_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_scan_page_info_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	ScanPageInfo** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = scan_page_info_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_scan_page_info (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecScanPageInfo* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SCAN_PAGE_INFO), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_scan_page_info (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_PAGE_INFO), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_scan_page_info (GValue* value, gpointer v_object) { +	ScanPageInfo* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_PAGE_INFO)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_PAGE_INFO)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		scan_page_info_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_page_info_unref (old); +	} +} + + +void value_take_scan_page_info (GValue* value, gpointer v_object) { +	ScanPageInfo* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_PAGE_INFO)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_PAGE_INFO)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_page_info_unref (old); +	} +} + + +static void scan_page_info_class_init (ScanPageInfoClass * klass) { +	scan_page_info_parent_class = g_type_class_peek_parent (klass); +	SCAN_PAGE_INFO_CLASS (klass)->finalize = scan_page_info_finalize; +} + + +static void scan_page_info_instance_init (ScanPageInfo * self) { +	self->ref_count = 1; +} + + +static void scan_page_info_finalize (ScanPageInfo* obj) { +	ScanPageInfo * self; +	self = SCAN_PAGE_INFO (obj); +	_g_free0 (self->device); +} + + +GType scan_page_info_get_type (void) { +	static volatile gsize scan_page_info_type_id__volatile = 0; +	if (g_once_init_enter (&scan_page_info_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_scan_page_info_init, value_scan_page_info_free_value, value_scan_page_info_copy_value, value_scan_page_info_peek_pointer, "p", value_scan_page_info_collect_value, "p", value_scan_page_info_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ScanPageInfoClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) scan_page_info_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ScanPageInfo), 0, (GInstanceInitFunc) scan_page_info_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType scan_page_info_type_id; +		scan_page_info_type_id = g_type_register_fundamental (g_type_fundamental_next (), "ScanPageInfo", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&scan_page_info_type_id__volatile, scan_page_info_type_id); +	} +	return scan_page_info_type_id__volatile; +} + + +gpointer scan_page_info_ref (gpointer instance) { +	ScanPageInfo* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void scan_page_info_unref (gpointer instance) { +	ScanPageInfo* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SCAN_PAGE_INFO_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +ScanLine* scan_line_construct (GType object_type) { +	ScanLine* self = NULL; +	self = (ScanLine*) g_type_create_instance (object_type); +	return self; +} + + +ScanLine* scan_line_new (void) { +	return scan_line_construct (TYPE_SCAN_LINE); +} + + +static void value_scan_line_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_scan_line_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		scan_line_unref (value->data[0].v_pointer); +	} +} + + +static void value_scan_line_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = scan_line_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_scan_line_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_scan_line_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		ScanLine* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = scan_line_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL;  } + + +static gchar* value_scan_line_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	ScanLine** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = scan_line_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_scan_line (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecScanLine* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SCAN_LINE), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_scan_line (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_LINE), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_scan_line (GValue* value, gpointer v_object) { +	ScanLine* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_LINE)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_LINE)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		scan_line_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_line_unref (old); +	} +} + + +void value_take_scan_line (GValue* value, gpointer v_object) { +	ScanLine* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_LINE)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_LINE)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_line_unref (old); +	} +} + + +static void scan_line_class_init (ScanLineClass * klass) { +	scan_line_parent_class = g_type_class_peek_parent (klass); +	SCAN_LINE_CLASS (klass)->finalize = scan_line_finalize; +} + + +static void scan_line_instance_init (ScanLine * self) { +	self->ref_count = 1; +} + + +static void scan_line_finalize (ScanLine* obj) { +	ScanLine * self; +	self = SCAN_LINE (obj); +	self->data = (g_free (self->data), NULL); +} + + +GType scan_line_get_type (void) { +	static volatile gsize scan_line_type_id__volatile = 0; +	if (g_once_init_enter (&scan_line_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_scan_line_init, value_scan_line_free_value, value_scan_line_copy_value, value_scan_line_peek_pointer, "p", value_scan_line_collect_value, "p", value_scan_line_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ScanLineClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) scan_line_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ScanLine), 0, (GInstanceInitFunc) scan_line_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType scan_line_type_id; +		scan_line_type_id = g_type_register_fundamental (g_type_fundamental_next (), "ScanLine", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&scan_line_type_id__volatile, scan_line_type_id); +	} +	return scan_line_type_id__volatile; +} + + +gpointer scan_line_ref (gpointer instance) { +	ScanLine* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void scan_line_unref (gpointer instance) { +	ScanLine* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SCAN_LINE_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +GType scan_mode_get_type (void) { +	static volatile gsize scan_mode_type_id__volatile = 0; +	if (g_once_init_enter (&scan_mode_type_id__volatile)) { +		static const GEnumValue values[] = {{SCAN_MODE_DEFAULT, "SCAN_MODE_DEFAULT", "default"}, {SCAN_MODE_COLOR, "SCAN_MODE_COLOR", "color"}, {SCAN_MODE_GRAY, "SCAN_MODE_GRAY", "gray"}, {SCAN_MODE_LINEART, "SCAN_MODE_LINEART", "lineart"}, {0, NULL, NULL}}; +		GType scan_mode_type_id; +		scan_mode_type_id = g_enum_register_static ("ScanMode", values); +		g_once_init_leave (&scan_mode_type_id__volatile, scan_mode_type_id); +	} +	return scan_mode_type_id__volatile; +} + + +GType scan_type_get_type (void) { +	static volatile gsize scan_type_type_id__volatile = 0; +	if (g_once_init_enter (&scan_type_type_id__volatile)) { +		static const GEnumValue values[] = {{SCAN_TYPE_SINGLE, "SCAN_TYPE_SINGLE", "single"}, {SCAN_TYPE_ADF_FRONT, "SCAN_TYPE_ADF_FRONT", "adf-front"}, {SCAN_TYPE_ADF_BACK, "SCAN_TYPE_ADF_BACK", "adf-back"}, {SCAN_TYPE_ADF_BOTH, "SCAN_TYPE_ADF_BOTH", "adf-both"}, {0, NULL, NULL}}; +		GType scan_type_type_id; +		scan_type_type_id = g_enum_register_static ("ScanType", values); +		g_once_init_leave (&scan_type_type_id__volatile, scan_type_type_id); +	} +	return scan_type_type_id__volatile; +} + + +ScanOptions* scan_options_construct (GType object_type) { +	ScanOptions* self = NULL; +	self = (ScanOptions*) g_type_create_instance (object_type); +	return self; +} + + +ScanOptions* scan_options_new (void) { +	return scan_options_construct (TYPE_SCAN_OPTIONS); +} + + +static void value_scan_options_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_scan_options_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		scan_options_unref (value->data[0].v_pointer); +	} +} + + +static void value_scan_options_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = scan_options_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_scan_options_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_scan_options_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		ScanOptions* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = scan_options_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_scan_options_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	ScanOptions** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = scan_options_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_scan_options (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecScanOptions* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SCAN_OPTIONS), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_scan_options (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_OPTIONS), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_scan_options (GValue* value, gpointer v_object) { +	ScanOptions* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_OPTIONS)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_OPTIONS)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		scan_options_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_options_unref (old); +	} +} + + +void value_take_scan_options (GValue* value, gpointer v_object) { +	ScanOptions* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_OPTIONS)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_OPTIONS)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_options_unref (old); +	} +} + + +static void scan_options_class_init (ScanOptionsClass * klass) { +	scan_options_parent_class = g_type_class_peek_parent (klass); +	SCAN_OPTIONS_CLASS (klass)->finalize = scan_options_finalize; +} + + +static void scan_options_instance_init (ScanOptions * self) { +	self->ref_count = 1; +} + + +static void scan_options_finalize (ScanOptions* obj) { +	ScanOptions * self; +	self = SCAN_OPTIONS (obj); +} + + +GType scan_options_get_type (void) { +	static volatile gsize scan_options_type_id__volatile = 0; +	if (g_once_init_enter (&scan_options_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_scan_options_init, value_scan_options_free_value, value_scan_options_copy_value, value_scan_options_peek_pointer, "p", value_scan_options_collect_value, "p", value_scan_options_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ScanOptionsClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) scan_options_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ScanOptions), 0, (GInstanceInitFunc) scan_options_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType scan_options_type_id; +		scan_options_type_id = g_type_register_fundamental (g_type_fundamental_next (), "ScanOptions", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&scan_options_type_id__volatile, scan_options_type_id); +	} +	return scan_options_type_id__volatile; +} + + +gpointer scan_options_ref (gpointer instance) { +	ScanOptions* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void scan_options_unref (gpointer instance) { +	ScanOptions* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SCAN_OPTIONS_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +ScanJob* scan_job_construct (GType object_type) { +	ScanJob* self = NULL; +	self = (ScanJob*) g_type_create_instance (object_type); +	return self; +} + + +ScanJob* scan_job_new (void) { +	return scan_job_construct (TYPE_SCAN_JOB); +} + + +static void value_scan_job_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_scan_job_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		scan_job_unref (value->data[0].v_pointer); +	} +} + + +static void value_scan_job_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = scan_job_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_scan_job_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_scan_job_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		ScanJob* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = scan_job_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_scan_job_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	ScanJob** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = scan_job_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_scan_job (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecScanJob* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SCAN_JOB), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_scan_job (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_JOB), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_scan_job (GValue* value, gpointer v_object) { +	ScanJob* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_JOB)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_JOB)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		scan_job_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_job_unref (old); +	} +} + + +void value_take_scan_job (GValue* value, gpointer v_object) { +	ScanJob* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCAN_JOB)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCAN_JOB)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scan_job_unref (old); +	} +} + + +static void scan_job_class_init (ScanJobClass * klass) { +	scan_job_parent_class = g_type_class_peek_parent (klass); +	SCAN_JOB_CLASS (klass)->finalize = scan_job_finalize; +} + + +static void scan_job_instance_init (ScanJob * self) { +	self->ref_count = 1; +} + + +static void scan_job_finalize (ScanJob* obj) { +	ScanJob * self; +	self = SCAN_JOB (obj); +	_g_free0 (self->device); +} + + +GType scan_job_get_type (void) { +	static volatile gsize scan_job_type_id__volatile = 0; +	if (g_once_init_enter (&scan_job_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_scan_job_init, value_scan_job_free_value, value_scan_job_copy_value, value_scan_job_peek_pointer, "p", value_scan_job_collect_value, "p", value_scan_job_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ScanJobClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) scan_job_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (ScanJob), 0, (GInstanceInitFunc) scan_job_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType scan_job_type_id; +		scan_job_type_id = g_type_register_fundamental (g_type_fundamental_next (), "ScanJob", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&scan_job_type_id__volatile, scan_job_type_id); +	} +	return scan_job_type_id__volatile; +} + + +gpointer scan_job_ref (gpointer instance) { +	ScanJob* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void scan_job_unref (gpointer instance) { +	ScanJob* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SCAN_JOB_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +Request* request_construct (GType object_type) { +	Request* self = NULL; +	self = (Request*) g_type_create_instance (object_type); +	return self; +} + + +Request* request_new (void) { +	return request_construct (TYPE_REQUEST); +} + + +static void value_request_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_request_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		request_unref (value->data[0].v_pointer); +	} +} + + +static void value_request_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = request_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_request_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_request_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Request* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = request_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_request_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Request** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = request_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_request (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecRequest* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_REQUEST), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_request (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_REQUEST), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_request (GValue* value, gpointer v_object) { +	Request* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_REQUEST)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_REQUEST)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		request_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		request_unref (old); +	} +} + + +void value_take_request (GValue* value, gpointer v_object) { +	Request* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_REQUEST)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_REQUEST)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		request_unref (old); +	} +} + + +static void request_class_init (RequestClass * klass) { +	request_parent_class = g_type_class_peek_parent (klass); +	REQUEST_CLASS (klass)->finalize = request_finalize; +} + + +static void request_instance_init (Request * self) { +	self->ref_count = 1; +} + + +static void request_finalize (Request* obj) { +	Request * self; +	self = REQUEST (obj); +} + + +GType request_get_type (void) { +	static volatile gsize request_type_id__volatile = 0; +	if (g_once_init_enter (&request_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_request_init, value_request_free_value, value_request_copy_value, value_request_peek_pointer, "p", value_request_collect_value, "p", value_request_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (RequestClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) request_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Request), 0, (GInstanceInitFunc) request_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType request_type_id; +		request_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Request", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&request_type_id__volatile, request_type_id); +	} +	return request_type_id__volatile; +} + + +gpointer request_ref (gpointer instance) { +	Request* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void request_unref (gpointer instance) { +	Request* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		REQUEST_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +RequestRedetect* request_redetect_construct (GType object_type) { +	RequestRedetect* self = NULL; +	self = (RequestRedetect*) request_construct (object_type); +	return self; +} + + +RequestRedetect* request_redetect_new (void) { +	return request_redetect_construct (TYPE_REQUEST_REDETECT); +} + + +static void request_redetect_class_init (RequestRedetectClass * klass) { +	request_redetect_parent_class = g_type_class_peek_parent (klass); +} + + +static void request_redetect_instance_init (RequestRedetect * self) { +} + + +GType request_redetect_get_type (void) { +	static volatile gsize request_redetect_type_id__volatile = 0; +	if (g_once_init_enter (&request_redetect_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (RequestRedetectClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) request_redetect_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RequestRedetect), 0, (GInstanceInitFunc) request_redetect_instance_init, NULL }; +		GType request_redetect_type_id; +		request_redetect_type_id = g_type_register_static (TYPE_REQUEST, "RequestRedetect", &g_define_type_info, 0); +		g_once_init_leave (&request_redetect_type_id__volatile, request_redetect_type_id); +	} +	return request_redetect_type_id__volatile; +} + + +RequestCancel* request_cancel_construct (GType object_type) { +	RequestCancel* self = NULL; +	self = (RequestCancel*) request_construct (object_type); +	return self; +} + + +RequestCancel* request_cancel_new (void) { +	return request_cancel_construct (TYPE_REQUEST_CANCEL); +} + + +static void request_cancel_class_init (RequestCancelClass * klass) { +	request_cancel_parent_class = g_type_class_peek_parent (klass); +} + + +static void request_cancel_instance_init (RequestCancel * self) { +} + + +GType request_cancel_get_type (void) { +	static volatile gsize request_cancel_type_id__volatile = 0; +	if (g_once_init_enter (&request_cancel_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (RequestCancelClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) request_cancel_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RequestCancel), 0, (GInstanceInitFunc) request_cancel_instance_init, NULL }; +		GType request_cancel_type_id; +		request_cancel_type_id = g_type_register_static (TYPE_REQUEST, "RequestCancel", &g_define_type_info, 0); +		g_once_init_leave (&request_cancel_type_id__volatile, request_cancel_type_id); +	} +	return request_cancel_type_id__volatile; +} + + +RequestStartScan* request_start_scan_construct (GType object_type) { +	RequestStartScan* self = NULL; +	self = (RequestStartScan*) request_construct (object_type); +	return self; +} + + +RequestStartScan* request_start_scan_new (void) { +	return request_start_scan_construct (TYPE_REQUEST_START_SCAN); +} + + +static void request_start_scan_class_init (RequestStartScanClass * klass) { +	request_start_scan_parent_class = g_type_class_peek_parent (klass); +	REQUEST_CLASS (klass)->finalize = request_start_scan_finalize; +} + + +static void request_start_scan_instance_init (RequestStartScan * self) { +} + + +static void request_start_scan_finalize (Request* obj) { +	RequestStartScan * self; +	self = REQUEST_START_SCAN (obj); +	_scan_job_unref0 (self->job); +	REQUEST_CLASS (request_start_scan_parent_class)->finalize (obj); +} + + +GType request_start_scan_get_type (void) { +	static volatile gsize request_start_scan_type_id__volatile = 0; +	if (g_once_init_enter (&request_start_scan_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (RequestStartScanClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) request_start_scan_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RequestStartScan), 0, (GInstanceInitFunc) request_start_scan_instance_init, NULL }; +		GType request_start_scan_type_id; +		request_start_scan_type_id = g_type_register_static (TYPE_REQUEST, "RequestStartScan", &g_define_type_info, 0); +		g_once_init_leave (&request_start_scan_type_id__volatile, request_start_scan_type_id); +	} +	return request_start_scan_type_id__volatile; +} + + +RequestQuit* request_quit_construct (GType object_type) { +	RequestQuit* self = NULL; +	self = (RequestQuit*) request_construct (object_type); +	return self; +} + + +RequestQuit* request_quit_new (void) { +	return request_quit_construct (TYPE_REQUEST_QUIT); +} + + +static void request_quit_class_init (RequestQuitClass * klass) { +	request_quit_parent_class = g_type_class_peek_parent (klass); +} + + +static void request_quit_instance_init (RequestQuit * self) { +} + + +GType request_quit_get_type (void) { +	static volatile gsize request_quit_type_id__volatile = 0; +	if (g_once_init_enter (&request_quit_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (RequestQuitClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) request_quit_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RequestQuit), 0, (GInstanceInitFunc) request_quit_instance_init, NULL }; +		GType request_quit_type_id; +		request_quit_type_id = g_type_register_static (TYPE_REQUEST, "RequestQuit", &g_define_type_info, 0); +		g_once_init_leave (&request_quit_type_id__volatile, request_quit_type_id); +	} +	return request_quit_type_id__volatile; +} + + +Credentials* credentials_construct (GType object_type) { +	Credentials* self = NULL; +	self = (Credentials*) g_type_create_instance (object_type); +	return self; +} + + +Credentials* credentials_new (void) { +	return credentials_construct (TYPE_CREDENTIALS); +} + + +static void value_credentials_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_credentials_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		credentials_unref (value->data[0].v_pointer); +	} +} + + +static void value_credentials_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = credentials_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_credentials_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_credentials_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Credentials* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = credentials_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_credentials_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Credentials** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = credentials_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_credentials (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecCredentials* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_CREDENTIALS), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_credentials (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_CREDENTIALS), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_credentials (GValue* value, gpointer v_object) { +	Credentials* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_CREDENTIALS)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_CREDENTIALS)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		credentials_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		credentials_unref (old); +	} +} + + +void value_take_credentials (GValue* value, gpointer v_object) { +	Credentials* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_CREDENTIALS)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_CREDENTIALS)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		credentials_unref (old); +	} +} + + +static void credentials_class_init (CredentialsClass * klass) { +	credentials_parent_class = g_type_class_peek_parent (klass); +	CREDENTIALS_CLASS (klass)->finalize = credentials_finalize; +} + + +static void credentials_instance_init (Credentials * self) { +	self->ref_count = 1; +} + + +static void credentials_finalize (Credentials* obj) { +	Credentials * self; +	self = CREDENTIALS (obj); +	_g_free0 (self->username); +	_g_free0 (self->password); +} + + +GType credentials_get_type (void) { +	static volatile gsize credentials_type_id__volatile = 0; +	if (g_once_init_enter (&credentials_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_credentials_init, value_credentials_free_value, value_credentials_copy_value, value_credentials_peek_pointer, "p", value_credentials_collect_value, "p", value_credentials_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (CredentialsClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) credentials_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Credentials), 0, (GInstanceInitFunc) credentials_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType credentials_type_id; +		credentials_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Credentials", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&credentials_type_id__volatile, credentials_type_id); +	} +	return credentials_type_id__volatile; +} + + +gpointer credentials_ref (gpointer instance) { +	Credentials* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void credentials_unref (gpointer instance) { +	Credentials* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		CREDENTIALS_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +GType scan_state_get_type (void) { +	static volatile gsize scan_state_type_id__volatile = 0; +	if (g_once_init_enter (&scan_state_type_id__volatile)) { +		static const GEnumValue values[] = {{SCAN_STATE_IDLE, "SCAN_STATE_IDLE", "idle"}, {SCAN_STATE_REDETECT, "SCAN_STATE_REDETECT", "redetect"}, {SCAN_STATE_OPEN, "SCAN_STATE_OPEN", "open"}, {SCAN_STATE_GET_OPTION, "SCAN_STATE_GET_OPTION", "get-option"}, {SCAN_STATE_START, "SCAN_STATE_START", "start"}, {SCAN_STATE_GET_PARAMETERS, "SCAN_STATE_GET_PARAMETERS", "get-parameters"}, {SCAN_STATE_READ, "SCAN_STATE_READ", "read"}, {0, NULL, NULL}}; +		GType scan_state_type_id; +		scan_state_type_id = g_enum_register_static ("ScanState", values); +		g_once_init_leave (&scan_state_type_id__volatile, scan_state_type_id); +	} +	return scan_state_type_id__volatile; +} + + +static void notify_real_run (Notify* self, Scanner* scanner) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +} + + +void notify_run (Notify* self, Scanner* scanner) { +	NOTIFY_GET_CLASS (self)->run (self, scanner); +} + + +Notify* notify_construct (GType object_type) { +	Notify* self = NULL; +	self = (Notify*) g_type_create_instance (object_type); +	return self; +} + + +Notify* notify_new (void) { +	return notify_construct (TYPE_NOTIFY); +} + + +static void value_notify_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_notify_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		notify_unref (value->data[0].v_pointer); +	} +} + + +static void value_notify_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = notify_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_notify_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_notify_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Notify* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = notify_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_notify_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Notify** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = notify_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_notify (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecNotify* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_NOTIFY), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_notify (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_NOTIFY), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_notify (GValue* value, gpointer v_object) { +	Notify* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_NOTIFY)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_NOTIFY)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		notify_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		notify_unref (old); +	} +} + + +void value_take_notify (GValue* value, gpointer v_object) { +	Notify* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_NOTIFY)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_NOTIFY)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		notify_unref (old); +	} +} + + +static void notify_class_init (NotifyClass * klass) { +	notify_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->finalize = notify_finalize; +	NOTIFY_CLASS (klass)->run = notify_real_run; +} + + +static void notify_instance_init (Notify * self) { +	self->ref_count = 1; +} + + +static void notify_finalize (Notify* obj) { +	Notify * self; +	self = NOTIFY (obj); +} + + +GType notify_get_type (void) { +	static volatile gsize notify_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_notify_init, value_notify_free_value, value_notify_copy_value, value_notify_peek_pointer, "p", value_notify_collect_value, "p", value_notify_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (NotifyClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Notify), 0, (GInstanceInitFunc) notify_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType notify_type_id; +		notify_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Notify", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (¬ify_type_id__volatile, notify_type_id); +	} +	return notify_type_id__volatile; +} + + +gpointer notify_ref (gpointer instance) { +	Notify* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void notify_unref (gpointer instance) { +	Notify* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		NOTIFY_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +static void notify_scanning_changed_real_run (Notify* base, Scanner* scanner) { +	NotifyScanningChanged * self; +	self = (NotifyScanningChanged*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "scanning-changed"); +} + + +NotifyScanningChanged* notify_scanning_changed_construct (GType object_type) { +	NotifyScanningChanged* self = NULL; +	self = (NotifyScanningChanged*) notify_construct (object_type); +	return self; +} + + +NotifyScanningChanged* notify_scanning_changed_new (void) { +	return notify_scanning_changed_construct (TYPE_NOTIFY_SCANNING_CHANGED); +} + + +static void notify_scanning_changed_class_init (NotifyScanningChangedClass * klass) { +	notify_scanning_changed_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->run = notify_scanning_changed_real_run; +} + + +static void notify_scanning_changed_instance_init (NotifyScanningChanged * self) { +} + + +GType notify_scanning_changed_get_type (void) { +	static volatile gsize notify_scanning_changed_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_scanning_changed_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyScanningChangedClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_scanning_changed_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyScanningChanged), 0, (GInstanceInitFunc) notify_scanning_changed_instance_init, NULL }; +		GType notify_scanning_changed_type_id; +		notify_scanning_changed_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyScanningChanged", &g_define_type_info, 0); +		g_once_init_leave (¬ify_scanning_changed_type_id__volatile, notify_scanning_changed_type_id); +	} +	return notify_scanning_changed_type_id__volatile; +} + + +static void _scan_device_unref0_ (gpointer var) { +	(var == NULL) ? NULL : (var = (scan_device_unref (var), NULL)); +} + + +static void _g_list_free__scan_device_unref0_ (GList* self) { +	g_list_foreach (self, (GFunc) _scan_device_unref0_, NULL); +	g_list_free (self); +} + + +NotifyUpdateDevices* notify_update_devices_construct (GType object_type, GList* devices) { +	NotifyUpdateDevices* self = NULL; +	GList* _tmp0_; +	self = (NotifyUpdateDevices*) notify_construct (object_type); +	_tmp0_ = devices; +	devices = NULL; +	__g_list_free__scan_device_unref0_0 (self->priv->devices); +	self->priv->devices = _tmp0_; +	__g_list_free__scan_device_unref0_0 (devices); +	return self; +} + + +NotifyUpdateDevices* notify_update_devices_new (GList* devices) { +	return notify_update_devices_construct (TYPE_NOTIFY_UPDATE_DEVICES, devices); +} + + +static void notify_update_devices_real_run (Notify* base, Scanner* scanner) { +	NotifyUpdateDevices * self; +	self = (NotifyUpdateDevices*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "update-devices", self->priv->devices); +} + + +static void notify_update_devices_class_init (NotifyUpdateDevicesClass * klass) { +	notify_update_devices_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->finalize = notify_update_devices_finalize; +	g_type_class_add_private (klass, sizeof (NotifyUpdateDevicesPrivate)); +	NOTIFY_CLASS (klass)->run = notify_update_devices_real_run; +} + + +static void notify_update_devices_instance_init (NotifyUpdateDevices * self) { +	self->priv = NOTIFY_UPDATE_DEVICES_GET_PRIVATE (self); +} + + +static void notify_update_devices_finalize (Notify* obj) { +	NotifyUpdateDevices * self; +	self = NOTIFY_UPDATE_DEVICES (obj); +	__g_list_free__scan_device_unref0_0 (self->priv->devices); +	NOTIFY_CLASS (notify_update_devices_parent_class)->finalize (obj); +} + + +GType notify_update_devices_get_type (void) { +	static volatile gsize notify_update_devices_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_update_devices_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyUpdateDevicesClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_update_devices_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyUpdateDevices), 0, (GInstanceInitFunc) notify_update_devices_instance_init, NULL }; +		GType notify_update_devices_type_id; +		notify_update_devices_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyUpdateDevices", &g_define_type_info, 0); +		g_once_init_leave (¬ify_update_devices_type_id__volatile, notify_update_devices_type_id); +	} +	return notify_update_devices_type_id__volatile; +} + + +NotifyRequestAuthorization* notify_request_authorization_construct (GType object_type, const gchar* resource) { +	NotifyRequestAuthorization* self = NULL; +	gchar* _tmp0_; +	g_return_val_if_fail (resource != NULL, NULL); +	self = (NotifyRequestAuthorization*) notify_construct (object_type); +	_tmp0_ = g_strdup (resource); +	_g_free0 (self->priv->resource); +	self->priv->resource = _tmp0_; +	return self; +} + + +NotifyRequestAuthorization* notify_request_authorization_new (const gchar* resource) { +	return notify_request_authorization_construct (TYPE_NOTIFY_REQUEST_AUTHORIZATION, resource); +} + + +static void notify_request_authorization_real_run (Notify* base, Scanner* scanner) { +	NotifyRequestAuthorization * self; +	self = (NotifyRequestAuthorization*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "request-authorization", self->priv->resource); +} + + +static void notify_request_authorization_class_init (NotifyRequestAuthorizationClass * klass) { +	notify_request_authorization_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->finalize = notify_request_authorization_finalize; +	g_type_class_add_private (klass, sizeof (NotifyRequestAuthorizationPrivate)); +	NOTIFY_CLASS (klass)->run = notify_request_authorization_real_run; +} + + +static void notify_request_authorization_instance_init (NotifyRequestAuthorization * self) { +	self->priv = NOTIFY_REQUEST_AUTHORIZATION_GET_PRIVATE (self); +} + + +static void notify_request_authorization_finalize (Notify* obj) { +	NotifyRequestAuthorization * self; +	self = NOTIFY_REQUEST_AUTHORIZATION (obj); +	_g_free0 (self->priv->resource); +	NOTIFY_CLASS (notify_request_authorization_parent_class)->finalize (obj); +} + + +GType notify_request_authorization_get_type (void) { +	static volatile gsize notify_request_authorization_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_request_authorization_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyRequestAuthorizationClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_request_authorization_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyRequestAuthorization), 0, (GInstanceInitFunc) notify_request_authorization_instance_init, NULL }; +		GType notify_request_authorization_type_id; +		notify_request_authorization_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyRequestAuthorization", &g_define_type_info, 0); +		g_once_init_leave (¬ify_request_authorization_type_id__volatile, notify_request_authorization_type_id); +	} +	return notify_request_authorization_type_id__volatile; +} + + +NotifyScanFailed* notify_scan_failed_construct (GType object_type, gint error_code, const gchar* error_string) { +	NotifyScanFailed* self = NULL; +	gchar* _tmp0_; +	g_return_val_if_fail (error_string != NULL, NULL); +	self = (NotifyScanFailed*) notify_construct (object_type); +	self->priv->error_code = error_code; +	_tmp0_ = g_strdup (error_string); +	_g_free0 (self->priv->error_string); +	self->priv->error_string = _tmp0_; +	return self; +} + + +NotifyScanFailed* notify_scan_failed_new (gint error_code, const gchar* error_string) { +	return notify_scan_failed_construct (TYPE_NOTIFY_SCAN_FAILED, error_code, error_string); +} + + +static void notify_scan_failed_real_run (Notify* base, Scanner* scanner) { +	NotifyScanFailed * self; +	self = (NotifyScanFailed*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "scan-failed", self->priv->error_code, self->priv->error_string); +} + + +static void notify_scan_failed_class_init (NotifyScanFailedClass * klass) { +	notify_scan_failed_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->finalize = notify_scan_failed_finalize; +	g_type_class_add_private (klass, sizeof (NotifyScanFailedPrivate)); +	NOTIFY_CLASS (klass)->run = notify_scan_failed_real_run; +} + + +static void notify_scan_failed_instance_init (NotifyScanFailed * self) { +	self->priv = NOTIFY_SCAN_FAILED_GET_PRIVATE (self); +} + + +static void notify_scan_failed_finalize (Notify* obj) { +	NotifyScanFailed * self; +	self = NOTIFY_SCAN_FAILED (obj); +	_g_free0 (self->priv->error_string); +	NOTIFY_CLASS (notify_scan_failed_parent_class)->finalize (obj); +} + + +GType notify_scan_failed_get_type (void) { +	static volatile gsize notify_scan_failed_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_scan_failed_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyScanFailedClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_scan_failed_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyScanFailed), 0, (GInstanceInitFunc) notify_scan_failed_instance_init, NULL }; +		GType notify_scan_failed_type_id; +		notify_scan_failed_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyScanFailed", &g_define_type_info, 0); +		g_once_init_leave (¬ify_scan_failed_type_id__volatile, notify_scan_failed_type_id); +	} +	return notify_scan_failed_type_id__volatile; +} + + +static void notify_document_done_real_run (Notify* base, Scanner* scanner) { +	NotifyDocumentDone * self; +	self = (NotifyDocumentDone*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "document-done"); +} + + +NotifyDocumentDone* notify_document_done_construct (GType object_type) { +	NotifyDocumentDone* self = NULL; +	self = (NotifyDocumentDone*) notify_construct (object_type); +	return self; +} + + +NotifyDocumentDone* notify_document_done_new (void) { +	return notify_document_done_construct (TYPE_NOTIFY_DOCUMENT_DONE); +} + + +static void notify_document_done_class_init (NotifyDocumentDoneClass * klass) { +	notify_document_done_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->run = notify_document_done_real_run; +} + + +static void notify_document_done_instance_init (NotifyDocumentDone * self) { +} + + +GType notify_document_done_get_type (void) { +	static volatile gsize notify_document_done_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_document_done_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyDocumentDoneClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_document_done_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyDocumentDone), 0, (GInstanceInitFunc) notify_document_done_instance_init, NULL }; +		GType notify_document_done_type_id; +		notify_document_done_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyDocumentDone", &g_define_type_info, 0); +		g_once_init_leave (¬ify_document_done_type_id__volatile, notify_document_done_type_id); +	} +	return notify_document_done_type_id__volatile; +} + + +static void notify_expect_page_real_run (Notify* base, Scanner* scanner) { +	NotifyExpectPage * self; +	self = (NotifyExpectPage*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "expect-page"); +} + + +NotifyExpectPage* notify_expect_page_construct (GType object_type) { +	NotifyExpectPage* self = NULL; +	self = (NotifyExpectPage*) notify_construct (object_type); +	return self; +} + + +NotifyExpectPage* notify_expect_page_new (void) { +	return notify_expect_page_construct (TYPE_NOTIFY_EXPECT_PAGE); +} + + +static void notify_expect_page_class_init (NotifyExpectPageClass * klass) { +	notify_expect_page_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->run = notify_expect_page_real_run; +} + + +static void notify_expect_page_instance_init (NotifyExpectPage * self) { +} + + +GType notify_expect_page_get_type (void) { +	static volatile gsize notify_expect_page_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_expect_page_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyExpectPageClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_expect_page_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyExpectPage), 0, (GInstanceInitFunc) notify_expect_page_instance_init, NULL }; +		GType notify_expect_page_type_id; +		notify_expect_page_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyExpectPage", &g_define_type_info, 0); +		g_once_init_leave (¬ify_expect_page_type_id__volatile, notify_expect_page_type_id); +	} +	return notify_expect_page_type_id__volatile; +} + + +static gpointer _scan_page_info_ref0 (gpointer self) { +	return self ? scan_page_info_ref (self) : NULL; +} + + +NotifyGotPageInfo* notify_got_page_info_construct (GType object_type, ScanPageInfo* info) { +	NotifyGotPageInfo* self = NULL; +	ScanPageInfo* _tmp0_; +	g_return_val_if_fail (info != NULL, NULL); +	self = (NotifyGotPageInfo*) notify_construct (object_type); +	_tmp0_ = _scan_page_info_ref0 (info); +	_scan_page_info_unref0 (self->priv->info); +	self->priv->info = _tmp0_; +	return self; +} + + +NotifyGotPageInfo* notify_got_page_info_new (ScanPageInfo* info) { +	return notify_got_page_info_construct (TYPE_NOTIFY_GOT_PAGE_INFO, info); +} + + +static void notify_got_page_info_real_run (Notify* base, Scanner* scanner) { +	NotifyGotPageInfo * self; +	self = (NotifyGotPageInfo*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "got-page-info", self->priv->info); +} + + +static void notify_got_page_info_class_init (NotifyGotPageInfoClass * klass) { +	notify_got_page_info_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->finalize = notify_got_page_info_finalize; +	g_type_class_add_private (klass, sizeof (NotifyGotPageInfoPrivate)); +	NOTIFY_CLASS (klass)->run = notify_got_page_info_real_run; +} + + +static void notify_got_page_info_instance_init (NotifyGotPageInfo * self) { +	self->priv = NOTIFY_GOT_PAGE_INFO_GET_PRIVATE (self); +} + + +static void notify_got_page_info_finalize (Notify* obj) { +	NotifyGotPageInfo * self; +	self = NOTIFY_GOT_PAGE_INFO (obj); +	_scan_page_info_unref0 (self->priv->info); +	NOTIFY_CLASS (notify_got_page_info_parent_class)->finalize (obj); +} + + +GType notify_got_page_info_get_type (void) { +	static volatile gsize notify_got_page_info_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_got_page_info_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyGotPageInfoClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_got_page_info_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyGotPageInfo), 0, (GInstanceInitFunc) notify_got_page_info_instance_init, NULL }; +		GType notify_got_page_info_type_id; +		notify_got_page_info_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyGotPageInfo", &g_define_type_info, 0); +		g_once_init_leave (¬ify_got_page_info_type_id__volatile, notify_got_page_info_type_id); +	} +	return notify_got_page_info_type_id__volatile; +} + + +static void notify_page_done_real_run (Notify* base, Scanner* scanner) { +	NotifyPageDone * self; +	self = (NotifyPageDone*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "page-done"); +} + + +NotifyPageDone* notify_page_done_construct (GType object_type) { +	NotifyPageDone* self = NULL; +	self = (NotifyPageDone*) notify_construct (object_type); +	return self; +} + + +NotifyPageDone* notify_page_done_new (void) { +	return notify_page_done_construct (TYPE_NOTIFY_PAGE_DONE); +} + + +static void notify_page_done_class_init (NotifyPageDoneClass * klass) { +	notify_page_done_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->run = notify_page_done_real_run; +} + + +static void notify_page_done_instance_init (NotifyPageDone * self) { +} + + +GType notify_page_done_get_type (void) { +	static volatile gsize notify_page_done_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_page_done_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyPageDoneClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_page_done_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyPageDone), 0, (GInstanceInitFunc) notify_page_done_instance_init, NULL }; +		GType notify_page_done_type_id; +		notify_page_done_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyPageDone", &g_define_type_info, 0); +		g_once_init_leave (¬ify_page_done_type_id__volatile, notify_page_done_type_id); +	} +	return notify_page_done_type_id__volatile; +} + + +static gpointer _scan_line_ref0 (gpointer self) { +	return self ? scan_line_ref (self) : NULL; +} + + +NotifyGotLine* notify_got_line_construct (GType object_type, ScanLine* line) { +	NotifyGotLine* self = NULL; +	ScanLine* _tmp0_; +	g_return_val_if_fail (line != NULL, NULL); +	self = (NotifyGotLine*) notify_construct (object_type); +	_tmp0_ = _scan_line_ref0 (line); +	_scan_line_unref0 (self->priv->line); +	self->priv->line = _tmp0_; +	return self; +} + + +NotifyGotLine* notify_got_line_new (ScanLine* line) { +	return notify_got_line_construct (TYPE_NOTIFY_GOT_LINE, line); +} + + +static void notify_got_line_real_run (Notify* base, Scanner* scanner) { +	NotifyGotLine * self; +	self = (NotifyGotLine*) base; +	g_return_if_fail (scanner != NULL); +	g_signal_emit_by_name (scanner, "got-line", self->priv->line); +} + + +static void notify_got_line_class_init (NotifyGotLineClass * klass) { +	notify_got_line_parent_class = g_type_class_peek_parent (klass); +	NOTIFY_CLASS (klass)->finalize = notify_got_line_finalize; +	g_type_class_add_private (klass, sizeof (NotifyGotLinePrivate)); +	NOTIFY_CLASS (klass)->run = notify_got_line_real_run; +} + + +static void notify_got_line_instance_init (NotifyGotLine * self) { +	self->priv = NOTIFY_GOT_LINE_GET_PRIVATE (self); +} + + +static void notify_got_line_finalize (Notify* obj) { +	NotifyGotLine * self; +	self = NOTIFY_GOT_LINE (obj); +	_scan_line_unref0 (self->priv->line); +	NOTIFY_CLASS (notify_got_line_parent_class)->finalize (obj); +} + + +GType notify_got_line_get_type (void) { +	static volatile gsize notify_got_line_type_id__volatile = 0; +	if (g_once_init_enter (¬ify_got_line_type_id__volatile)) { +		static const GTypeInfo g_define_type_info = { sizeof (NotifyGotLineClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) notify_got_line_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (NotifyGotLine), 0, (GInstanceInitFunc) notify_got_line_instance_init, NULL }; +		GType notify_got_line_type_id; +		notify_got_line_type_id = g_type_register_static (TYPE_NOTIFY, "NotifyGotLine", &g_define_type_info, 0); +		g_once_init_leave (¬ify_got_line_type_id__volatile, notify_got_line_type_id); +	} +	return notify_got_line_type_id__volatile; +} + + +static void _scan_job_unref0_ (gpointer var) { +	(var == NULL) ? NULL : (var = (scan_job_unref (var), NULL)); +} + + +static void _g_list_free__scan_job_unref0_ (GList* self) { +	g_list_foreach (self, (GFunc) _scan_job_unref0_, NULL); +	g_list_free (self); +} + + +static Scanner* scanner_construct (GType object_type) { +	Scanner* self = NULL; +	GAsyncQueue* _tmp0_ = NULL; +	GAsyncQueue* _tmp1_ = NULL; +	GAsyncQueue* _tmp2_ = NULL; +	self = (Scanner*) g_type_create_instance (object_type); +	_tmp0_ = g_async_queue_new (); +	_g_async_queue_unref0 (self->priv->request_queue); +	self->priv->request_queue = _tmp0_; +	_tmp1_ = g_async_queue_new (); +	_g_async_queue_unref0 (self->priv->notify_queue); +	self->priv->notify_queue = _tmp1_; +	_tmp2_ = g_async_queue_new (); +	_g_async_queue_unref0 (self->priv->authorize_queue); +	self->priv->authorize_queue = _tmp2_; +	return self; +} + + +static Scanner* scanner_new (void) { +	return scanner_construct (TYPE_SCANNER); +} + + +static gpointer _scanner_ref0 (gpointer self) { +	return self ? scanner_ref (self) : NULL; +} + + +Scanner* scanner_get_instance (void) { +	Scanner* result = NULL; +	Scanner* _tmp1_; +	if (scanner_scanner_object == NULL) { +		Scanner* _tmp0_ = NULL; +		_tmp0_ = scanner_new (); +		_scanner_unref0 (scanner_scanner_object); +		scanner_scanner_object = _tmp0_; +	} +	_tmp1_ = _scanner_ref0 (scanner_scanner_object); +	result = _tmp1_; +	return result; +} + + +static gboolean scanner_notify_idle_cb (Scanner* self) { +	gboolean result = FALSE; +	gpointer _tmp0_ = NULL; +	Notify* notification; +	g_return_val_if_fail (self != NULL, FALSE); +	_tmp0_ = g_async_queue_pop (self->priv->notify_queue); +	notification = (Notify*) _tmp0_; +	notify_run (notification, self); +	result = FALSE; +	_notify_unref0 (notification); +	return result; +} + + +static gpointer _notify_ref0 (gpointer self) { +	return self ? notify_ref (self) : NULL; +} + + +static gboolean _scanner_notify_idle_cb_gsource_func (gpointer self) { +	gboolean result; +	result = scanner_notify_idle_cb (self); +	return result; +} + + +static void scanner_notify (Scanner* self, Notify* notification) { +	Notify* _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (notification != NULL); +	_tmp0_ = _notify_ref0 (notification); +	g_async_queue_push (self->priv->notify_queue, _tmp0_); +	g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, _scanner_notify_idle_cb_gsource_func, scanner_ref (self), scanner_unref); +} + + +static void scanner_set_scanning (Scanner* self, gboolean is_scanning) { +	gboolean _tmp0_ = FALSE; +	gboolean _tmp1_ = FALSE; +	g_return_if_fail (self != NULL); +	if (self->priv->scanning) { +		_tmp1_ = !is_scanning; +	} else { +		_tmp1_ = FALSE; +	} +	if (_tmp1_) { +		_tmp0_ = TRUE; +	} else { +		gboolean _tmp2_ = FALSE; +		if (!self->priv->scanning) { +			_tmp2_ = is_scanning; +		} else { +			_tmp2_ = FALSE; +		} +		_tmp0_ = _tmp2_; +	} +	if (_tmp0_) { +		NotifyScanningChanged* _tmp3_ = NULL; +		NotifyScanningChanged* _tmp4_; +		self->priv->scanning = is_scanning; +		g_signal_emit_by_name (self, "scanning-changed"); +		_tmp3_ = notify_scanning_changed_new (); +		_tmp4_ = _tmp3_; +		scanner_notify (self, (Notify*) _tmp4_); +		_notify_unref0 (_tmp4_); +	} +} + + +static gboolean string_contains (const gchar* self, const gchar* needle) { +	gboolean result = FALSE; +	gchar* _tmp0_ = NULL; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (needle != NULL, FALSE); +	_tmp0_ = strstr ((gchar*) self, (gchar*) needle); +	result = _tmp0_ != NULL; +	return result; +} + + +static gint scanner_get_device_weight (const gchar* device) { +	gint result = 0; +	gboolean _tmp0_; +	gboolean _tmp1_; +	g_return_val_if_fail (device != NULL, 0); +	_tmp0_ = g_str_has_prefix (device, "vfl:"); +	if (_tmp0_) { +		result = 2; +		return result; +	} +	_tmp1_ = string_contains (device, "usb"); +	if (_tmp1_) { +		result = 0; +		return result; +	} +	result = 1; +	return result; +} + + +static gint scanner_compare_devices (ScanDevice* device1, ScanDevice* device2) { +	gint result = 0; +	gint _tmp0_; +	gint weight1; +	gint _tmp1_; +	gint weight2; +	gint _tmp2_; +	g_return_val_if_fail (device1 != NULL, 0); +	g_return_val_if_fail (device2 != NULL, 0); +	_tmp0_ = scanner_get_device_weight (device1->name); +	weight1 = _tmp0_; +	_tmp1_ = scanner_get_device_weight (device2->name); +	weight2 = _tmp1_; +	if (weight1 != weight2) { +		result = weight1 - weight2; +		return result; +	} +	_tmp2_ = g_strcmp0 (device1->label, device2->label); +	result = _tmp2_; +	return result; +} + + +static gchar* sane_status_to_string (SANE_Status status) { +	gchar* result = NULL; +	switch (status) { +		case SANE_STATUS_GOOD: +		{ +			gchar* _tmp0_; +			_tmp0_ = g_strdup ("SANE_STATUS_GOOD"); +			result = _tmp0_; +			return result; +		} +		case SANE_STATUS_UNSUPPORTED: +		{ +			gchar* _tmp1_; +			_tmp1_ = g_strdup ("SANE_STATUS_UNSUPPORTED"); +			result = _tmp1_; +			return result; +		} +		case SANE_STATUS_CANCELLED: +		{ +			gchar* _tmp2_; +			_tmp2_ = g_strdup ("SANE_STATUS_CANCELLED"); +			result = _tmp2_; +			return result; +		} +		case SANE_STATUS_DEVICE_BUSY: +		{ +			gchar* _tmp3_; +			_tmp3_ = g_strdup ("SANE_STATUS_DEVICE_BUSY"); +			result = _tmp3_; +			return result; +		} +		case SANE_STATUS_INVAL: +		{ +			gchar* _tmp4_; +			_tmp4_ = g_strdup ("SANE_STATUS_INVAL"); +			result = _tmp4_; +			return result; +		} +		case SANE_STATUS_EOF: +		{ +			gchar* _tmp5_; +			_tmp5_ = g_strdup ("SANE_STATUS_EOF"); +			result = _tmp5_; +			return result; +		} +		case SANE_STATUS_JAMMED: +		{ +			gchar* _tmp6_; +			_tmp6_ = g_strdup ("SANE_STATUS_JAMMED"); +			result = _tmp6_; +			return result; +		} +		case SANE_STATUS_NO_DOCS: +		{ +			gchar* _tmp7_; +			_tmp7_ = g_strdup ("SANE_STATUS_NO_DOCS"); +			result = _tmp7_; +			return result; +		} +		case SANE_STATUS_COVER_OPEN: +		{ +			gchar* _tmp8_; +			_tmp8_ = g_strdup ("SANE_STATUS_COVER_OPEN"); +			result = _tmp8_; +			return result; +		} +		case SANE_STATUS_IO_ERROR: +		{ +			gchar* _tmp9_; +			_tmp9_ = g_strdup ("SANE_STATUS_IO_ERROR"); +			result = _tmp9_; +			return result; +		} +		case SANE_STATUS_NO_MEM: +		{ +			gchar* _tmp10_; +			_tmp10_ = g_strdup ("SANE_STATUS_NO_MEM"); +			result = _tmp10_; +			return result; +		} +		case SANE_STATUS_ACCESS_DENIED: +		{ +			gchar* _tmp11_; +			_tmp11_ = g_strdup ("SANE_STATUS_ACCESS_DENIED"); +			result = _tmp11_; +			return result; +		} +		default: +		{ +			gchar* _tmp12_ = NULL; +			_tmp12_ = g_strdup_printf ("SANE_STATUS(%d)", (gint) status); +			result = _tmp12_; +			return result; +		} +	} +} + + +static gchar* string_replace (const gchar* self, const gchar* old, const gchar* replacement) { +	gchar* result = NULL; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (old != NULL, NULL); +	g_return_val_if_fail (replacement != NULL, NULL); +	{ +		gchar* _tmp0_ = NULL; +		gchar* _tmp1_; +		GRegex* _tmp2_ = NULL; +		GRegex* _tmp3_; +		GRegex* regex; +		gchar* _tmp4_ = NULL; +		gchar* _tmp5_; +		_tmp0_ = g_regex_escape_string (old, -1); +		_tmp1_ = _tmp0_; +		_tmp2_ = g_regex_new (_tmp1_, 0, 0, &_inner_error_); +		_tmp3_ = _tmp2_; +		_g_free0 (_tmp1_); +		regex = _tmp3_; +		if (_inner_error_ != NULL) { +			if (_inner_error_->domain == G_REGEX_ERROR) { +				goto __catch8_g_regex_error; +			} +			g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +			g_clear_error (&_inner_error_); +			return NULL; +		} +		_tmp4_ = g_regex_replace_literal (regex, self, (gssize) (-1), 0, replacement, 0, &_inner_error_); +		_tmp5_ = _tmp4_; +		if (_inner_error_ != NULL) { +			_g_regex_unref0 (regex); +			if (_inner_error_->domain == G_REGEX_ERROR) { +				goto __catch8_g_regex_error; +			} +			_g_regex_unref0 (regex); +			g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +			g_clear_error (&_inner_error_); +			return NULL; +		} +		result = _tmp5_; +		_g_regex_unref0 (regex); +		return result; +	} +	goto __finally8; +	__catch8_g_regex_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_assert_not_reached (); +		_g_error_free0 (e); +	} +	__finally8: +	if (_inner_error_ != NULL) { +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return NULL; +	} +} + + +static gpointer _scan_device_ref0 (gpointer self) { +	return self ? scan_device_ref (self) : NULL; +} + + +static gint _scanner_compare_devices_gcompare_func (gconstpointer a, gconstpointer b) { +	gint result; +	result = scanner_compare_devices (a, b); +	return result; +} + + +static void scanner_do_redetect (Scanner* self) { +	SANE_Device** device_list; +	gint device_list_length1; +	gint _device_list_size_; +	SANE_Device** _tmp0_ = NULL; +	SANE_Status _tmp1_; +	SANE_Status status; +	gchar* _tmp2_ = NULL; +	gchar* _tmp3_; +	GList* devices; +	GList* _tmp17_; +	NotifyUpdateDevices* _tmp18_ = NULL; +	NotifyUpdateDevices* _tmp19_; +	g_return_if_fail (self != NULL); +	device_list = NULL; +	device_list_length1 = 0; +	_device_list_size_ = device_list_length1; +	_tmp1_ = sane_get_devices (&_tmp0_, FALSE); +	device_list = _tmp0_; +	device_list_length1 = -1; +	_device_list_size_ = device_list_length1; +	status = _tmp1_; +	_tmp2_ = sane_status_to_string (status); +	_tmp3_ = _tmp2_; +	g_debug ("scanner.vala:318: sane_get_devices () -> %s", _tmp3_); +	_g_free0 (_tmp3_); +	if (status != SANE_STATUS_GOOD) { +		const gchar* _tmp4_ = NULL; +		_tmp4_ = sane_strstatus (status); +		g_warning ("scanner.vala:321: Unable to get SANE devices: %s", _tmp4_); +		self->priv->need_redetect = FALSE; +		self->priv->state = SCAN_STATE_IDLE; +		return; +	} +	devices = NULL; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp5_; +			_tmp5_ = TRUE; +			while (TRUE) { +				ScanDevice* _tmp6_ = NULL; +				ScanDevice* scan_device; +				gchar* _tmp7_; +				gchar* _tmp8_; +				gchar* vendor; +				gchar* _tmp10_ = NULL; +				gchar* _tmp11_ = NULL; +				gchar* _tmp12_; +				ScanDevice* _tmp13_; +				if (!_tmp5_) { +					i++; +				} +				_tmp5_ = FALSE; +				if (!(device_list[i] != NULL)) { +					break; +				} +				g_debug ("scanner.vala:330: Device: name=\"%s\" vendor=\"%s\" model=\"%s\" type=" \ +"\"%s\"", device_list[i]->name, device_list[i]->vendor, device_list[i]->model, device_list[i]->type); +				_tmp6_ = scan_device_new (); +				scan_device = _tmp6_; +				_tmp7_ = g_strdup (device_list[i]->name); +				_g_free0 (scan_device->name); +				scan_device->name = _tmp7_; +				_tmp8_ = g_strdup (device_list[i]->vendor); +				vendor = _tmp8_; +				if (g_strcmp0 (vendor, "Hewlett-Packard") == 0) { +					gchar* _tmp9_; +					_tmp9_ = g_strdup ("HP"); +					_g_free0 (vendor); +					vendor = _tmp9_; +				} +				_tmp10_ = g_strdup_printf ("%s %s", vendor, device_list[i]->model); +				_g_free0 (scan_device->label); +				scan_device->label = _tmp10_; +				_tmp11_ = string_replace (scan_device->label, "_", " "); +				_tmp12_ = _tmp11_; +				_g_free0 (_tmp12_); +				_tmp13_ = _scan_device_ref0 (scan_device); +				devices = g_list_append (devices, _tmp13_); +				_g_free0 (vendor); +				_scan_device_unref0 (scan_device); +			} +		} +	} +	devices = g_list_sort (devices, _scanner_compare_devices_gcompare_func); +	self->priv->need_redetect = FALSE; +	self->priv->state = SCAN_STATE_IDLE; +	if (devices != NULL) { +		gconstpointer _tmp14_ = NULL; +		ScanDevice* _tmp15_; +		ScanDevice* device; +		gchar* _tmp16_; +		_tmp14_ = g_list_nth_data (devices, (guint) 0); +		_tmp15_ = _scan_device_ref0 ((ScanDevice*) _tmp14_); +		device = _tmp15_; +		_tmp16_ = g_strdup (device->name); +		_g_free0 (self->priv->default_device); +		self->priv->default_device = _tmp16_; +		_scan_device_unref0 (device); +	} else { +		_g_free0 (self->priv->default_device); +		self->priv->default_device = NULL; +	} +	_tmp17_ = devices; +	devices = NULL; +	_tmp18_ = notify_update_devices_new (_tmp17_); +	_tmp19_ = _tmp18_; +	scanner_notify (self, (Notify*) _tmp19_); +	_notify_unref0 (_tmp19_); +	__g_list_free__scan_device_unref0_0 (devices); +} + + +static gboolean scanner_set_default_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index) { +	gboolean result = FALSE; +	SANE_Status _tmp0_; +	SANE_Status status; +	gchar* _tmp1_ = NULL; +	gchar* _tmp2_; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (option != NULL, FALSE); +	if (((gint) (option->cap & SANE_CAP_AUTOMATIC)) == 0) { +		result = FALSE; +		return result; +	} +	_tmp0_ = sane_control_option (handle, option_index, SANE_ACTION_SET_AUTO, NULL, NULL); +	status = _tmp0_; +	_tmp1_ = sane_status_to_string (status); +	_tmp2_ = _tmp1_; +	g_debug ("scanner.vala:372: sane_control_option (%d, SANE_ACTION_SET_AUTO) -> %s", (gint) option_index, _tmp2_); +	_g_free0 (_tmp2_); +	if (status != SANE_STATUS_GOOD) { +		const gchar* _tmp3_ = NULL; +		_tmp3_ = sane_strstatus (status); +		g_warning ("scanner.vala:374: Error setting default option %s: %s", option->name, _tmp3_); +	} +	result = status == SANE_STATUS_GOOD; +	return result; +} + + +static void scanner_set_bool_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gboolean value, gboolean* _result_) { +	gboolean _result = FALSE; +	SANE_Bool v; +	SANE_Status _tmp0_; +	SANE_Status status; +	const gchar* _tmp1_ = NULL; +	const gchar* _tmp2_ = NULL; +	gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (option != NULL); +	g_return_if_fail (option->type == SANE_TYPE_BOOL); +	v = (SANE_Bool) value; +	_tmp0_ = sane_control_option (handle, option_index, SANE_ACTION_SET_VALUE, &v, NULL); +	status = _tmp0_; +	_result = (gboolean) v; +	if (value) { +		_tmp1_ = "SANE_TRUE"; +	} else { +		_tmp1_ = "SANE_FALSE"; +	} +	if (_result) { +		_tmp2_ = "SANE_TRUE"; +	} else { +		_tmp2_ = "SANE_FALSE"; +	} +	_tmp3_ = sane_status_to_string (status); +	_tmp4_ = _tmp3_; +	g_debug ("scanner.vala:386: sane_control_option (%d, SANE_ACTION_SET_VALUE, %s) " \ +"-> (%s, %s)", (gint) option_index, _tmp1_, _tmp4_, _tmp2_); +	_g_free0 (_tmp4_); +	if (_result_) { +		*_result_ = _result; +	} +} + + +static void scanner_set_int_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gint value, gint* _result_) { +	gint _result = 0; +	SANE_Int v; +	SANE_Status _tmp2_; +	SANE_Status status; +	gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (option != NULL); +	g_return_if_fail (option->type == SANE_TYPE_INT); +	v = (SANE_Int) value; +	if (option->constraint_type == SANE_CONSTRAINT_RANGE) { +		if (((gint) option->constraint.range->quant) != 0) { +			v = v * option->constraint.range->quant; +		} +		if (v < ((SANE_Int) option->constraint.range->min)) { +			v = (SANE_Int) option->constraint.range->min; +		} +		if (v > ((SANE_Int) option->constraint.range->max)) { +			v = (SANE_Int) option->constraint.range->max; +		} +	} else { +		if (option->constraint_type == SANE_CONSTRAINT_WORD_LIST) { +			gint distance; +			gint nearest; +			distance = G_MAXINT; +			nearest = 0; +			{ +				gint i; +				i = 0; +				{ +					gboolean _tmp0_; +					_tmp0_ = TRUE; +					while (TRUE) { +						gint x; +						gint _tmp1_; +						gint d; +						if (!_tmp0_) { +							i++; +						} +						_tmp0_ = FALSE; +						if (!(i < ((gint) option->constraint.word_list[0]))) { +							break; +						} +						x = (gint) option->constraint.word_list[i + 1]; +						_tmp1_ = abs (x - v); +						d = _tmp1_; +						if (d < distance) { +							distance = d; +							nearest = x; +						} +					} +				} +			} +			v = (SANE_Int) nearest; +		} +	} +	_tmp2_ = sane_control_option (handle, option_index, SANE_ACTION_SET_VALUE, &v, NULL); +	status = _tmp2_; +	_tmp3_ = sane_status_to_string (status); +	_tmp4_ = _tmp3_; +	g_debug ("scanner.vala:422: sane_control_option (%d, SANE_ACTION_SET_VALUE, %d) " \ +"-> (%s, %d)", (gint) option_index, value, _tmp4_, (gint) v); +	_g_free0 (_tmp4_); +	_result = (gint) v; +	if (_result_) { +		*_result_ = _result; +	} +} + + +static void scanner_set_fixed_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gdouble value, gdouble* _result_) { +	gdouble _result = 0.0; +	gdouble v; +	SANE_Fixed v_fixed; +	SANE_Fixed _tmp6_; +	SANE_Status _tmp7_; +	SANE_Status status; +	gchar* _tmp8_ = NULL; +	gchar* _tmp9_; +	gdouble _tmp10_; +	gdouble _tmp11_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (option != NULL); +	v = value; +	g_return_if_fail (option->type == SANE_TYPE_FIXED); +	if (option->constraint_type == SANE_CONSTRAINT_RANGE) { +		gdouble _tmp0_; +		gdouble min; +		gdouble _tmp1_; +		gdouble max; +		_tmp0_ = SANE_UNFIX ((SANE_Fixed) option->constraint.range->min); +		min = _tmp0_; +		_tmp1_ = SANE_UNFIX ((SANE_Fixed) option->constraint.range->max); +		max = _tmp1_; +		if (v < min) { +			v = min; +		} +		if (v > max) { +			v = max; +		} +	} else { +		if (option->constraint_type == SANE_CONSTRAINT_WORD_LIST) { +			gdouble distance; +			gdouble nearest; +			distance = DBL_MAX; +			nearest = 0.0; +			{ +				gint i; +				i = 0; +				{ +					gboolean _tmp2_; +					_tmp2_ = TRUE; +					while (TRUE) { +						gdouble _tmp3_; +						gdouble x; +						gdouble _tmp4_; +						if (!_tmp2_) { +							i++; +						} +						_tmp2_ = FALSE; +						if (!(i < ((gint) option->constraint.word_list[0]))) { +							break; +						} +						_tmp3_ = SANE_UNFIX ((SANE_Fixed) option->constraint.word_list[i + 1]); +						x = _tmp3_; +						_tmp4_ = fabs (x - v); +						if (_tmp4_ < distance) { +							gdouble _tmp5_; +							_tmp5_ = fabs (x - v); +							distance = _tmp5_; +							nearest = x; +						} +					} +				} +			} +			v = nearest; +		} +	} +	_tmp6_ = SANE_FIX (v); +	v_fixed = _tmp6_; +	_tmp7_ = sane_control_option (handle, option_index, SANE_ACTION_SET_VALUE, &v_fixed, NULL); +	status = _tmp7_; +	_tmp8_ = sane_status_to_string (status); +	_tmp9_ = _tmp8_; +	_tmp10_ = SANE_UNFIX (v_fixed); +	g_debug ("scanner.vala:462: sane_control_option (%d, SANE_ACTION_SET_VALUE, %f) " \ +"-> (%s, %f)", (gint) option_index, value, _tmp9_, _tmp10_); +	_g_free0 (_tmp9_); +	_tmp11_ = SANE_UNFIX (v_fixed); +	_result = _tmp11_; +	if (_result_) { +		*_result_ = _result; +	} +} + + +static gchar string_get (const gchar* self, glong index) { +	gchar result = '\0'; +	g_return_val_if_fail (self != NULL, '\0'); +	result = ((gchar*) self)[index]; +	return result; +} + + +static gboolean scanner_set_string_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, const gchar* value, gchar** _result_) { +	gchar* _result = NULL; +	gboolean result = FALSE; +	gchar* _tmp0_ = NULL; +	gchar* s; +	gint s_length1; +	gint _s_size_; +	gint i; +	SANE_Status _tmp5_; +	SANE_Status status; +	gchar* _tmp6_; +	gchar* _tmp7_ = NULL; +	gchar* _tmp8_; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (option != NULL, FALSE); +	g_return_val_if_fail (value != NULL, FALSE); +	g_return_val_if_fail (option->type == SANE_TYPE_STRING, FALSE); +	_tmp0_ = g_new0 (gchar, option->size); +	s = _tmp0_; +	s_length1 = option->size; +	_s_size_ = s_length1; +	i = 0; +	{ +		gboolean _tmp1_; +		_tmp1_ = TRUE; +		while (TRUE) { +			gboolean _tmp2_ = FALSE; +			gchar _tmp4_; +			if (!_tmp1_) { +				i++; +			} +			_tmp1_ = FALSE; +			if (i < (option->size - 1)) { +				gchar _tmp3_; +				_tmp3_ = string_get (value, (glong) i); +				_tmp2_ = _tmp3_ != '\0'; +			} else { +				_tmp2_ = FALSE; +			} +			if (!_tmp2_) { +				break; +			} +			_tmp4_ = string_get (value, (glong) i); +			s[i] = _tmp4_; +		} +	} +	s[i] = '\0'; +	_tmp5_ = sane_control_option (handle, option_index, SANE_ACTION_SET_VALUE, s, NULL); +	status = _tmp5_; +	_tmp6_ = g_strdup ((const gchar*) s); +	_g_free0 (_result); +	_result = _tmp6_; +	_tmp7_ = sane_status_to_string (status); +	_tmp8_ = _tmp7_; +	g_debug ("scanner.vala:478: sane_control_option (%d, SANE_ACTION_SET_VALUE, \"%s" \ +"\") -> (%s, \"%s\")", (gint) option_index, value, _tmp8_, _result); +	_g_free0 (_tmp8_); +	result = status == SANE_STATUS_GOOD; +	s = (g_free (s), NULL); +	if (_result_) { +		*_result_ = _result; +	} else { +		_g_free0 (_result); +	} +	return result; +} + + +static gboolean scanner_set_constrained_string_option (Scanner* self, SANE_Handle handle, const SANE_Option_Descriptor* option, SANE_Int option_index, gchar** values, int values_length1, gchar** _result_) { +	gchar* _result = NULL; +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (option != NULL, FALSE); +	g_return_val_if_fail (option->type == SANE_TYPE_STRING, FALSE); +	g_return_val_if_fail (option->constraint_type == SANE_CONSTRAINT_STRING_LIST, FALSE); +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp0_; +			_tmp0_ = TRUE; +			while (TRUE) { +				gint j; +				if (!_tmp0_) { +					i++; +				} +				_tmp0_ = FALSE; +				if (!(values[i] != NULL)) { +					break; +				} +				j = 0; +				{ +					gboolean _tmp1_; +					_tmp1_ = TRUE; +					while (TRUE) { +						if (!_tmp1_) { +							j++; +						} +						_tmp1_ = FALSE; +						if (!(option->constraint.string_list[j] != NULL)) { +							break; +						} +						if (g_strcmp0 (values[i], option->constraint.string_list[j]) == 0) { +							break; +						} +					} +				} +				if (option->constraint.string_list[j] != NULL) { +					gchar* _tmp2_ = NULL; +					gboolean _tmp3_; +					_tmp3_ = scanner_set_string_option (self, handle, option, option_index, values[i], &_tmp2_); +					_g_free0 (_result); +					_result = _tmp2_; +					result = _tmp3_; +					if (_result_) { +						*_result_ = _result; +					} else { +						_g_free0 (_result); +					} +					return result; +				} +			} +		} +	} +	result = FALSE; +	if (_result_) { +		*_result_ = _result; +	} else { +		_g_free0 (_result); +	} +	return result; +} + + +static void scanner_log_option (Scanner* self, SANE_Int index, const SANE_Option_Descriptor* option) { +	gchar* _tmp0_ = NULL; +	gchar* s; +	gchar* _tmp16_ = NULL; +	gchar* _tmp17_; +	gchar* _tmp18_; +	SANE_Int cap; +	g_return_if_fail (self != NULL); +	g_return_if_fail (option != NULL); +	_tmp0_ = g_strdup_printf ("Option %d:", (gint) index); +	s = _tmp0_; +	if (g_strcmp0 (option->name, "") != 0) { +		gchar* _tmp1_ = NULL; +		gchar* _tmp2_; +		gchar* _tmp3_; +		_tmp1_ = g_strdup_printf (" name='%s'", option->name); +		_tmp2_ = _tmp1_; +		_tmp3_ = g_strconcat (s, _tmp2_, NULL); +		_g_free0 (s); +		s = _tmp3_; +		_g_free0 (_tmp2_); +	} +	if (g_strcmp0 (option->title, "") != 0) { +		gchar* _tmp4_ = NULL; +		gchar* _tmp5_; +		gchar* _tmp6_; +		_tmp4_ = g_strdup_printf (" title='%s'", option->title); +		_tmp5_ = _tmp4_; +		_tmp6_ = g_strconcat (s, _tmp5_, NULL); +		_g_free0 (s); +		s = _tmp6_; +		_g_free0 (_tmp5_); +	} +	switch (option->type) { +		case SANE_TYPE_BOOL: +		{ +			gchar* _tmp7_; +			_tmp7_ = g_strconcat (s, " type=bool", NULL); +			_g_free0 (s); +			s = _tmp7_; +			break; +		} +		case SANE_TYPE_INT: +		{ +			gchar* _tmp8_; +			_tmp8_ = g_strconcat (s, " type=int", NULL); +			_g_free0 (s); +			s = _tmp8_; +			break; +		} +		case SANE_TYPE_FIXED: +		{ +			gchar* _tmp9_; +			_tmp9_ = g_strconcat (s, " type=fixed", NULL); +			_g_free0 (s); +			s = _tmp9_; +			break; +		} +		case SANE_TYPE_STRING: +		{ +			gchar* _tmp10_; +			_tmp10_ = g_strconcat (s, " type=string", NULL); +			_g_free0 (s); +			s = _tmp10_; +			break; +		} +		case SANE_TYPE_BUTTON: +		{ +			gchar* _tmp11_; +			_tmp11_ = g_strconcat (s, " type=button", NULL); +			_g_free0 (s); +			s = _tmp11_; +			break; +		} +		case SANE_TYPE_GROUP: +		{ +			gchar* _tmp12_; +			_tmp12_ = g_strconcat (s, " type=group", NULL); +			_g_free0 (s); +			s = _tmp12_; +			break; +		} +		default: +		{ +			gchar* _tmp13_ = NULL; +			gchar* _tmp14_; +			gchar* _tmp15_; +			_tmp13_ = g_strdup_printf (" type=%d", (gint) option->type); +			_tmp14_ = _tmp13_; +			_tmp15_ = g_strconcat (s, _tmp14_, NULL); +			_g_free0 (s); +			s = _tmp15_; +			_g_free0 (_tmp14_); +			break; +		} +	} +	_tmp16_ = g_strdup_printf (" size=%d", (gint) option->size); +	_tmp17_ = _tmp16_; +	_tmp18_ = g_strconcat (s, _tmp17_, NULL); +	_g_free0 (s); +	s = _tmp18_; +	_g_free0 (_tmp17_); +	switch (option->unit) { +		case SANE_UNIT_NONE: +		{ +			break; +		} +		case SANE_UNIT_PIXEL: +		{ +			gchar* _tmp19_; +			_tmp19_ = g_strconcat (s, " unit=pixels", NULL); +			_g_free0 (s); +			s = _tmp19_; +			break; +		} +		case SANE_UNIT_BIT: +		{ +			gchar* _tmp20_; +			_tmp20_ = g_strconcat (s, " unit=bits", NULL); +			_g_free0 (s); +			s = _tmp20_; +			break; +		} +		case SANE_UNIT_MM: +		{ +			gchar* _tmp21_; +			_tmp21_ = g_strconcat (s, " unit=mm", NULL); +			_g_free0 (s); +			s = _tmp21_; +			break; +		} +		case SANE_UNIT_DPI: +		{ +			gchar* _tmp22_; +			_tmp22_ = g_strconcat (s, " unit=dpi", NULL); +			_g_free0 (s); +			s = _tmp22_; +			break; +		} +		case SANE_UNIT_PERCENT: +		{ +			gchar* _tmp23_; +			_tmp23_ = g_strconcat (s, " unit=percent", NULL); +			_g_free0 (s); +			s = _tmp23_; +			break; +		} +		case SANE_UNIT_MICROSECOND: +		{ +			gchar* _tmp24_; +			_tmp24_ = g_strconcat (s, " unit=microseconds", NULL); +			_g_free0 (s); +			s = _tmp24_; +			break; +		} +		default: +		{ +			gchar* _tmp25_ = NULL; +			gchar* _tmp26_; +			gchar* _tmp27_; +			_tmp25_ = g_strdup_printf (" unit=%d", (gint) option->unit); +			_tmp26_ = _tmp25_; +			_tmp27_ = g_strconcat (s, _tmp26_, NULL); +			_g_free0 (s); +			s = _tmp27_; +			_g_free0 (_tmp26_); +			break; +		} +	} +	switch (option->constraint_type) { +		case SANE_CONSTRAINT_RANGE: +		{ +			if (option->type == SANE_TYPE_FIXED) { +				gdouble _tmp28_; +				gdouble _tmp29_; +				gchar* _tmp30_ = NULL; +				gchar* _tmp31_; +				gchar* _tmp32_; +				_tmp28_ = SANE_UNFIX ((SANE_Fixed) option->constraint.range->min); +				_tmp29_ = SANE_UNFIX ((SANE_Fixed) option->constraint.range->max); +				_tmp30_ = g_strdup_printf (" min=%f, max=%f, quant=%d", _tmp28_, _tmp29_, (gint) option->constraint.range->quant); +				_tmp31_ = _tmp30_; +				_tmp32_ = g_strconcat (s, _tmp31_, NULL); +				_g_free0 (s); +				s = _tmp32_; +				_g_free0 (_tmp31_); +			} else { +				gchar* _tmp33_ = NULL; +				gchar* _tmp34_; +				gchar* _tmp35_; +				_tmp33_ = g_strdup_printf (" min=%d, max=%d, quant=%d", (gint) option->constraint.range->min, (gint) option->constraint.range->max, (gint) option->constraint.range->quant); +				_tmp34_ = _tmp33_; +				_tmp35_ = g_strconcat (s, _tmp34_, NULL); +				_g_free0 (s); +				s = _tmp35_; +				_g_free0 (_tmp34_); +			} +			break; +		} +		case SANE_CONSTRAINT_WORD_LIST: +		{ +			gchar* _tmp36_; +			gchar* _tmp46_; +			_tmp36_ = g_strconcat (s, " values=[", NULL); +			_g_free0 (s); +			s = _tmp36_; +			{ +				gint i; +				i = 0; +				{ +					gboolean _tmp37_; +					_tmp37_ = TRUE; +					while (TRUE) { +						if (!_tmp37_) { +							i++; +						} +						_tmp37_ = FALSE; +						if (!(i < ((gint) option->constraint.word_list[0]))) { +							break; +						} +						if (i != 0) { +							gchar* _tmp38_; +							_tmp38_ = g_strconcat (s, ", ", NULL); +							_g_free0 (s); +							s = _tmp38_; +						} +						if (option->type == SANE_TYPE_INT) { +							gchar* _tmp39_ = NULL; +							gchar* _tmp40_; +							gchar* _tmp41_; +							_tmp39_ = g_strdup_printf ("%d", (gint) option->constraint.word_list[i + 1]); +							_tmp40_ = _tmp39_; +							_tmp41_ = g_strconcat (s, _tmp40_, NULL); +							_g_free0 (s); +							s = _tmp41_; +							_g_free0 (_tmp40_); +						} else { +							gdouble _tmp42_; +							gchar* _tmp43_ = NULL; +							gchar* _tmp44_; +							gchar* _tmp45_; +							_tmp42_ = SANE_UNFIX ((SANE_Fixed) option->constraint.word_list[i + 1]); +							_tmp43_ = g_strdup_printf ("%f", _tmp42_); +							_tmp44_ = _tmp43_; +							_tmp45_ = g_strconcat (s, _tmp44_, NULL); +							_g_free0 (s); +							s = _tmp45_; +							_g_free0 (_tmp44_); +						} +					} +				} +			} +			_tmp46_ = g_strconcat (s, "]", NULL); +			_g_free0 (s); +			s = _tmp46_; +			break; +		} +		case SANE_CONSTRAINT_STRING_LIST: +		{ +			gchar* _tmp47_; +			gchar* _tmp53_; +			_tmp47_ = g_strconcat (s, " values=[", NULL); +			_g_free0 (s); +			s = _tmp47_; +			{ +				gint i; +				i = 0; +				{ +					gboolean _tmp48_; +					_tmp48_ = TRUE; +					while (TRUE) { +						gchar* _tmp50_ = NULL; +						gchar* _tmp51_; +						gchar* _tmp52_; +						if (!_tmp48_) { +							i++; +						} +						_tmp48_ = FALSE; +						if (!(option->constraint.string_list[i] != NULL)) { +							break; +						} +						if (i != 0) { +							gchar* _tmp49_; +							_tmp49_ = g_strconcat (s, ", ", NULL); +							_g_free0 (s); +							s = _tmp49_; +						} +						_tmp50_ = g_strdup_printf ("\"%s\"", option->constraint.string_list[i]); +						_tmp51_ = _tmp50_; +						_tmp52_ = g_strconcat (s, _tmp51_, NULL); +						_g_free0 (s); +						s = _tmp52_; +						_g_free0 (_tmp51_); +					} +				} +			} +			_tmp53_ = g_strconcat (s, "]", NULL); +			_g_free0 (s); +			s = _tmp53_; +			break; +		} +		default: +		{ +			break; +		} +	} +	cap = option->cap; +	if (((gint) cap) != 0) { +		gchar* _tmp54_; +		_tmp54_ = g_strconcat (s, " cap=", NULL); +		_g_free0 (s); +		s = _tmp54_; +		if (((gint) (cap & SANE_CAP_SOFT_SELECT)) != 0) { +			gchar* _tmp56_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp55_; +				_tmp55_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp55_; +			} +			_tmp56_ = g_strconcat (s, "soft-select", NULL); +			_g_free0 (s); +			s = _tmp56_; +			cap = cap & (~SANE_CAP_SOFT_SELECT); +		} +		if (((gint) (cap & SANE_CAP_HARD_SELECT)) != 0) { +			gchar* _tmp58_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp57_; +				_tmp57_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp57_; +			} +			_tmp58_ = g_strconcat (s, "hard-select", NULL); +			_g_free0 (s); +			s = _tmp58_; +			cap = cap & (~SANE_CAP_HARD_SELECT); +		} +		if (((gint) (cap & SANE_CAP_SOFT_DETECT)) != 0) { +			gchar* _tmp60_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp59_; +				_tmp59_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp59_; +			} +			_tmp60_ = g_strconcat (s, "soft-detect", NULL); +			_g_free0 (s); +			s = _tmp60_; +			cap = cap & (~SANE_CAP_SOFT_DETECT); +		} +		if (((gint) (cap & SANE_CAP_EMULATED)) != 0) { +			gchar* _tmp62_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp61_; +				_tmp61_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp61_; +			} +			_tmp62_ = g_strconcat (s, "emulated", NULL); +			_g_free0 (s); +			s = _tmp62_; +			cap = cap & (~SANE_CAP_EMULATED); +		} +		if (((gint) (cap & SANE_CAP_AUTOMATIC)) != 0) { +			gchar* _tmp64_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp63_; +				_tmp63_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp63_; +			} +			_tmp64_ = g_strconcat (s, "automatic", NULL); +			_g_free0 (s); +			s = _tmp64_; +			cap = cap & (~SANE_CAP_AUTOMATIC); +		} +		if (((gint) (cap & SANE_CAP_INACTIVE)) != 0) { +			gchar* _tmp66_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp65_; +				_tmp65_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp65_; +			} +			_tmp66_ = g_strconcat (s, "inactive", NULL); +			_g_free0 (s); +			s = _tmp66_; +			cap = cap & (~SANE_CAP_INACTIVE); +		} +		if (((gint) (cap & SANE_CAP_ADVANCED)) != 0) { +			gchar* _tmp68_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp67_; +				_tmp67_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp67_; +			} +			_tmp68_ = g_strconcat (s, "advanced", NULL); +			_g_free0 (s); +			s = _tmp68_; +			cap = cap & (~SANE_CAP_ADVANCED); +		} +		if (((gint) cap) != 0) { +			gchar* _tmp70_ = NULL; +			gchar* _tmp71_; +			gchar* _tmp72_; +			if (g_strcmp0 (s, "") != 0) { +				gchar* _tmp69_; +				_tmp69_ = g_strconcat (s, ",", NULL); +				_g_free0 (s); +				s = _tmp69_; +			} +			_tmp70_ = g_strdup_printf ("%x", (guint) cap); +			_tmp71_ = _tmp70_; +			_tmp72_ = g_strconcat (s, _tmp71_, NULL); +			_g_free0 (s); +			s = _tmp72_; +			_g_free0 (_tmp71_); +		} +	} +	g_debug ("scanner.vala:665: %s", s); +	if (option->desc != NULL) { +		g_debug ("scanner.vala:668:   Description: %s", option->desc); +	} +	_g_free0 (s); +} + + +static void scanner_authorization_cb (const gchar* resource, gchar* username, int username_length1, gchar* password, int password_length1) { +	NotifyRequestAuthorization* _tmp0_ = NULL; +	NotifyRequestAuthorization* _tmp1_; +	gpointer _tmp2_ = NULL; +	Credentials* credentials; +	g_return_if_fail (resource != NULL); +	_tmp0_ = notify_request_authorization_new (resource); +	_tmp1_ = _tmp0_; +	scanner_notify (scanner_scanner_object, (Notify*) _tmp1_); +	_notify_unref0 (_tmp1_); +	_tmp2_ = g_async_queue_pop (scanner_scanner_object->priv->authorize_queue); +	credentials = (Credentials*) _tmp2_; +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp3_; +			_tmp3_ = TRUE; +			while (TRUE) { +				gboolean _tmp4_ = FALSE; +				gchar _tmp5_; +				gchar _tmp6_; +				if (!_tmp3_) { +					i++; +				} +				_tmp3_ = FALSE; +				_tmp5_ = string_get (credentials->username, (glong) i); +				if (_tmp5_ != '\0') { +					_tmp4_ = i < SANE_MAX_USERNAME_LEN; +				} else { +					_tmp4_ = FALSE; +				} +				if (!_tmp4_) { +					break; +				} +				_tmp6_ = string_get (credentials->username, (glong) i); +				username[i] = _tmp6_; +			} +		} +	} +	{ +		gint i; +		i = 0; +		{ +			gboolean _tmp7_; +			_tmp7_ = TRUE; +			while (TRUE) { +				gboolean _tmp8_ = FALSE; +				gchar _tmp9_; +				gchar _tmp10_; +				if (!_tmp7_) { +					i++; +				} +				_tmp7_ = FALSE; +				_tmp9_ = string_get (credentials->password, (glong) i); +				if (_tmp9_ != '\0') { +					_tmp8_ = i < SANE_MAX_USERNAME_LEN; +				} else { +					_tmp8_ = FALSE; +				} +				if (!_tmp8_) { +					break; +				} +				_tmp10_ = string_get (credentials->password, (glong) i); +				password[i] = _tmp10_; +			} +		} +	} +	_credentials_unref0 (credentials); +} + + +static gpointer _credentials_ref0 (gpointer self) { +	return self ? credentials_ref (self) : NULL; +} + + +void scanner_authorize (Scanner* self, const gchar* username, const gchar* password) { +	Credentials* _tmp0_ = NULL; +	Credentials* credentials; +	gchar* _tmp1_; +	gchar* _tmp2_; +	Credentials* _tmp3_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (username != NULL); +	g_return_if_fail (password != NULL); +	_tmp0_ = credentials_new (); +	credentials = _tmp0_; +	_tmp1_ = g_strdup (username); +	_g_free0 (credentials->username); +	credentials->username = _tmp1_; +	_tmp2_ = g_strdup (password); +	_g_free0 (credentials->password); +	credentials->password = _tmp2_; +	_tmp3_ = _credentials_ref0 (credentials); +	g_async_queue_push (self->priv->authorize_queue, _tmp3_); +	_credentials_unref0 (credentials); +} + + +static void scanner_close_device (Scanner* self) { +	g_return_if_fail (self != NULL); +	if (self->priv->have_handle) { +		sane_cancel (self->priv->handle); +		g_debug ("scanner.vala:695: sane_cancel ()"); +		sane_close (self->priv->handle); +		g_debug ("scanner.vala:698: sane_close ()"); +		self->priv->have_handle = FALSE; +	} +	self->priv->buffer = (g_free (self->priv->buffer), NULL); +	self->priv->buffer = NULL; +	self->priv->buffer_length1 = 0; +	self->priv->_buffer_size_ = self->priv->buffer_length1; +	__g_list_free__scan_job_unref0_0 (self->priv->job_queue); +	self->priv->job_queue = NULL; +	scanner_set_scanning (self, FALSE); +} + + +static void scanner_fail_scan (Scanner* self, gint error_code, const gchar* error_string) { +	NotifyScanFailed* _tmp0_ = NULL; +	NotifyScanFailed* _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (error_string != NULL); +	scanner_close_device (self); +	self->priv->state = SCAN_STATE_IDLE; +	_tmp0_ = notify_scan_failed_new (error_code, error_string); +	_tmp1_ = _tmp0_; +	scanner_notify (self, (Notify*) _tmp1_); +	_notify_unref0 (_tmp1_); +} + + +static gpointer _request_ref0 (gpointer self) { +	return self ? request_ref (self) : NULL; +} + + +static gpointer _scan_job_ref0 (gpointer self) { +	return self ? scan_job_ref (self) : NULL; +} + + +static gboolean scanner_handle_requests (Scanner* self) { +	gboolean result = FALSE; +	gboolean _tmp0_ = FALSE; +	gint request_count; +	g_return_val_if_fail (self != NULL, FALSE); +	if (self->priv->state == SCAN_STATE_IDLE) { +		_tmp0_ = self->priv->need_redetect; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		self->priv->state = SCAN_STATE_REDETECT; +	} +	request_count = 0; +	while (TRUE) { +		Request* request = NULL; +		gboolean _tmp1_ = FALSE; +		gboolean _tmp2_ = FALSE; +		if (self->priv->state == SCAN_STATE_IDLE) { +			_tmp2_ = request_count == 0; +		} else { +			_tmp2_ = FALSE; +		} +		if (_tmp2_) { +			_tmp1_ = TRUE; +		} else { +			gint _tmp3_; +			_tmp3_ = g_async_queue_length (self->priv->request_queue); +			_tmp1_ = _tmp3_ > 0; +		} +		if (_tmp1_) { +			gpointer _tmp4_ = NULL; +			_tmp4_ = g_async_queue_pop (self->priv->request_queue); +			_request_unref0 (request); +			request = (Request*) _tmp4_; +		} else { +			result = TRUE; +			_request_unref0 (request); +			return result; +		} +		g_debug ("scanner.vala:732: Processing request"); +		request_count++; +		if (IS_REQUEST_START_SCAN (request)) { +			RequestStartScan* _tmp5_; +			RequestStartScan* r; +			ScanJob* _tmp6_; +			_tmp5_ = _request_ref0 (REQUEST_START_SCAN (request)); +			r = _tmp5_; +			_tmp6_ = _scan_job_ref0 (r->job); +			self->priv->job_queue = g_list_append (self->priv->job_queue, _tmp6_); +			_request_unref0 (r); +		} else { +			if (IS_REQUEST_CANCEL (request)) { +				scanner_fail_scan (self, (gint) SANE_STATUS_CANCELLED, "Scan cancelled - do not report this error"); +			} else { +				if (IS_REQUEST_QUIT (request)) { +					scanner_close_device (self); +					result = FALSE; +					_request_unref0 (request); +					return result; +				} +			} +		} +		_request_unref0 (request); +	} +} + + +static void scanner_do_open (Scanner* self) { +	ScanJob* _tmp0_; +	ScanJob* job; +	gboolean _tmp1_ = FALSE; +	SANE_Handle _tmp4_; +	SANE_Status _tmp5_; +	SANE_Status status; +	gchar* _tmp6_ = NULL; +	gchar* _tmp7_; +	gchar* _tmp10_; +	g_return_if_fail (self != NULL); +	_tmp0_ = _scan_job_ref0 (SCAN_JOB ((ScanJob*) self->priv->job_queue->data)); +	job = _tmp0_; +	self->priv->line_count = 0; +	self->priv->pass_number = 0; +	self->priv->page_number = 0; +	self->priv->notified_page = -1; +	self->priv->option_index = (SANE_Int) 0; +	self->priv->br_x_option_index = (SANE_Int) 0; +	self->priv->br_y_option_index = (SANE_Int) 0; +	if (job->device == NULL) { +		_tmp1_ = self->priv->default_device != NULL; +	} else { +		_tmp1_ = FALSE; +	} +	if (_tmp1_) { +		gchar* _tmp2_; +		_tmp2_ = g_strdup (self->priv->default_device); +		_g_free0 (job->device); +		job->device = _tmp2_; +	} +	if (job->device == NULL) { +		const gchar* _tmp3_ = NULL; +		g_warning ("scanner.vala:769: No scan device available"); +		_tmp3_ = _ ("No scanners available.  Please connect a scanner."); +		scanner_fail_scan (self, 0, _tmp3_); +		_scan_job_unref0 (job); +		return; +	} +	if (self->priv->have_handle) { +		if (g_strcmp0 (self->priv->current_device, job->device) == 0) { +			self->priv->state = SCAN_STATE_GET_OPTION; +			_scan_job_unref0 (job); +			return; +		} +		sane_close (self->priv->handle); +		g_debug ("scanner.vala:786: sane_close ()"); +		self->priv->have_handle = FALSE; +	} +	_g_free0 (self->priv->current_device); +	self->priv->current_device = NULL; +	self->priv->have_handle = FALSE; +	_tmp5_ = sane_open (job->device, &_tmp4_); +	self->priv->handle = _tmp4_; +	status = _tmp5_; +	_tmp6_ = sane_status_to_string (status); +	_tmp7_ = _tmp6_; +	g_debug ("scanner.vala:794: sane_open (\"%s\") -> %s", job->device, _tmp7_); +	_g_free0 (_tmp7_); +	if (status != SANE_STATUS_GOOD) { +		const gchar* _tmp8_ = NULL; +		const gchar* _tmp9_ = NULL; +		_tmp8_ = sane_strstatus (status); +		g_warning ("scanner.vala:798: Unable to get open device: %s", _tmp8_); +		_tmp9_ = _ ("Unable to connect to scanner"); +		scanner_fail_scan (self, (gint) status, _tmp9_); +		_scan_job_unref0 (job); +		return; +	} +	self->priv->have_handle = TRUE; +	_tmp10_ = g_strdup (job->device); +	_g_free0 (self->priv->current_device); +	self->priv->current_device = _tmp10_; +	self->priv->state = SCAN_STATE_GET_OPTION; +	_scan_job_unref0 (job); +} + + +static void scanner_do_get_option (Scanner* self) { +	ScanJob* _tmp0_; +	ScanJob* job; +	const SANE_Option_Descriptor* _tmp1_ = NULL; +	const SANE_Option_Descriptor* option; +	SANE_Int index; +	g_return_if_fail (self != NULL); +	_tmp0_ = _scan_job_ref0 (SCAN_JOB ((ScanJob*) self->priv->job_queue->data)); +	job = _tmp0_; +	_tmp1_ = sane_get_option_descriptor (self->priv->handle, self->priv->option_index); +	option = _tmp1_; +	g_debug ("scanner.vala:815: sane_get_option_descriptor (%d)", (gint) self->priv->option_index); +	index = self->priv->option_index; +	self->priv->option_index++; +	if (option == NULL) { +		if (((gint) self->priv->br_x_option_index) != 0) { +			const SANE_Option_Descriptor* _tmp2_ = NULL; +			_tmp2_ = sane_get_option_descriptor (self->priv->handle, self->priv->br_x_option_index); +			option = _tmp2_; +			g_debug ("scanner.vala:825: sane_get_option_descriptor (%d)", (gint) self->priv->br_x_option_index); +			if (option->constraint_type == SANE_CONSTRAINT_RANGE) { +				if (option->type == SANE_TYPE_FIXED) { +					gdouble _tmp3_; +					_tmp3_ = SANE_UNFIX ((SANE_Fixed) option->constraint.range->max); +					scanner_set_fixed_option (self, self->priv->handle, option, self->priv->br_x_option_index, _tmp3_, NULL); +				} else { +					scanner_set_int_option (self, self->priv->handle, option, self->priv->br_x_option_index, (gint) option->constraint.range->max, NULL); +				} +			} +		} +		if (((gint) self->priv->br_y_option_index) != 0) { +			const SANE_Option_Descriptor* _tmp4_ = NULL; +			_tmp4_ = sane_get_option_descriptor (self->priv->handle, self->priv->br_y_option_index); +			option = _tmp4_; +			g_debug ("scanner.vala:837: sane_get_option_descriptor (%d)", (gint) self->priv->br_y_option_index); +			if (option->constraint_type == SANE_CONSTRAINT_RANGE) { +				if (option->type == SANE_TYPE_FIXED) { +					gdouble _tmp5_; +					_tmp5_ = SANE_UNFIX ((SANE_Fixed) option->constraint.range->max); +					scanner_set_fixed_option (self, self->priv->handle, option, self->priv->br_y_option_index, _tmp5_, NULL); +				} else { +					scanner_set_int_option (self, self->priv->handle, option, self->priv->br_y_option_index, (gint) option->constraint.range->max, NULL); +				} +			} +		} +		self->priv->state = SCAN_STATE_START; +		_scan_job_unref0 (job); +		return; +	} +	scanner_log_option (self, index, option); +	if (option->type == SANE_TYPE_GROUP) { +		_scan_job_unref0 (job); +		return; +	} +	if (((gint) (option->cap & SANE_CAP_INACTIVE)) != 0) { +		_scan_job_unref0 (job); +		return; +	} +	if (option->name == NULL) { +		_scan_job_unref0 (job); +		return; +	} +	if (g_strcmp0 (option->name, SANE_NAME_SCAN_RESOLUTION) == 0) { +		if (option->type == SANE_TYPE_FIXED) { +			gdouble _tmp6_; +			scanner_set_fixed_option (self, self->priv->handle, option, index, job->dpi, &_tmp6_); +			job->dpi = _tmp6_; +		} else { +			gint dpi = 0; +			gint _tmp7_; +			scanner_set_int_option (self, self->priv->handle, option, index, (gint) job->dpi, &_tmp7_); +			dpi = _tmp7_; +			job->dpi = (gdouble) dpi; +		} +	} else { +		if (g_strcmp0 (option->name, SANE_NAME_SCAN_SOURCE) == 0) { +			gchar* _tmp8_; +			const gchar* _tmp9_ = NULL; +			gchar* _tmp10_; +			gchar* _tmp11_; +			const gchar* _tmp12_ = NULL; +			gchar* _tmp13_; +			gchar* _tmp14_; +			gchar* _tmp15_; +			const gchar* _tmp16_ = NULL; +			gchar* _tmp17_; +			gchar** _tmp18_ = NULL; +			gchar** flatbed_sources; +			gint flatbed_sources_length1; +			gint _flatbed_sources_size_; +			gchar* _tmp19_; +			const gchar* _tmp20_ = NULL; +			gchar* _tmp21_; +			gchar* _tmp22_; +			gchar* _tmp23_; +			gchar* _tmp24_; +			gchar** _tmp25_ = NULL; +			gchar** adf_sources; +			gint adf_sources_length1; +			gint _adf_sources_size_; +			gchar* _tmp26_; +			const gchar* _tmp27_ = NULL; +			gchar* _tmp28_; +			gchar** _tmp29_ = NULL; +			gchar** adf_front_sources; +			gint adf_front_sources_length1; +			gint _adf_front_sources_size_; +			gchar* _tmp30_; +			const gchar* _tmp31_ = NULL; +			gchar* _tmp32_; +			gchar** _tmp33_ = NULL; +			gchar** adf_back_sources; +			gint adf_back_sources_length1; +			gint _adf_back_sources_size_; +			gchar* _tmp34_; +			const gchar* _tmp35_ = NULL; +			gchar* _tmp36_; +			gchar** _tmp37_ = NULL; +			gchar** adf_duplex_sources; +			gint adf_duplex_sources_length1; +			gint _adf_duplex_sources_size_; +			_tmp8_ = g_strdup ("Auto"); +			_tmp9_ = SANE_I18N ("Auto"); +			_tmp10_ = g_strdup (_tmp9_); +			_tmp11_ = g_strdup ("Flatbed"); +			_tmp12_ = SANE_I18N ("Flatbed"); +			_tmp13_ = g_strdup (_tmp12_); +			_tmp14_ = g_strdup ("FlatBed"); +			_tmp15_ = g_strdup ("Normal"); +			_tmp16_ = SANE_I18N ("Normal"); +			_tmp17_ = g_strdup (_tmp16_); +			_tmp18_ = g_new0 (gchar*, 7 + 1); +			_tmp18_[0] = _tmp8_; +			_tmp18_[1] = _tmp10_; +			_tmp18_[2] = _tmp11_; +			_tmp18_[3] = _tmp13_; +			_tmp18_[4] = _tmp14_; +			_tmp18_[5] = _tmp15_; +			_tmp18_[6] = _tmp17_; +			flatbed_sources = _tmp18_; +			flatbed_sources_length1 = 7; +			_flatbed_sources_size_ = flatbed_sources_length1; +			_tmp19_ = g_strdup ("Automatic Document Feeder"); +			_tmp20_ = SANE_I18N ("Automatic Document Feeder"); +			_tmp21_ = g_strdup (_tmp20_); +			_tmp22_ = g_strdup ("ADF"); +			_tmp23_ = g_strdup ("Automatic Document Feeder(left aligned)"); +			_tmp24_ = g_strdup ("Automatic Document Feeder(centrally aligned)"); +			_tmp25_ = g_new0 (gchar*, 5 + 1); +			_tmp25_[0] = _tmp19_; +			_tmp25_[1] = _tmp21_; +			_tmp25_[2] = _tmp22_; +			_tmp25_[3] = _tmp23_; +			_tmp25_[4] = _tmp24_; +			adf_sources = _tmp25_; +			adf_sources_length1 = 5; +			_adf_sources_size_ = adf_sources_length1; +			_tmp26_ = g_strdup ("ADF Front"); +			_tmp27_ = SANE_I18N ("ADF Front"); +			_tmp28_ = g_strdup (_tmp27_); +			_tmp29_ = g_new0 (gchar*, 2 + 1); +			_tmp29_[0] = _tmp26_; +			_tmp29_[1] = _tmp28_; +			adf_front_sources = _tmp29_; +			adf_front_sources_length1 = 2; +			_adf_front_sources_size_ = adf_front_sources_length1; +			_tmp30_ = g_strdup ("ADF Back"); +			_tmp31_ = SANE_I18N ("ADF Back"); +			_tmp32_ = g_strdup (_tmp31_); +			_tmp33_ = g_new0 (gchar*, 2 + 1); +			_tmp33_[0] = _tmp30_; +			_tmp33_[1] = _tmp32_; +			adf_back_sources = _tmp33_; +			adf_back_sources_length1 = 2; +			_adf_back_sources_size_ = adf_back_sources_length1; +			_tmp34_ = g_strdup ("ADF Duplex"); +			_tmp35_ = SANE_I18N ("ADF Duplex"); +			_tmp36_ = g_strdup (_tmp35_); +			_tmp37_ = g_new0 (gchar*, 2 + 1); +			_tmp37_[0] = _tmp34_; +			_tmp37_[1] = _tmp36_; +			adf_duplex_sources = _tmp37_; +			adf_duplex_sources_length1 = 2; +			_adf_duplex_sources_size_ = adf_duplex_sources_length1; +			switch (job->type) { +				case SCAN_TYPE_SINGLE: +				{ +					gboolean _tmp38_; +					_tmp38_ = scanner_set_default_option (self, self->priv->handle, option, index); +					if (!_tmp38_) { +						gboolean _tmp39_; +						_tmp39_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, flatbed_sources, flatbed_sources_length1, NULL); +						if (!_tmp39_) { +							g_warning ("scanner.vala:921: Unable to set single page source, please file a bug"); +						} +					} +					break; +				} +				case SCAN_TYPE_ADF_FRONT: +				{ +					gboolean _tmp40_; +					_tmp40_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, adf_front_sources, adf_front_sources_length1, NULL); +					if (!_tmp40_) { +						gboolean _tmp41_; +						_tmp41_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, adf_sources, adf_sources_length1, NULL); +						if (!(!_tmp41_)) { +							g_warning ("scanner.vala:926: Unable to set front ADF source, please file a bug"); +						} +					} +					break; +				} +				case SCAN_TYPE_ADF_BACK: +				{ +					gboolean _tmp42_; +					_tmp42_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, adf_back_sources, adf_back_sources_length1, NULL); +					if (!_tmp42_) { +						gboolean _tmp43_; +						_tmp43_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, adf_sources, adf_sources_length1, NULL); +						if (!_tmp43_) { +							g_warning ("scanner.vala:931: Unable to set back ADF source, please file a bug"); +						} +					} +					break; +				} +				case SCAN_TYPE_ADF_BOTH: +				{ +					gboolean _tmp44_; +					_tmp44_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, adf_duplex_sources, adf_duplex_sources_length1, NULL); +					if (!_tmp44_) { +						gboolean _tmp45_; +						_tmp45_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, adf_sources, adf_sources_length1, NULL); +						if (!_tmp45_) { +							g_warning ("scanner.vala:936: Unable to set duplex ADF source, please file a bug"); +						} +					} +					break; +				} +				default: +				break; +			} +			adf_duplex_sources = (_vala_array_free (adf_duplex_sources, adf_duplex_sources_length1, (GDestroyNotify) g_free), NULL); +			adf_back_sources = (_vala_array_free (adf_back_sources, adf_back_sources_length1, (GDestroyNotify) g_free), NULL); +			adf_front_sources = (_vala_array_free (adf_front_sources, adf_front_sources_length1, (GDestroyNotify) g_free), NULL); +			adf_sources = (_vala_array_free (adf_sources, adf_sources_length1, (GDestroyNotify) g_free), NULL); +			flatbed_sources = (_vala_array_free (flatbed_sources, flatbed_sources_length1, (GDestroyNotify) g_free), NULL); +		} else { +			if (g_strcmp0 (option->name, "duplex") == 0) { +				if (option->type == SANE_TYPE_BOOL) { +					scanner_set_bool_option (self, self->priv->handle, option, index, job->type == SCAN_TYPE_ADF_BOTH, NULL); +				} +			} else { +				if (g_strcmp0 (option->name, "batch-scan") == 0) { +					if (option->type == SANE_TYPE_BOOL) { +						scanner_set_bool_option (self, self->priv->handle, option, index, job->type != SCAN_TYPE_SINGLE, NULL); +					} +				} else { +					if (g_strcmp0 (option->name, SANE_NAME_BIT_DEPTH) == 0) { +						if (job->depth > 0) { +							scanner_set_int_option (self, self->priv->handle, option, index, job->depth, NULL); +						} +					} else { +						if (g_strcmp0 (option->name, SANE_NAME_SCAN_MODE) == 0) { +							gchar* _tmp46_; +							gchar* _tmp47_; +							gchar* _tmp48_; +							gchar** _tmp49_ = NULL; +							gchar** color_scan_modes; +							gint color_scan_modes_length1; +							gint _color_scan_modes_size_; +							gchar* _tmp50_; +							gchar* _tmp51_; +							gchar* _tmp52_; +							const gchar* _tmp53_ = NULL; +							gchar* _tmp54_; +							gchar* _tmp55_; +							gchar** _tmp56_ = NULL; +							gchar** gray_scan_modes; +							gint gray_scan_modes_length1; +							gint _gray_scan_modes_size_; +							gchar* _tmp57_; +							gchar* _tmp58_; +							gchar* _tmp59_; +							const gchar* _tmp60_ = NULL; +							gchar* _tmp61_; +							gchar* _tmp62_; +							const gchar* _tmp63_ = NULL; +							gchar* _tmp64_; +							gchar* _tmp65_; +							const gchar* _tmp66_ = NULL; +							gchar* _tmp67_; +							gchar* _tmp68_; +							gchar* _tmp69_; +							gchar* _tmp70_; +							gchar* _tmp71_; +							const gchar* _tmp72_ = NULL; +							gchar* _tmp73_; +							gchar* _tmp74_; +							gchar** _tmp75_ = NULL; +							gchar** lineart_scan_modes; +							gint lineart_scan_modes_length1; +							gint _lineart_scan_modes_size_; +							_tmp46_ = g_strdup (SANE_VALUE_SCAN_MODE_COLOR); +							_tmp47_ = g_strdup ("Color"); +							_tmp48_ = g_strdup ("24bit Color"); +							_tmp49_ = g_new0 (gchar*, 3 + 1); +							_tmp49_[0] = _tmp46_; +							_tmp49_[1] = _tmp47_; +							_tmp49_[2] = _tmp48_; +							color_scan_modes = _tmp49_; +							color_scan_modes_length1 = 3; +							_color_scan_modes_size_ = color_scan_modes_length1; +							_tmp50_ = g_strdup (SANE_VALUE_SCAN_MODE_GRAY); +							_tmp51_ = g_strdup ("Gray"); +							_tmp52_ = g_strdup ("Grayscale"); +							_tmp53_ = SANE_I18N ("Grayscale"); +							_tmp54_ = g_strdup (_tmp53_); +							_tmp55_ = g_strdup ("True Gray"); +							_tmp56_ = g_new0 (gchar*, 5 + 1); +							_tmp56_[0] = _tmp50_; +							_tmp56_[1] = _tmp51_; +							_tmp56_[2] = _tmp52_; +							_tmp56_[3] = _tmp54_; +							_tmp56_[4] = _tmp55_; +							gray_scan_modes = _tmp56_; +							gray_scan_modes_length1 = 5; +							_gray_scan_modes_size_ = gray_scan_modes_length1; +							_tmp57_ = g_strdup (SANE_VALUE_SCAN_MODE_LINEART); +							_tmp58_ = g_strdup ("Lineart"); +							_tmp59_ = g_strdup ("LineArt"); +							_tmp60_ = SANE_I18N ("LineArt"); +							_tmp61_ = g_strdup (_tmp60_); +							_tmp62_ = g_strdup ("Black & White"); +							_tmp63_ = SANE_I18N ("Black & White"); +							_tmp64_ = g_strdup (_tmp63_); +							_tmp65_ = g_strdup ("Binary"); +							_tmp66_ = SANE_I18N ("Binary"); +							_tmp67_ = g_strdup (_tmp66_); +							_tmp68_ = g_strdup ("Thresholded"); +							_tmp69_ = g_strdup (SANE_VALUE_SCAN_MODE_GRAY); +							_tmp70_ = g_strdup ("Gray"); +							_tmp71_ = g_strdup ("Grayscale"); +							_tmp72_ = SANE_I18N ("Grayscale"); +							_tmp73_ = g_strdup (_tmp72_); +							_tmp74_ = g_strdup ("True Gray"); +							_tmp75_ = g_new0 (gchar*, 14 + 1); +							_tmp75_[0] = _tmp57_; +							_tmp75_[1] = _tmp58_; +							_tmp75_[2] = _tmp59_; +							_tmp75_[3] = _tmp61_; +							_tmp75_[4] = _tmp62_; +							_tmp75_[5] = _tmp64_; +							_tmp75_[6] = _tmp65_; +							_tmp75_[7] = _tmp67_; +							_tmp75_[8] = _tmp68_; +							_tmp75_[9] = _tmp69_; +							_tmp75_[10] = _tmp70_; +							_tmp75_[11] = _tmp71_; +							_tmp75_[12] = _tmp73_; +							_tmp75_[13] = _tmp74_; +							lineart_scan_modes = _tmp75_; +							lineart_scan_modes_length1 = 14; +							_lineart_scan_modes_size_ = lineart_scan_modes_length1; +							switch (job->scan_mode) { +								case SCAN_MODE_COLOR: +								{ +									gboolean _tmp76_; +									_tmp76_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, color_scan_modes, color_scan_modes_length1, NULL); +									if (!_tmp76_) { +										g_warning ("scanner.vala:994: Unable to set Color mode, please file a bug"); +									} +									break; +								} +								case SCAN_MODE_GRAY: +								{ +									gboolean _tmp77_; +									_tmp77_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, gray_scan_modes, gray_scan_modes_length1, NULL); +									if (!_tmp77_) { +										g_warning ("scanner.vala:998: Unable to set Gray mode, please file a bug"); +									} +									break; +								} +								case SCAN_MODE_LINEART: +								{ +									gboolean _tmp78_; +									_tmp78_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, lineart_scan_modes, lineart_scan_modes_length1, NULL); +									if (!_tmp78_) { +										g_warning ("scanner.vala:1002: Unable to set Lineart mode, please file a bug"); +									} +									break; +								} +								default: +								{ +									break; +								} +							} +							lineart_scan_modes = (_vala_array_free (lineart_scan_modes, lineart_scan_modes_length1, (GDestroyNotify) g_free), NULL); +							gray_scan_modes = (_vala_array_free (gray_scan_modes, gray_scan_modes_length1, (GDestroyNotify) g_free), NULL); +							color_scan_modes = (_vala_array_free (color_scan_modes, color_scan_modes_length1, (GDestroyNotify) g_free), NULL); +						} else { +							if (g_strcmp0 (option->name, "compression") == 0) { +								const gchar* _tmp79_ = NULL; +								gchar* _tmp80_; +								const gchar* _tmp81_ = NULL; +								gchar* _tmp82_; +								gchar* _tmp83_; +								gchar* _tmp84_; +								gchar** _tmp85_ = NULL; +								gchar** disable_compression_names; +								gint disable_compression_names_length1; +								gint _disable_compression_names_size_; +								gboolean _tmp86_; +								_tmp79_ = SANE_I18N ("None"); +								_tmp80_ = g_strdup (_tmp79_); +								_tmp81_ = SANE_I18N ("none"); +								_tmp82_ = g_strdup (_tmp81_); +								_tmp83_ = g_strdup ("None"); +								_tmp84_ = g_strdup ("none"); +								_tmp85_ = g_new0 (gchar*, 4 + 1); +								_tmp85_[0] = _tmp80_; +								_tmp85_[1] = _tmp82_; +								_tmp85_[2] = _tmp83_; +								_tmp85_[3] = _tmp84_; +								disable_compression_names = _tmp85_; +								disable_compression_names_length1 = 4; +								_disable_compression_names_size_ = disable_compression_names_length1; +								_tmp86_ = scanner_set_constrained_string_option (self, self->priv->handle, option, index, disable_compression_names, disable_compression_names_length1, NULL); +								if (!_tmp86_) { +									g_warning ("scanner.vala:1020: Unable to disable compression, please file a bug"); +								} +								disable_compression_names = (_vala_array_free (disable_compression_names, disable_compression_names_length1, (GDestroyNotify) g_free), NULL); +							} else { +								if (g_strcmp0 (option->name, SANE_NAME_SCAN_BR_X) == 0) { +									self->priv->br_x_option_index = index; +								} else { +									if (g_strcmp0 (option->name, SANE_NAME_SCAN_BR_Y) == 0) { +										self->priv->br_y_option_index = index; +									} else { +										if (g_strcmp0 (option->name, SANE_NAME_PAGE_WIDTH) == 0) { +											if (((gdouble) job->page_width) > 0.0) { +												if (option->type == SANE_TYPE_FIXED) { +													scanner_set_fixed_option (self, self->priv->handle, option, index, job->page_width / 10.0, NULL); +												} else { +													scanner_set_int_option (self, self->priv->handle, option, index, job->page_width / 10, NULL); +												} +											} +										} else { +											if (g_strcmp0 (option->name, SANE_NAME_PAGE_HEIGHT) == 0) { +												if (((gdouble) job->page_height) > 0.0) { +													if (option->type == SANE_TYPE_FIXED) { +														scanner_set_fixed_option (self, self->priv->handle, option, index, job->page_height / 10.0, NULL); +													} else { +														scanner_set_int_option (self, self->priv->handle, option, index, job->page_height / 10, NULL); +													} +												} +											} +										} +									} +								} +							} +						} +					} +				} +			} +		} +	} +	if (g_strcmp0 (self->priv->current_device, "test") == 0) { +		if (g_strcmp0 (option->name, "hand-scanner") == 0) { +			scanner_set_bool_option (self, self->priv->handle, option, index, FALSE, NULL); +		} else { +			if (g_strcmp0 (option->name, "three-pass") == 0) { +				scanner_set_bool_option (self, self->priv->handle, option, index, FALSE, NULL); +			} else { +				if (g_strcmp0 (option->name, "test-picture") == 0) { +					scanner_set_string_option (self, self->priv->handle, option, index, "Color pattern", NULL); +				} else { +					if (g_strcmp0 (option->name, "read-delay") == 0) { +						scanner_set_bool_option (self, self->priv->handle, option, index, TRUE, NULL); +					} else { +						if (g_strcmp0 (option->name, "read-delay-duration") == 0) { +							scanner_set_int_option (self, self->priv->handle, option, index, 200000, NULL); +						} +					} +				} +			} +		} +	} +	_scan_job_unref0 (job); +} + + +static void scanner_do_complete_document (Scanner* self) { +	NotifyDocumentDone* _tmp0_ = NULL; +	NotifyDocumentDone* _tmp1_; +	g_return_if_fail (self != NULL); +	self->priv->job_queue = g_list_remove_link (self->priv->job_queue, self->priv->job_queue); +	self->priv->state = SCAN_STATE_IDLE; +	if (self->priv->job_queue != NULL) { +		self->priv->state = SCAN_STATE_OPEN; +		return; +	} +	_tmp0_ = notify_document_done_new (); +	_tmp1_ = _tmp0_; +	scanner_notify (self, (Notify*) _tmp1_); +	_notify_unref0 (_tmp1_); +	scanner_set_scanning (self, FALSE); +} + + +static void scanner_do_start (Scanner* self) { +	SANE_Status status = 0; +	NotifyExpectPage* _tmp0_ = NULL; +	NotifyExpectPage* _tmp1_; +	SANE_Status _tmp2_; +	gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	g_return_if_fail (self != NULL); +	_tmp0_ = notify_expect_page_new (); +	_tmp1_ = _tmp0_; +	scanner_notify (self, (Notify*) _tmp1_); +	_notify_unref0 (_tmp1_); +	_tmp2_ = sane_start (self->priv->handle); +	status = _tmp2_; +	_tmp3_ = sane_status_to_string (status); +	_tmp4_ = _tmp3_; +	g_debug ("scanner.vala:1090: sane_start (page=%d, pass=%d) -> %s", self->priv->page_number, self->priv->pass_number, _tmp4_); +	_g_free0 (_tmp4_); +	if (status == SANE_STATUS_GOOD) { +		self->priv->state = SCAN_STATE_GET_PARAMETERS; +	} else { +		if (status == SANE_STATUS_NO_DOCS) { +			scanner_do_complete_document (self); +		} else { +			const gchar* _tmp5_ = NULL; +			const gchar* _tmp6_ = NULL; +			_tmp5_ = sane_strstatus (status); +			g_warning ("scanner.vala:1097: Unable to start device: %s", _tmp5_); +			_tmp6_ = _ ("Unable to start scan"); +			scanner_fail_scan (self, (gint) status, _tmp6_); +		} +	} +} + + +static gchar* sane_frame_to_string (SANE_Frame frame) { +	gchar* result = NULL; +	switch (frame) { +		case SANE_FRAME_GRAY: +		{ +			gchar* _tmp0_; +			_tmp0_ = g_strdup ("SANE_FRAME_GRAY"); +			result = _tmp0_; +			return result; +		} +		case SANE_FRAME_RGB: +		{ +			gchar* _tmp1_; +			_tmp1_ = g_strdup ("SANE_FRAME_RGB"); +			result = _tmp1_; +			return result; +		} +		case SANE_FRAME_RED: +		{ +			gchar* _tmp2_; +			_tmp2_ = g_strdup ("SANE_FRAME_RED"); +			result = _tmp2_; +			return result; +		} +		case SANE_FRAME_GREEN: +		{ +			gchar* _tmp3_; +			_tmp3_ = g_strdup ("SANE_FRAME_GREEN"); +			result = _tmp3_; +			return result; +		} +		case SANE_FRAME_BLUE: +		{ +			gchar* _tmp4_; +			_tmp4_ = g_strdup ("SANE_FRAME_BLUE"); +			result = _tmp4_; +			return result; +		} +		default: +		{ +			gchar* _tmp5_ = NULL; +			_tmp5_ = g_strdup_printf ("SANE_FRAME(%d)", (gint) frame); +			result = _tmp5_; +			return result; +		} +	} +} + + +static void scanner_do_get_parameters (Scanner* self) { +	SANE_Parameters _tmp0_ = {0}; +	SANE_Status _tmp1_; +	SANE_Status status; +	gchar* _tmp2_ = NULL; +	gchar* _tmp3_; +	ScanJob* _tmp6_; +	ScanJob* job; +	const gchar* _tmp7_ = NULL; +	gchar* _tmp8_ = NULL; +	gchar* _tmp9_; +	ScanPageInfo* _tmp10_ = NULL; +	ScanPageInfo* info; +	gboolean _tmp11_ = FALSE; +	gboolean _tmp12_ = FALSE; +	gboolean _tmp13_ = FALSE; +	gint _tmp14_ = 0; +	gchar* _tmp15_; +	gint buffer_size; +	guchar* _tmp18_ = NULL; +	g_return_if_fail (self != NULL); +	_tmp1_ = sane_get_parameters (self->priv->handle, &_tmp0_); +	self->priv->parameters = _tmp0_; +	status = _tmp1_; +	_tmp2_ = sane_status_to_string (status); +	_tmp3_ = _tmp2_; +	g_debug ("scanner.vala:1107: sane_get_parameters () -> %s", _tmp3_); +	_g_free0 (_tmp3_); +	if (status != SANE_STATUS_GOOD) { +		const gchar* _tmp4_ = NULL; +		const gchar* _tmp5_ = NULL; +		_tmp4_ = sane_strstatus (status); +		g_warning ("scanner.vala:1110: Unable to get device parameters: %s", _tmp4_); +		_tmp5_ = _ ("Error communicating with scanner"); +		scanner_fail_scan (self, (gint) status, _tmp5_); +		return; +	} +	_tmp6_ = _scan_job_ref0 (SCAN_JOB ((ScanJob*) self->priv->job_queue->data)); +	job = _tmp6_; +	if (self->priv->parameters.last_frame) { +		_tmp7_ = "SANE_TRUE"; +	} else { +		_tmp7_ = "SANE_FALSE"; +	} +	_tmp8_ = sane_frame_to_string (self->priv->parameters.format); +	_tmp9_ = _tmp8_; +	g_debug ("scanner.vala:1119: Parameters: format=%s last_frame=%s bytes_per_line=" \ +"%d pixels_per_line=%d lines=%d depth=%d", _tmp9_, _tmp7_, self->priv->parameters.bytes_per_line, self->priv->parameters.pixels_per_line, self->priv->parameters.lines, self->priv->parameters.depth); +	_g_free0 (_tmp9_); +	_tmp10_ = scan_page_info_new (); +	info = _tmp10_; +	info->width = self->priv->parameters.pixels_per_line; +	info->height = self->priv->parameters.lines; +	info->depth = self->priv->parameters.depth; +	if (self->priv->parameters.depth == 8) { +		_tmp13_ = self->priv->parameters.format == SANE_FRAME_GRAY; +	} else { +		_tmp13_ = FALSE; +	} +	if (_tmp13_) { +		_tmp12_ = job->depth == 2; +	} else { +		_tmp12_ = FALSE; +	} +	if (_tmp12_) { +		_tmp11_ = job->scan_mode == SCAN_MODE_GRAY; +	} else { +		_tmp11_ = FALSE; +	} +	if (_tmp11_) { +		info->depth = job->depth; +	} +	if (self->priv->parameters.format == SANE_FRAME_GRAY) { +		_tmp14_ = 1; +	} else { +		_tmp14_ = 3; +	} +	info->n_channels = _tmp14_; +	info->dpi = job->dpi; +	_tmp15_ = g_strdup (self->priv->current_device); +	_g_free0 (info->device); +	info->device = _tmp15_; +	if (self->priv->page_number != self->priv->notified_page) { +		NotifyGotPageInfo* _tmp16_ = NULL; +		NotifyGotPageInfo* _tmp17_; +		_tmp16_ = notify_got_page_info_new (info); +		_tmp17_ = _tmp16_; +		scanner_notify (self, (Notify*) _tmp17_); +		_notify_unref0 (_tmp17_); +		self->priv->notified_page = self->priv->page_number; +	} +	buffer_size = self->priv->parameters.bytes_per_line + 1; +	_tmp18_ = g_new0 (guchar, buffer_size); +	self->priv->buffer = (g_free (self->priv->buffer), NULL); +	self->priv->buffer = _tmp18_; +	self->priv->buffer_length1 = buffer_size; +	self->priv->_buffer_size_ = self->priv->buffer_length1; +	self->priv->n_used = 0; +	self->priv->line_count = 0; +	self->priv->pass_number = 0; +	self->priv->state = SCAN_STATE_READ; +	_scan_page_info_unref0 (info); +	_scan_job_unref0 (job); +} + + +static void scanner_do_complete_page (Scanner* self) { +	NotifyPageDone* _tmp0_ = NULL; +	NotifyPageDone* _tmp1_; +	ScanJob* _tmp2_; +	ScanJob* job; +	g_return_if_fail (self != NULL); +	_tmp0_ = notify_page_done_new (); +	_tmp1_ = _tmp0_; +	scanner_notify (self, (Notify*) _tmp1_); +	_notify_unref0 (_tmp1_); +	_tmp2_ = _scan_job_ref0 (SCAN_JOB ((ScanJob*) self->priv->job_queue->data)); +	job = _tmp2_; +	if (!self->priv->parameters.last_frame) { +		self->priv->pass_number++; +		self->priv->state = SCAN_STATE_START; +		_scan_job_unref0 (job); +		return; +	} +	if (job->type != SCAN_TYPE_SINGLE) { +		NotifyPageDone* _tmp3_ = NULL; +		NotifyPageDone* _tmp4_; +		self->priv->page_number++; +		self->priv->pass_number = 0; +		_tmp3_ = notify_page_done_new (); +		_tmp4_ = _tmp3_; +		scanner_notify (self, (Notify*) _tmp4_); +		_notify_unref0 (_tmp4_); +		self->priv->state = SCAN_STATE_START; +		_scan_job_unref0 (job); +		return; +	} +	sane_cancel (self->priv->handle); +	g_debug ("scanner.vala:1179: sane_cancel ()"); +	scanner_do_complete_document (self); +	_scan_job_unref0 (job); +} + + +static void scanner_do_read (Scanner* self) { +	ScanJob* _tmp0_; +	ScanJob* job; +	gint n_to_read; +	SANE_Int n_read; +	guchar* b; +	SANE_Int _tmp1_; +	SANE_Status _tmp2_; +	SANE_Status status; +	gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	gboolean full_read; +	gboolean _tmp8_ = FALSE; +	g_return_if_fail (self != NULL); +	_tmp0_ = _scan_job_ref0 (SCAN_JOB ((ScanJob*) self->priv->job_queue->data)); +	job = _tmp0_; +	n_to_read = self->priv->buffer_length1 - self->priv->n_used; +	b = (guchar*) self->priv->buffer; +	_tmp2_ = sane_read (self->priv->handle, (guint8*) (b + self->priv->n_used), (SANE_Int) n_to_read, &_tmp1_); +	n_read = _tmp1_; +	status = _tmp2_; +	_tmp3_ = sane_status_to_string (status); +	_tmp4_ = _tmp3_; +	g_debug ("scanner.vala:1194: sane_read (%d) -> (%s, %d)", n_to_read, _tmp4_, (gint) n_read); +	_g_free0 (_tmp4_); +	if (status == SANE_STATUS_EOF) { +		gboolean _tmp5_ = FALSE; +		if (self->priv->parameters.lines > 0) { +			_tmp5_ = self->priv->line_count != self->priv->parameters.lines; +		} else { +			_tmp5_ = FALSE; +		} +		if (_tmp5_) { +			g_warning ("scanner.vala:1200: Scan completed with %d lines, expected %d lines", self->priv->parameters.lines, self->priv->parameters.lines); +		} +		if (self->priv->n_used > 0) { +			g_warning ("scanner.vala:1202: Scan complete with %d bytes of unused data", self->priv->n_used); +		} +		scanner_do_complete_page (self); +		_scan_job_unref0 (job); +		return; +	} +	if (status != SANE_STATUS_GOOD) { +		const gchar* _tmp6_ = NULL; +		const gchar* _tmp7_ = NULL; +		_tmp6_ = sane_strstatus (status); +		g_warning ("scanner.vala:1210: Unable to read frame from device: %s", _tmp6_); +		_tmp7_ = _ ("Error communicating with scanner"); +		scanner_fail_scan (self, (gint) status, _tmp7_); +		_scan_job_unref0 (job); +		return; +	} +	full_read = FALSE; +	if (self->priv->n_used == 0) { +		_tmp8_ = ((gint) n_read) == self->priv->buffer_length1; +	} else { +		_tmp8_ = FALSE; +	} +	if (_tmp8_) { +		full_read = TRUE; +	} +	self->priv->n_used = self->priv->n_used + n_read; +	if (self->priv->n_used >= self->priv->parameters.bytes_per_line) { +		ScanLine* _tmp9_ = NULL; +		ScanLine* line; +		guchar* _tmp10_; +		gint _tmp11_; +		gint buffer_size; +		guchar* _tmp12_ = NULL; +		gint n_remaining; +		gboolean _tmp14_ = FALSE; +		gboolean _tmp15_ = FALSE; +		gboolean _tmp16_ = FALSE; +		NotifyGotLine* _tmp19_ = NULL; +		NotifyGotLine* _tmp20_; +		_tmp9_ = scan_line_new (); +		line = _tmp9_; +		switch (self->priv->parameters.format) { +			case SANE_FRAME_GRAY: +			{ +				line->channel = 0; +				break; +			} +			case SANE_FRAME_RGB: +			{ +				line->channel = -1; +				break; +			} +			case SANE_FRAME_RED: +			{ +				line->channel = 0; +				break; +			} +			case SANE_FRAME_GREEN: +			{ +				line->channel = 1; +				break; +			} +			case SANE_FRAME_BLUE: +			{ +				line->channel = 2; +				break; +			} +			default: +			break; +		} +		line->width = self->priv->parameters.pixels_per_line; +		line->depth = self->priv->parameters.depth; +		_tmp10_ = self->priv->buffer; +		_tmp11_ = self->priv->buffer_length1; +		self->priv->buffer = NULL; +		line->data = (g_free (line->data), NULL); +		line->data = _tmp10_; +		line->data_length1 = _tmp11_; +		line->data_length = self->priv->parameters.bytes_per_line; +		line->number = self->priv->line_count; +		line->n_lines = self->priv->n_used / line->data_length; +		self->priv->line_count = self->priv->line_count + line->n_lines; +		buffer_size = self->priv->buffer_length1; +		if (full_read) { +			buffer_size = buffer_size + self->priv->parameters.bytes_per_line; +		} +		_tmp12_ = g_new0 (guchar, buffer_size); +		self->priv->buffer = (g_free (self->priv->buffer), NULL); +		self->priv->buffer = _tmp12_; +		self->priv->buffer_length1 = buffer_size; +		self->priv->_buffer_size_ = self->priv->buffer_length1; +		n_remaining = self->priv->n_used - (line->n_lines * line->data_length); +		self->priv->n_used = 0; +		{ +			gint i; +			i = 0; +			{ +				gboolean _tmp13_; +				_tmp13_ = TRUE; +				while (TRUE) { +					if (!_tmp13_) { +						i++; +					} +					_tmp13_ = FALSE; +					if (!(i < n_remaining)) { +						break; +					} +					self->priv->buffer[i] = line->data[i + (line->n_lines * line->data_length)]; +					self->priv->n_used++; +				} +			} +		} +		if (self->priv->parameters.depth == 8) { +			_tmp16_ = self->priv->parameters.format == SANE_FRAME_GRAY; +		} else { +			_tmp16_ = FALSE; +		} +		if (_tmp16_) { +			_tmp15_ = job->depth == 2; +		} else { +			_tmp15_ = FALSE; +		} +		if (_tmp15_) { +			_tmp14_ = job->scan_mode == SCAN_MODE_GRAY; +		} else { +			_tmp14_ = FALSE; +		} +		if (_tmp14_) { +			guchar block; +			gint write_offset; +			gint block_shift; +			block = (guchar) 0; +			write_offset = 0; +			block_shift = 6; +			{ +				gint i; +				i = 0; +				{ +					gboolean _tmp17_; +					_tmp17_ = TRUE; +					while (TRUE) { +						gint offset; +						if (!_tmp17_) { +							i++; +						} +						_tmp17_ = FALSE; +						if (!(i < line->n_lines)) { +							break; +						} +						offset = i * line->data_length; +						{ +							gint x; +							x = 0; +							{ +								gboolean _tmp18_; +								_tmp18_ = TRUE; +								while (TRUE) { +									guchar p; +									guchar sample = '\0'; +									if (!_tmp18_) { +										x++; +									} +									_tmp18_ = FALSE; +									if (!(x < line->width)) { +										break; +									} +									p = line->data[offset + x]; +									if (((gint) p) >= 192) { +										sample = (guchar) 3; +									} else { +										if (((gint) p) >= 128) { +											sample = (guchar) 2; +										} else { +											if (((gint) p) >= 64) { +												sample = (guchar) 1; +											} else { +												sample = (guchar) 0; +											} +										} +									} +									block = block | (sample << block_shift); +									if (block_shift == 0) { +										line->data[write_offset] = block; +										write_offset++; +										block = (guchar) 0; +										block_shift = 6; +									} else { +										block_shift = block_shift - 2; +									} +								} +							} +						} +						if (block_shift != 6) { +							line->data[write_offset] = block; +							write_offset++; +							block = (guchar) 0; +							block_shift = 6; +						} +					} +				} +			} +			line->data_length = ((line->width * 2) + 7) / 8; +		} +		_tmp19_ = notify_got_line_new (line); +		_tmp20_ = _tmp19_; +		scanner_notify (self, (Notify*) _tmp20_); +		_notify_unref0 (_tmp20_); +		_scan_line_unref0 (line); +	} +	_scan_job_unref0 (job); +} + + +static void _scanner_authorization_cb_sane_authcallback (const gchar* resource, gchar* username, gchar* password) { +	scanner_authorization_cb (resource, username, -1, password, -1); +} + + +static void* scanner_scan_thread (Scanner* self) { +	void* result = NULL; +	SANE_Int version_code; +	SANE_Int _tmp0_; +	SANE_Status _tmp1_; +	SANE_Status status; +	gchar* _tmp2_ = NULL; +	gchar* _tmp3_; +	gint _tmp5_; +	gint _tmp6_; +	gint _tmp7_; +	g_return_val_if_fail (self != NULL, NULL); +	self->priv->state = SCAN_STATE_IDLE; +	_tmp1_ = sane_init (&_tmp0_, _scanner_authorization_cb_sane_authcallback); +	version_code = _tmp0_; +	status = _tmp1_; +	_tmp2_ = sane_status_to_string (status); +	_tmp3_ = _tmp2_; +	g_debug ("scanner.vala:1327: sane_init () -> %s", _tmp3_); +	_g_free0 (_tmp3_); +	if (status != SANE_STATUS_GOOD) { +		const gchar* _tmp4_ = NULL; +		_tmp4_ = sane_strstatus (status); +		g_warning ("scanner.vala:1330: Unable to initialize SANE backend: %s", _tmp4_); +		result = NULL; +		return result; +	} +	_tmp5_ = SANE_VERSION_MAJOR (version_code); +	_tmp6_ = SANE_VERSION_MINOR (version_code); +	_tmp7_ = SANE_VERSION_BUILD (version_code); +	g_debug ("scanner.vala:1333: SANE version %d.%d.%d", _tmp5_, _tmp6_, _tmp7_); +	scanner_redetect (self); +	while (TRUE) { +		gboolean _tmp8_; +		_tmp8_ = scanner_handle_requests (self); +		if (!_tmp8_) { +			break; +		} +		switch (self->priv->state) { +			case SCAN_STATE_IDLE: +			{ +				if (self->priv->job_queue != NULL) { +					scanner_set_scanning (self, TRUE); +					self->priv->state = SCAN_STATE_OPEN; +				} +				break; +			} +			case SCAN_STATE_REDETECT: +			{ +				scanner_do_redetect (self); +				break; +			} +			case SCAN_STATE_OPEN: +			{ +				scanner_do_open (self); +				break; +			} +			case SCAN_STATE_GET_OPTION: +			{ +				scanner_do_get_option (self); +				break; +			} +			case SCAN_STATE_START: +			{ +				scanner_do_start (self); +				break; +			} +			case SCAN_STATE_GET_PARAMETERS: +			{ +				scanner_do_get_parameters (self); +				break; +			} +			case SCAN_STATE_READ: +			{ +				scanner_do_read (self); +				break; +			} +			default: +			break; +		} +	} +	result = NULL; +	return result; +} + + +static gpointer _scanner_scan_thread_gthread_func (gpointer self) { +	gpointer result; +	result = scanner_scan_thread (self); +	return result; +} + + +void scanner_start (Scanner* self) { +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	{ +		GThread* _tmp0_ = NULL; +		GThread* _tmp1_; +		_tmp0_ = g_thread_create (_scanner_scan_thread_gthread_func, self, TRUE, &_inner_error_); +		_tmp1_ = _tmp0_; +		if (_inner_error_ != NULL) { +			goto __catch9_g_error; +		} +		self->priv->thread = _tmp1_; +	} +	goto __finally9; +	__catch9_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_critical ("scanner.vala:1384: Unable to create thread: %s", e->message); +		_g_error_free0 (e); +	} +	__finally9: +	if (_inner_error_ != NULL) { +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +} + + +void scanner_redetect (Scanner* self) { +	RequestRedetect* _tmp0_ = NULL; +	g_return_if_fail (self != NULL); +	if (self->priv->need_redetect) { +		return; +	} +	self->priv->need_redetect = TRUE; +	g_debug ("scanner.vala:1394: Requesting redetection of scan devices"); +	_tmp0_ = request_redetect_new (); +	g_async_queue_push (self->priv->request_queue, (Request*) _tmp0_); +} + + +gboolean scanner_is_scanning (Scanner* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	result = self->priv->scanning; +	return result; +} + + +static gchar* scanner_get_scan_mode_string (Scanner* self, ScanMode mode) { +	gchar* result = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	switch (mode) { +		case SCAN_MODE_DEFAULT: +		{ +			gchar* _tmp0_; +			_tmp0_ = g_strdup ("ScanMode.DEFAULT"); +			result = _tmp0_; +			return result; +		} +		case SCAN_MODE_COLOR: +		{ +			gchar* _tmp1_; +			_tmp1_ = g_strdup ("ScanMode.COLOR"); +			result = _tmp1_; +			return result; +		} +		case SCAN_MODE_GRAY: +		{ +			gchar* _tmp2_; +			_tmp2_ = g_strdup ("ScanMode.GRAY"); +			result = _tmp2_; +			return result; +		} +		case SCAN_MODE_LINEART: +		{ +			gchar* _tmp3_; +			_tmp3_ = g_strdup ("ScanMode.LINEART"); +			result = _tmp3_; +			return result; +		} +		default: +		{ +			gchar* _tmp4_ = NULL; +			_tmp4_ = g_strdup_printf ("%d", (gint) mode); +			result = _tmp4_; +			return result; +		} +	} +} + + +static gchar* scanner_get_scan_type_string (Scanner* self, ScanType type) { +	gchar* result = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	switch (type) { +		case SCAN_TYPE_SINGLE: +		{ +			gchar* _tmp0_; +			_tmp0_ = g_strdup ("ScanType.SINGLE"); +			result = _tmp0_; +			return result; +		} +		case SCAN_TYPE_ADF_FRONT: +		{ +			gchar* _tmp1_; +			_tmp1_ = g_strdup ("ScanType.ADF_FRONT"); +			result = _tmp1_; +			return result; +		} +		case SCAN_TYPE_ADF_BACK: +		{ +			gchar* _tmp2_; +			_tmp2_ = g_strdup ("ScanType.ADF_BACK"); +			result = _tmp2_; +			return result; +		} +		case SCAN_TYPE_ADF_BOTH: +		{ +			gchar* _tmp3_; +			_tmp3_ = g_strdup ("ScanType.ADF_BOTH"); +			result = _tmp3_; +			return result; +		} +		default: +		{ +			gchar* _tmp4_ = NULL; +			_tmp4_ = g_strdup_printf ("%d", (gint) type); +			result = _tmp4_; +			return result; +		} +	} +} + + +void scanner_scan (Scanner* self, const gchar* device, ScanOptions* options) { +	const gchar* _tmp0_ = NULL; +	gchar* _tmp1_ = NULL; +	gchar* _tmp2_; +	gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	RequestStartScan* _tmp5_ = NULL; +	RequestStartScan* request; +	ScanJob* _tmp6_ = NULL; +	gchar* _tmp7_; +	Request* _tmp8_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (options != NULL); +	if (device != NULL) { +		_tmp0_ = device; +	} else { +		_tmp0_ = "(null)"; +	} +	_tmp1_ = scanner_get_scan_mode_string (self, options->scan_mode); +	_tmp2_ = _tmp1_; +	_tmp3_ = scanner_get_scan_type_string (self, options->type); +	_tmp4_ = _tmp3_; +	g_debug ("scanner.vala:1440: Scanner.scan (\"%s\", dpi=%d, scan_mode=%s, depth=%" \ +"d, type=%s, paper_width=%d, paper_height=%d)", _tmp0_, options->dpi, _tmp2_, options->depth, _tmp4_, options->paper_width, options->paper_height); +	_g_free0 (_tmp4_); +	_g_free0 (_tmp2_); +	_tmp5_ = request_start_scan_new (); +	request = _tmp5_; +	_tmp6_ = scan_job_new (); +	_scan_job_unref0 (request->job); +	request->job = _tmp6_; +	_tmp7_ = g_strdup (device); +	_g_free0 (request->job->device); +	request->job->device = _tmp7_; +	request->job->dpi = (gdouble) options->dpi; +	request->job->scan_mode = options->scan_mode; +	request->job->depth = options->depth; +	request->job->type = options->type; +	request->job->page_width = options->paper_width; +	request->job->page_height = options->paper_height; +	_tmp8_ = _request_ref0 ((Request*) request); +	g_async_queue_push (self->priv->request_queue, _tmp8_); +	_request_unref0 (request); +} + + +void scanner_cancel (Scanner* self) { +	RequestCancel* _tmp0_ = NULL; +	g_return_if_fail (self != NULL); +	_tmp0_ = request_cancel_new (); +	g_async_queue_push (self->priv->request_queue, (Request*) _tmp0_); +} + + +void scanner_free (Scanner* self) { +	RequestQuit* _tmp0_ = NULL; +	g_return_if_fail (self != NULL); +	g_debug ("scanner.vala:1462: Stopping scan thread"); +	_tmp0_ = request_quit_new (); +	g_async_queue_push (self->priv->request_queue, (Request*) _tmp0_); +	if (self->priv->thread != NULL) { +		g_thread_join (self->priv->thread); +	} +	sane_exit (); +	g_debug ("scanner.vala:1470: sane_exit ()"); +} + + +static void g_cclosure_user_marshal_VOID__SCAN_PAGE_INFO (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { +	typedef void (*GMarshalFunc_VOID__SCAN_PAGE_INFO) (gpointer data1, gpointer arg_1, gpointer data2); +	register GMarshalFunc_VOID__SCAN_PAGE_INFO callback; +	register GCClosure * cc; +	register gpointer data1; +	register gpointer data2; +	cc = (GCClosure *) closure; +	g_return_if_fail (n_param_values == 2); +	if (G_CCLOSURE_SWAP_DATA (closure)) { +		data1 = closure->data; +		data2 = param_values->data[0].v_pointer; +	} else { +		data1 = param_values->data[0].v_pointer; +		data2 = closure->data; +	} +	callback = (GMarshalFunc_VOID__SCAN_PAGE_INFO) (marshal_data ? marshal_data : cc->callback); +	callback (data1, value_get_scan_page_info (param_values + 1), data2); +} + + +static void g_cclosure_user_marshal_VOID__SCAN_LINE (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { +	typedef void (*GMarshalFunc_VOID__SCAN_LINE) (gpointer data1, gpointer arg_1, gpointer data2); +	register GMarshalFunc_VOID__SCAN_LINE callback; +	register GCClosure * cc; +	register gpointer data1; +	register gpointer data2; +	cc = (GCClosure *) closure; +	g_return_if_fail (n_param_values == 2); +	if (G_CCLOSURE_SWAP_DATA (closure)) { +		data1 = closure->data; +		data2 = param_values->data[0].v_pointer; +	} else { +		data1 = param_values->data[0].v_pointer; +		data2 = closure->data; +	} +	callback = (GMarshalFunc_VOID__SCAN_LINE) (marshal_data ? marshal_data : cc->callback); +	callback (data1, value_get_scan_line (param_values + 1), data2); +} + + +static void g_cclosure_user_marshal_VOID__INT_STRING (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { +	typedef void (*GMarshalFunc_VOID__INT_STRING) (gpointer data1, gint arg_1, const char* arg_2, gpointer data2); +	register GMarshalFunc_VOID__INT_STRING callback; +	register GCClosure * cc; +	register gpointer data1; +	register gpointer data2; +	cc = (GCClosure *) closure; +	g_return_if_fail (n_param_values == 3); +	if (G_CCLOSURE_SWAP_DATA (closure)) { +		data1 = closure->data; +		data2 = param_values->data[0].v_pointer; +	} else { +		data1 = param_values->data[0].v_pointer; +		data2 = closure->data; +	} +	callback = (GMarshalFunc_VOID__INT_STRING) (marshal_data ? marshal_data : cc->callback); +	callback (data1, g_value_get_int (param_values + 1), g_value_get_string (param_values + 2), data2); +} + + +static void value_scanner_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_scanner_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		scanner_unref (value->data[0].v_pointer); +	} +} + + +static void value_scanner_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = scanner_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_scanner_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_scanner_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Scanner* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = scanner_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_scanner_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Scanner** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = scanner_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_scanner (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecScanner* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SCANNER), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_scanner (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCANNER), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_scanner (GValue* value, gpointer v_object) { +	Scanner* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCANNER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCANNER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		scanner_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scanner_unref (old); +	} +} + + +void value_take_scanner (GValue* value, gpointer v_object) { +	Scanner* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SCANNER)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SCANNER)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		scanner_unref (old); +	} +} + + +static void scanner_class_init (ScannerClass * klass) { +	scanner_parent_class = g_type_class_peek_parent (klass); +	SCANNER_CLASS (klass)->finalize = scanner_finalize; +	g_type_class_add_private (klass, sizeof (ScannerPrivate)); +	g_signal_new ("update_devices", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); +	g_signal_new ("request_authorization", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); +	g_signal_new ("expect_page", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("got_page_info", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__SCAN_PAGE_INFO, G_TYPE_NONE, 1, TYPE_SCAN_PAGE_INFO); +	g_signal_new ("got_line", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__SCAN_LINE, G_TYPE_NONE, 1, TYPE_SCAN_LINE); +	g_signal_new ("scan_failed", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__INT_STRING, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING); +	g_signal_new ("page_done", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("document_done", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("scanning_changed", TYPE_SCANNER, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + + +static void scanner_instance_init (Scanner * self) { +	self->priv = SCANNER_GET_PRIVATE (self); +	self->ref_count = 1; +} + + +static void scanner_finalize (Scanner* obj) { +	Scanner * self; +	self = SCANNER (obj); +	_g_async_queue_unref0 (self->priv->request_queue); +	_g_async_queue_unref0 (self->priv->notify_queue); +	_g_async_queue_unref0 (self->priv->authorize_queue); +	_g_free0 (self->priv->default_device); +	__g_list_free__scan_job_unref0_0 (self->priv->job_queue); +	_g_free0 (self->priv->current_device); +	self->priv->buffer = (g_free (self->priv->buffer), NULL); +} + + +GType scanner_get_type (void) { +	static volatile gsize scanner_type_id__volatile = 0; +	if (g_once_init_enter (&scanner_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_scanner_init, value_scanner_free_value, value_scanner_copy_value, value_scanner_peek_pointer, "p", value_scanner_collect_value, "p", value_scanner_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ScannerClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) scanner_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Scanner), 0, (GInstanceInitFunc) scanner_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType scanner_type_id; +		scanner_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Scanner", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&scanner_type_id__volatile, scanner_type_id); +	} +	return scanner_type_id__volatile; +} + + +gpointer scanner_ref (gpointer instance) { +	Scanner* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void scanner_unref (gpointer instance) { +	Scanner* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SCANNER_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	if ((array != NULL) && (destroy_func != NULL)) { +		int i; +		for (i = 0; i < array_length; i = i + 1) { +			if (((gpointer*) array)[i] != NULL) { +				destroy_func (((gpointer*) array)[i]); +			} +		} +	} +} + + +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	_vala_array_destroy (array, array_length, destroy_func); +	g_free (array); +} + + + diff --git a/src/scanner.h b/src/scanner.h deleted file mode 100644 index 72a4ffd..0000000 --- a/src/scanner.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2009 Canonical Ltd. - * Author: Robert Ancell <robert.ancell@canonical.com> - *  - * This program 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 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _SCANNER_H_ -#define _SCANNER_H_ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define SCANNER_TYPE  (scanner_get_type ()) -#define SCANNER(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCANNER_TYPE, Scanner)) - - -typedef struct -{ -    gchar *name, *label; -} ScanDevice; - -typedef struct -{ -    /* Width, height in pixels */ -    gint width, height; - -    /* Bit depth */ -    gint depth; - -    /* Number of colour channels */ -    gint n_channels; - -    /* Resolution */ -    gdouble dpi; - -    /* The device this page came from */ -    gchar *device; -} ScanPageInfo; - -typedef struct -{ -    /* Line number */ -    gint number; -   -    /* Number of lines in this packet */ -    gint n_lines; - -    /* Width in pixels and format */ -    gint width, depth; - -    /* Channel for this line or -1 for all channels */ -    gint channel; -     -    /* Raw line data */ -    guchar *data; -    gsize data_length; -} ScanLine; - -typedef enum -{ -    SCAN_MODE_DEFAULT,     -    SCAN_MODE_COLOR, -    SCAN_MODE_GRAY, -    SCAN_MODE_LINEART -} ScanMode; - -typedef enum -{ -    SCAN_SINGLE, -    SCAN_ADF_FRONT, -    SCAN_ADF_BACK, -    SCAN_ADF_BOTH -} ScanType; - -typedef struct -{ -    gint dpi; -    ScanMode scan_mode; -    gint depth; -    ScanType type; -    gint paper_width, paper_height; -} ScanOptions; - -typedef struct ScannerPrivate ScannerPrivate; - -typedef struct -{ -    GObject         parent_instance; -    ScannerPrivate *priv; -} Scanner; - -typedef struct -{ -    GObjectClass parent_class; - -    void (*update_devices) (Scanner *scanner, GList *devices); -    void (*authorize) (Scanner *scanner, const gchar *resource); -    void (*expect_page) (Scanner *scanner); -    void (*got_page_info) (Scanner *scanner, ScanPageInfo *info); -    void (*got_line) (Scanner *scanner, ScanLine *line); -    void (*scan_failed) (Scanner *scanner, GError *error); -    void (*page_done) (Scanner *scanner); -    void (*document_done) (Scanner *scanner); -    void (*scanning_changed) (Scanner *scanner); -} ScannerClass; - - -GType scanner_get_type (void); - -Scanner *scanner_new (void); - -void scanner_start (Scanner *scanner); - -void scanner_authorize (Scanner *scanner, const gchar *username, const gchar *password); - -void scanner_redetect (Scanner *scanner); - -gboolean scanner_is_scanning (Scanner *scanner); - -void scanner_scan (Scanner *scanner, const char *device, ScanOptions *options); - -void scanner_cancel (Scanner *scanner); - -void scanner_free (Scanner *scanner); - -#endif /* _SCANNER_H_ */ diff --git a/src/scanner.vala b/src/scanner.vala new file mode 100644 index 0000000..02aa69d --- /dev/null +++ b/src/scanner.vala @@ -0,0 +1,1472 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +/* TODO: Could indicate the start of the next page immediately after the last page is received (i.e. before the sane_cancel()) */ + +public class ScanDevice +{ +    public string name; +    public string label; +} + +public class ScanPageInfo +{ +    /* Width, height in pixels */ +    public int width; +    public int height; + +    /* Bit depth */ +    public int depth; + +    /* Number of colour channels */ +    public int n_channels; + +    /* Resolution */ +    public double dpi; + +    /* The device this page came from */ +    public string device; +} + +public class ScanLine +{ +    /* Line number */ +    public int number; + +    /* Number of lines in this packet */ +    public int n_lines; + +    /* Width in pixels and format */ +    public int width; +    public int depth; + +    /* Channel for this line or -1 for all channels */ +    public int channel; + +    /* Raw line data */ +    public uchar[] data; +    public int data_length; +} + +public enum ScanMode +{ +    DEFAULT, +    COLOR, +    GRAY, +    LINEART +} + +public enum ScanType +{ +    SINGLE, +    ADF_FRONT, +    ADF_BACK, +    ADF_BOTH +} + +public class ScanOptions +{ +    public int dpi; +    public ScanMode scan_mode; +    public int depth; +    public ScanType type; +    public int paper_width; +    public int paper_height; +} + +private class ScanJob +{ +    public string device; +    public double dpi; +    public ScanMode scan_mode; +    public int depth; +    public ScanType type; +    public int page_width; +    public int page_height; +} + +private class Request {} + +private class RequestRedetect : Request {} + +private class RequestCancel : Request {} + +private class RequestStartScan : Request +{ +    public ScanJob job; +} + +private class RequestQuit : Request {} + +private class Credentials +{ +    public string username; +    public string password; +} + +private enum ScanState +{ +    IDLE = 0, +    REDETECT, +    OPEN, +    GET_OPTION, +    START, +    GET_PARAMETERS, +    READ +} + +private class Notify +{ +    public virtual void run (Scanner scanner) {} +} + +private class NotifyScanningChanged : Notify +{ +    public override void run (Scanner scanner) { scanner.scanning_changed (); } +} + +private class NotifyUpdateDevices : Notify +{ +    public NotifyUpdateDevices (owned List<ScanDevice> devices) { this.devices = (owned) devices; } +    private List<ScanDevice> devices; +    public override void run (Scanner scanner) { scanner.update_devices (devices); } +} + +private class NotifyRequestAuthorization : Notify +{ +    public NotifyRequestAuthorization (string resource) { this.resource = resource; } +    private string resource; +    public override void run (Scanner scanner) { scanner.request_authorization (resource); } +} + +private class NotifyScanFailed : Notify +{ +    public NotifyScanFailed (int error_code, string error_string) { this.error_code = error_code; this.error_string = error_string; } +    private int error_code; +    private string error_string; +    public override void run (Scanner scanner) { scanner.scan_failed (error_code, error_string); } +} + +private class NotifyDocumentDone : Notify +{ +    public override void run (Scanner scanner) { scanner.document_done (); } +} + +private class NotifyExpectPage : Notify +{ +    public override void run (Scanner scanner) { scanner.expect_page (); } +} + +private class NotifyGotPageInfo : Notify +{ +    public NotifyGotPageInfo (ScanPageInfo info) { this.info = info; } +    private ScanPageInfo info; +    public override void run (Scanner scanner) { scanner.got_page_info (info); } +} + +private class NotifyPageDone : Notify +{ +    public override void run (Scanner scanner) { scanner.page_done (); } +} + +private class NotifyGotLine : Notify +{ +    public NotifyGotLine (ScanLine line) { this.line = line; } +    private ScanLine line; +    public override void run (Scanner scanner) +    { +        scanner.got_line (line); +    } +} + +public class Scanner +{ +    /* Singleton object */ +    private static Scanner scanner_object = null; + +    /* Thread communicating with SANE */ +    private unowned Thread<void*> thread; + +    /* Queue of requests from main thread */ +    private AsyncQueue<Request> request_queue; + +    /* Queue of events to notify in main queue */ +    private AsyncQueue<Notify> notify_queue; + +    /* Queue of responses to authorization requests */ +    private AsyncQueue<Credentials> authorize_queue; + +    private string? default_device; + +    private ScanState state; +    private bool need_redetect; + +    private List<ScanJob> job_queue; + +    /* Handle to SANE device */ +    private Sane.Handle handle; +    private bool have_handle; +    private string? current_device; + +    private Sane.Parameters parameters; + +    /* Last option read */ +    private Sane.Int option_index; + +    /* Option index for scan area */ +    private Sane.Int br_x_option_index; +    private Sane.Int br_y_option_index; + +    /* Buffer for received line */ +    private uchar[] buffer; +    private int n_used; + +    //private int bytes_remaining; +    private int line_count; +    private int pass_number; +    private int page_number; +    private int notified_page; + +    private bool scanning; + +    public signal void update_devices (List<ScanDevice> devices); +    public signal void request_authorization (string resource); +    public signal void expect_page (); +    public signal void got_page_info (ScanPageInfo info); +    public signal void got_line (ScanLine line); +    public signal void scan_failed (int error_code, string error_string); +    public signal void page_done (); +    public signal void document_done (); +    public signal void scanning_changed (); + +    private Scanner () +    { +        request_queue = new AsyncQueue<Request> (); +        notify_queue = new AsyncQueue<Notify> (); +        authorize_queue = new AsyncQueue<Credentials> (); +    } + +    public static Scanner get_instance () +    { +        if (scanner_object == null) +            scanner_object = new Scanner (); +        return scanner_object; +    } + +    private bool notify_idle_cb () +    { +        var notification = notify_queue.pop (); +        notification.run (this); +        return false; +    } + +    private void notify (Notify notification) +    { +        notify_queue.push (notification); +        Idle.add (notify_idle_cb); +    } + +    private void set_scanning (bool is_scanning) +    { +        if ((scanning && !is_scanning) || (!scanning && is_scanning)) +        { +            scanning = is_scanning; +            scanning_changed (); +            notify (new NotifyScanningChanged ()); +        } +    } + +    private static int get_device_weight (string device) +    { +        /* NOTE: This is using trends in the naming of SANE devices, SANE should be able to provide this information better */ + +        /* Use webcams as a last resort */ +        if (device.has_prefix ("vfl:")) +           return 2; + +        /* Use locally connected devices first */ +        if (device.contains ("usb")) +           return 0; + +        return 1; +    } + +    private static int compare_devices (ScanDevice device1, ScanDevice device2) +    { +        /* TODO: Should do some fuzzy matching on the last selected device and set that to the default */ + +        var weight1 = get_device_weight (device1.name); +        var weight2 = get_device_weight (device2.name); +        if (weight1 != weight2) +            return weight1 - weight2; + +        return strcmp (device1.label, device2.label); +    } + +    private void do_redetect () +    { +        unowned Sane.Device[] device_list = null; +        var status = Sane.get_devices (out device_list, false); +        debug ("sane_get_devices () -> %s", Sane.status_to_string (status)); +        if (status != Sane.Status.GOOD) +        { +            warning ("Unable to get SANE devices: %s", Sane.strstatus(status)); +            need_redetect = false; +            state = ScanState.IDLE; +            return; +        } + +        List<ScanDevice> devices = null; +        for (var i = 0; device_list[i] != null; i++) +        { +            debug ("Device: name=\"%s\" vendor=\"%s\" model=\"%s\" type=\"%s\"", +                   device_list[i].name, device_list[i].vendor, device_list[i].model, device_list[i].type); + +            var scan_device = new ScanDevice (); +            scan_device.name = device_list[i].name; + +            /* Abbreviate HP as it is a long string and does not match what is on the physical scanner */ +            var vendor = device_list[i].vendor; +            if (vendor == "Hewlett-Packard") +                vendor = "HP"; + +            scan_device.label = "%s %s".printf (vendor, device_list[i].model); +            /* Replace underscores in name */ +            scan_device.label.replace ("_", " "); + +            devices.append (scan_device); +        } + +        /* Sort devices by priority */ +        devices.sort (compare_devices); + +        need_redetect = false; +        state = ScanState.IDLE; + +        if (devices != null) +        { +            var device = devices.nth_data (0); +            default_device = device.name; +        } +        else +            default_device = null; + +        notify (new NotifyUpdateDevices ((owned) devices)); +    } + +    private bool set_default_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index) +    { +        /* Check if supports automatic option */ +        if ((option.cap & Sane.Capability.AUTOMATIC) == 0) +            return false; + +        var status = Sane.control_option (handle, option_index, Sane.Action.SET_AUTO, null, null); +        debug ("sane_control_option (%d, SANE_ACTION_SET_AUTO) -> %s", option_index, Sane.status_to_string (status)); +        if (status != Sane.Status.GOOD) +            warning ("Error setting default option %s: %s", option.name, Sane.strstatus(status)); + +        return status == Sane.Status.GOOD; +    } + +    private void set_bool_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, bool value, out bool result) +    { +        return_if_fail (option.type == Sane.ValueType.BOOL); + +        Sane.Bool v = (Sane.Bool) value; +        var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &v, null); +        result = (bool) v; +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s) -> (%s, %s)", option_index, value ? "SANE_TRUE" : "SANE_FALSE", Sane.status_to_string (status), result ? "SANE_TRUE" : "SANE_FALSE"); +    } + +    private void set_int_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, int value, out int result) +    { +        return_if_fail (option.type == Sane.ValueType.INT); + +        Sane.Int v = (Sane.Int) value; +        if (option.constraint_type == Sane.ConstraintType.RANGE) +        { +            if (option.constraint.range.quant != 0) +                v *= option.constraint.range.quant; +            if (v < option.constraint.range.min) +                v = option.constraint.range.min; +            if (v > option.constraint.range.max) +                v = option.constraint.range.max; +        } +        else if (option.constraint_type == Sane.ConstraintType.WORD_LIST) +        { +            int distance = int.MAX, nearest = 0; + +            /* Find nearest value to requested */ +            for (var i = 0; i < option.constraint.word_list[0]; i++) +            { +                var x = (int) option.constraint.word_list[i+1]; +                var d = (x - v).abs (); +                if (d < distance) +                { +                    distance = d; +                    nearest = x; +                } +            } +            v = (Sane.Int) nearest; +        } + +        var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &v, null); +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %d) -> (%s, %d)", option_index, value, Sane.status_to_string (status), v); +        result = v; +    } + +    private void set_fixed_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, double value, out double result) +    { +        double v = value; +        Sane.Fixed v_fixed; + +        return_if_fail (option.type == Sane.ValueType.FIXED); + +        if (option.constraint_type == Sane.ConstraintType.RANGE) +        { +            double min = Sane.UNFIX (option.constraint.range.min); +            double max = Sane.UNFIX (option.constraint.range.max); + +            if (v < min) +                v = min; +            if (v > max) +                v = max; +        } +        else if (option.constraint_type == Sane.ConstraintType.WORD_LIST) +        { +            double distance = double.MAX, nearest = 0.0; + +            /* Find nearest value to requested */ +            for (var i = 0; i < option.constraint.word_list[0]; i++) +            { +                double x = Sane.UNFIX (option.constraint.word_list[i+1]); +                if (Math.fabs (x - v) < distance) +                { +                    distance = Math.fabs (x - v); +                    nearest = x; +                } +            } +            v = nearest; +        } + +        v_fixed = Sane.FIX (v); +        var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &v_fixed, null); +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %f) -> (%s, %f)", option_index, value, Sane.status_to_string (status), Sane.UNFIX (v_fixed)); + +        result = Sane.UNFIX (v_fixed); +    } + +    private bool set_string_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, string value, out string result) +    { +        return_val_if_fail (option.type == Sane.ValueType.STRING, false); + +        var s = new char[option.size]; +        var i = 0; +        for (; i < (option.size - 1) && value[i] != '\0'; i++) +            s[i] = value[i]; +        s[i] = '\0'; +        var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, s, null); +        result = (string) s; +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, \"%s\") -> (%s, \"%s\")", option_index, value, Sane.status_to_string (status), result); + +        return status == Sane.Status.GOOD; +    } + +    private bool set_constrained_string_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, string[] values, out string result) +    { +        return_val_if_fail (option.type == Sane.ValueType.STRING, false); +        return_val_if_fail (option.constraint_type == Sane.ConstraintType.STRING_LIST, false); + +        for (var i = 0; values[i] != null; i++) +        { +            var j = 0; +            for (; option.constraint.string_list[j] != null; j++) +            { +                if (values[i] == option.constraint.string_list[j]) +                   break; +            } + +            if (option.constraint.string_list[j] != null) +                return set_string_option (handle, option, option_index, values[i], out result); +        } + +        return false; +    } + +    private void log_option (Sane.Int index, Sane.OptionDescriptor option) +    { +        var s = "Option %d:".printf (index); + +        if (option.name != "") +            s += " name='%s'".printf (option.name); + +        if (option.title != "") +            s += " title='%s'".printf (option.title); + +        switch (option.type) +        { +        case Sane.ValueType.BOOL: +            s += " type=bool"; +            break; +        case Sane.ValueType.INT: +            s += " type=int"; +            break; +        case Sane.ValueType.FIXED: +            s += " type=fixed"; +            break; +        case Sane.ValueType.STRING: +            s += " type=string"; +            break; +        case Sane.ValueType.BUTTON: +            s += " type=button"; +            break; +        case Sane.ValueType.GROUP: +            s += " type=group"; +            break; +        default: +            s += " type=%d".printf (option.type); +            break; +        } + +        s += " size=%d".printf (option.size); + +        switch (option.unit) +        { +        case Sane.Unit.NONE: +            break; +        case Sane.Unit.PIXEL: +            s += " unit=pixels"; +            break; +        case Sane.Unit.BIT: +            s += " unit=bits"; +            break; +        case Sane.Unit.MM: +            s += " unit=mm"; +            break; +        case Sane.Unit.DPI: +            s += " unit=dpi"; +            break; +        case Sane.Unit.PERCENT: +            s += " unit=percent"; +            break; +        case Sane.Unit.MICROSECOND: +            s += " unit=microseconds"; +            break; +        default: +            s += " unit=%d".printf (option.unit); +            break; +        } + +        switch (option.constraint_type) +        { +        case Sane.ConstraintType.RANGE: +            if (option.type == Sane.ValueType.FIXED) +                s += " min=%f, max=%f, quant=%d".printf (Sane.UNFIX (option.constraint.range.min), Sane.UNFIX (option.constraint.range.max), option.constraint.range.quant); +            else +                s += " min=%d, max=%d, quant=%d".printf (option.constraint.range.min, option.constraint.range.max, option.constraint.range.quant); +            break; +        case Sane.ConstraintType.WORD_LIST: +            s += " values=["; +            for (var i = 0; i < option.constraint.word_list[0]; i++) +            { +                if (i != 0) +                    s += ", "; +                if (option.type == Sane.ValueType.INT) +                    s += "%d".printf (option.constraint.word_list[i+1]); +                else +                    s += "%f".printf (Sane.UNFIX (option.constraint.word_list[i+1])); +            } +            s += "]"; +            break; +        case Sane.ConstraintType.STRING_LIST: +            s += " values=["; +            for (var i = 0; option.constraint.string_list[i] != null; i++) +            { +                if (i != 0) +                    s += ", "; +                s += "\"%s\"".printf (option.constraint.string_list[i]); +            } +            s += "]"; +            break; +        default: +            break; +        } + +        var cap = option.cap; +        if (cap != 0) +        { +            s += " cap="; +            if ((cap & Sane.Capability.SOFT_SELECT) != 0) +            { +                if (s != "") +                    s += ","; +                s += "soft-select"; +                cap &= ~Sane.Capability.SOFT_SELECT; +            } +            if ((cap & Sane.Capability.HARD_SELECT) != 0) +            { +                if (s != "") +                    s += ","; +                s += "hard-select"; +                cap &= ~Sane.Capability.HARD_SELECT; +            } +            if ((cap & Sane.Capability.SOFT_DETECT) != 0) +            { +                if (s != "") +                    s += ","; +                s += "soft-detect"; +                cap &= ~Sane.Capability.SOFT_DETECT; +            } +            if ((cap & Sane.Capability.EMULATED) != 0) +            { +                if (s != "") +                    s += ","; +                s += "emulated"; +                cap &= ~Sane.Capability.EMULATED; +            } +            if ((cap & Sane.Capability.AUTOMATIC) != 0) +            { +                if (s != "") +                    s += ","; +                s += "automatic"; +                cap &= ~Sane.Capability.AUTOMATIC; +            } +            if ((cap & Sane.Capability.INACTIVE) != 0) +            { +                if (s != "") +                    s += ","; +                s += "inactive"; +                cap &= ~Sane.Capability.INACTIVE; +            } +            if ((cap & Sane.Capability.ADVANCED) != 0) +            { +                if (s != "") +                    s += ","; +                s += "advanced"; +                cap &= ~Sane.Capability.ADVANCED; +            } +            /* Unknown capabilities */ +            if (cap != 0) +            { +                if (s != "") +                    s += ","; +                s += "%x".printf (cap); +            } +        } + +        debug ("%s", s); + +        if (option.desc != null) +            debug ("  Description: %s", option.desc); +    } + +    private static void authorization_cb (string resource, char[] username, char[] password) +    { +        scanner_object.notify (new NotifyRequestAuthorization (resource)); + +        var credentials = scanner_object.authorize_queue.pop (); +        for (var i = 0; credentials.username[i] != '\0' && i < Sane.MAX_USERNAME_LEN; i++) +            username[i] = credentials.username[i]; +        for (var i = 0; credentials.password[i] != '\0' && i < Sane.MAX_PASSWORD_LEN; i++) +            password[i] = credentials.password[i]; +    } + +    public void authorize (string username, string password) +    { +        var credentials = new Credentials (); +        credentials.username = username; +        credentials.password = password; +        authorize_queue.push (credentials); +    } + +    private void close_device () +    { +        if (have_handle) +        { +            Sane.cancel (handle); +            debug ("sane_cancel ()"); + +            Sane.close (handle); +            debug ("sane_close ()"); +            have_handle = false; +        } + +        buffer = null; +        job_queue = null; + +        set_scanning (false); +    } + +    private void fail_scan (int error_code, string error_string) +    { +        close_device (); +        state = ScanState.IDLE; +        notify (new NotifyScanFailed (error_code, error_string)); +    } + +    private bool handle_requests () +    { +        /* Redetect when idle */ +        if (state == ScanState.IDLE && need_redetect) +            state = ScanState.REDETECT; + +        /* Process all requests */ +        int request_count = 0; +        while (true) +        { +            Request request; +            if ((state == ScanState.IDLE && request_count == 0) || +                request_queue.length () > 0) +                request = request_queue.pop (); +            else +                return true; + +            debug ("Processing request"); +            request_count++; + +            if (request is RequestStartScan) +            { +                var r = (RequestStartScan) request; +                job_queue.append (r.job); +            } +            else if (request is RequestCancel) +            { +                fail_scan (Sane.Status.CANCELLED, "Scan cancelled - do not report this error"); +            } +            else if (request is RequestQuit) +            { +                close_device (); +                return false; +            } +        } +    } + +    private void do_open () +    { +        var job = (ScanJob) job_queue.data; + +        line_count = 0; +        pass_number = 0; +        page_number = 0; +        notified_page = -1; +        option_index = 0; +        br_x_option_index = 0; +        br_y_option_index = 0; + +        if (job.device == null && default_device != null) +            job.device = default_device; + +        if (job.device == null) +        { +            warning ("No scan device available"); +            fail_scan (0, +                       /* Error displayed when no scanners to scan with */ +                       _("No scanners available.  Please connect a scanner.")); +            return; +        } + +        /* See if we can use the already open device */ +        if (have_handle) +        { +            if (current_device == job.device) +            { +                state = ScanState.GET_OPTION; +                return; +            } + +            Sane.close (handle); +            debug ("sane_close ()"); +            have_handle = false; +        } + +        current_device = null; + +        have_handle = false; +        var status = Sane.open (job.device, out handle); +        debug ("sane_open (\"%s\") -> %s", job.device, Sane.status_to_string (status)); + +        if (status != Sane.Status.GOOD) +        { +            warning ("Unable to get open device: %s", Sane.strstatus (status)); +            fail_scan (status, +                       /* Error displayed when cannot connect to scanner */ +                       _("Unable to connect to scanner")); +            return; +        } +        have_handle = true; + +        current_device = job.device; +        state = ScanState.GET_OPTION; +    } + +    private void do_get_option () +    { +        var job = (ScanJob) job_queue.data; + +        var option = Sane.get_option_descriptor (handle, option_index); +        debug ("sane_get_option_descriptor (%d)", option_index); +        var index = option_index; +        option_index++; + +        if (option == null) +        { +            /* Always use maximum scan area - some scanners default to using partial areas.  This should be patched in sane-backends */ +            if (br_x_option_index != 0) +            { +                option = Sane.get_option_descriptor (handle, br_x_option_index); +                debug ("sane_get_option_descriptor (%d)", br_x_option_index); +                if (option.constraint_type == Sane.ConstraintType.RANGE) +                { +                    if (option.type == Sane.ValueType.FIXED) +                        set_fixed_option (handle, option, br_x_option_index, Sane.UNFIX (option.constraint.range.max), null); +                    else +                        set_int_option (handle, option, br_x_option_index, option.constraint.range.max, null); +                } +            } +            if (br_y_option_index != 0) +            { +                option = Sane.get_option_descriptor (handle, br_y_option_index); +                debug ("sane_get_option_descriptor (%d)", br_y_option_index); +                if (option.constraint_type == Sane.ConstraintType.RANGE) +                { +                    if (option.type == Sane.ValueType.FIXED) +                        set_fixed_option (handle, option, br_y_option_index, Sane.UNFIX (option.constraint.range.max), null); +                    else +                        set_int_option (handle, option, br_y_option_index, option.constraint.range.max, null); +                } +            } + +            state = ScanState.START; +            return; +        } + +        log_option (index, option); + +        /* Ignore groups */ +        if (option.type == Sane.ValueType.GROUP) +            return; + +        /* Option disabled */ +        if ((option.cap & Sane.Capability.INACTIVE) != 0) +            return; + +        /* Some options are unnammed (e.g. Option 0) */ +        if (option.name == null) +            return; + +        if (option.name == Sane.NAME_SCAN_RESOLUTION) +        { +            if (option.type == Sane.ValueType.FIXED) +                set_fixed_option (handle, option, index, job.dpi, out job.dpi); +            else +            { +                int dpi; +                set_int_option (handle, option, index, (int) job.dpi, out dpi); +                job.dpi = dpi; +            } +        } +        else if (option.name == Sane.NAME_SCAN_SOURCE) +        { +            string[] flatbed_sources = +            { +                "Auto", +                Sane.I18N ("Auto"), +                "Flatbed", +                Sane.I18N ("Flatbed"), +                "FlatBed", +                "Normal", +                Sane.I18N ("Normal") +            }; + +            string[] adf_sources = +            { +                "Automatic Document Feeder", +                Sane.I18N ("Automatic Document Feeder"), +                "ADF", +                "Automatic Document Feeder(left aligned)", /* Seen in the proprietary brother3 driver */ +                "Automatic Document Feeder(centrally aligned)" /* Seen in the proprietary brother3 driver */ +            }; + +            string[] adf_front_sources = +            { +                "ADF Front", +                Sane.I18N ("ADF Front") +            }; + +            string[] adf_back_sources = +            { +                "ADF Back", +                Sane.I18N ("ADF Back") +            }; + +            string[] adf_duplex_sources = +            { +                "ADF Duplex", +                Sane.I18N ("ADF Duplex") +            }; + +            switch (job.type) +            { +            case ScanType.SINGLE: +                if (!set_default_option (handle, option, index)) +                    if (!set_constrained_string_option (handle, option, index, flatbed_sources, null)) +                        warning ("Unable to set single page source, please file a bug"); +                break; +            case ScanType.ADF_FRONT: +                if (!set_constrained_string_option (handle, option, index, adf_front_sources, null)) +                    if (!!set_constrained_string_option (handle, option, index, adf_sources, null)) +                        warning ("Unable to set front ADF source, please file a bug"); +                break; +            case ScanType.ADF_BACK: +                if (!set_constrained_string_option (handle, option, index, adf_back_sources, null)) +                    if (!set_constrained_string_option (handle, option, index, adf_sources, null)) +                        warning ("Unable to set back ADF source, please file a bug"); +                break; +            case ScanType.ADF_BOTH: +                if (!set_constrained_string_option (handle, option, index, adf_duplex_sources, null)) +                    if (!set_constrained_string_option (handle, option, index, adf_sources, null)) +                        warning ("Unable to set duplex ADF source, please file a bug"); +                break; +            } +        } +        else if (option.name == "duplex") +        { +            if (option.type == Sane.ValueType.BOOL) +                set_bool_option (handle, option, index, job.type == ScanType.ADF_BOTH, null); +        } +        else if (option.name == "batch-scan") +        { +            if (option.type == Sane.ValueType.BOOL) +                set_bool_option (handle, option, index, job.type != ScanType.SINGLE, null); +        } +        else if (option.name == Sane.NAME_BIT_DEPTH) +        { +            if (job.depth > 0) +                set_int_option (handle, option, index, job.depth, null); +        } +        else if (option.name == Sane.NAME_SCAN_MODE) +        { +            /* The names of scan modes often used in drivers, as taken from the sane-backends source */ +            string[] color_scan_modes = +            { +                Sane.VALUE_SCAN_MODE_COLOR, +                "Color", +                "24bit Color" /* Seen in the proprietary brother3 driver */ +            }; +            string[] gray_scan_modes = +            { +                Sane.VALUE_SCAN_MODE_GRAY, +                "Gray", +                "Grayscale", +                Sane.I18N ("Grayscale"), +                "True Gray" /* Seen in the proprietary brother3 driver */ +            }; +            string[] lineart_scan_modes = +            { +                Sane.VALUE_SCAN_MODE_LINEART, +                "Lineart", +                "LineArt", +                Sane.I18N ("LineArt"), +                "Black & White", +                Sane.I18N ("Black & White"), +                "Binary", +                Sane.I18N ("Binary"), +                "Thresholded", +                Sane.VALUE_SCAN_MODE_GRAY, +                "Gray", +                "Grayscale", +                Sane.I18N ("Grayscale"), +                "True Gray" /* Seen in the proprietary brother3 driver */ +            }; + +            switch (job.scan_mode) +            { +            case ScanMode.COLOR: +                if (!set_constrained_string_option (handle, option, index, color_scan_modes, null)) +                    warning ("Unable to set Color mode, please file a bug"); +                break; +            case ScanMode.GRAY: +                if (!set_constrained_string_option (handle, option, index, gray_scan_modes, null)) +                    warning ("Unable to set Gray mode, please file a bug"); +                break; +            case ScanMode.LINEART: +                if (!set_constrained_string_option (handle, option, index, lineart_scan_modes, null)) +                    warning ("Unable to set Lineart mode, please file a bug"); +                break; +            default: +                break; +            } +        } +        /* Disable compression, we will compress after scanning */ +        else if (option.name == "compression") +        { +            string[] disable_compression_names = +            { +                Sane.I18N ("None"), +                Sane.I18N ("none"), +                "None", +                "none" +            }; + +            if (!set_constrained_string_option (handle, option, index, disable_compression_names, null)) +                warning ("Unable to disable compression, please file a bug"); +        } +        else if (option.name == Sane.NAME_SCAN_BR_X) +            br_x_option_index = index; +        else if (option.name == Sane.NAME_SCAN_BR_Y) +            br_y_option_index = index; +        else if (option.name == Sane.NAME_PAGE_WIDTH) +        { +            if (job.page_width > 0.0) +            { +                if (option.type == Sane.ValueType.FIXED) +                    set_fixed_option (handle, option, index, job.page_width / 10.0, null); +                else +                    set_int_option (handle, option, index, job.page_width / 10, null); +            } +        } +        else if (option.name == Sane.NAME_PAGE_HEIGHT) +        { +            if (job.page_height > 0.0) +            { +                if (option.type == Sane.ValueType.FIXED) +                    set_fixed_option (handle, option, index, job.page_height / 10.0, null); +                else +                    set_int_option (handle, option, index, job.page_height / 10, null); +            } +        } + +        /* Test scanner options (hoping will not effect other scanners...) */ +        if (current_device == "test") +        { +            if (option.name == "hand-scanner") +                set_bool_option (handle, option, index, false, null); +            else if (option.name == "three-pass") +                set_bool_option (handle, option, index, false, null); +            else if (option.name == "test-picture") +                set_string_option (handle, option, index, "Color pattern", null); +            else if (option.name == "read-delay") +                set_bool_option (handle, option, index, true, null); +            else if (option.name == "read-delay-duration") +                set_int_option (handle, option, index, 200000, null); +        } +    } + +    private void do_complete_document () +    { +        job_queue.remove_link (job_queue); + +        state = ScanState.IDLE; + +        /* Continue onto the next job */ +        if (job_queue != null) +        { +            state = ScanState.OPEN; +            return; +        } + +        /* Trigger timeout to close */ +        // TODO + +        notify (new NotifyDocumentDone ()); +        set_scanning (false); +    } + +    private void do_start () +    { +        Sane.Status status; + +        notify (new NotifyExpectPage ()); + +        status = Sane.start (handle); +        debug ("sane_start (page=%d, pass=%d) -> %s", page_number, pass_number, Sane.status_to_string (status)); +        if (status == Sane.Status.GOOD) +            state = ScanState.GET_PARAMETERS; +        else if (status == Sane.Status.NO_DOCS) +            do_complete_document (); +        else +        { +            warning ("Unable to start device: %s", Sane.strstatus (status)); +            fail_scan (status, +                       /* Error display when unable to start scan */ +                       _("Unable to start scan")); +        } +    } + +    private void do_get_parameters () +    { +        var status = Sane.get_parameters (handle, out parameters); +        debug ("sane_get_parameters () -> %s", Sane.status_to_string (status)); +        if (status != Sane.Status.GOOD) +        { +            warning ("Unable to get device parameters: %s", Sane.strstatus (status)); +            fail_scan (status, +                       /* Error displayed when communication with scanner broken */ +                       _("Error communicating with scanner")); +            return; +        } + +        var job = (ScanJob) job_queue.data; + +        debug ("Parameters: format=%s last_frame=%s bytes_per_line=%d pixels_per_line=%d lines=%d depth=%d", +               Sane.frame_to_string (parameters.format), +               parameters.last_frame ? "SANE_TRUE" : "SANE_FALSE", +               parameters.bytes_per_line, +               parameters.pixels_per_line, +               parameters.lines, +               parameters.depth); + +        var info = new ScanPageInfo (); +        info.width = parameters.pixels_per_line; +        info.height = parameters.lines; +        info.depth = parameters.depth; +        /* Reduce bit depth if requested lower than received */ +        // FIXME: This a hack and only works on 8 bit gray to 2 bit gray +        if (parameters.depth == 8 && parameters.format == Sane.Frame.GRAY && job.depth == 2 && job.scan_mode == ScanMode.GRAY) +            info.depth = job.depth; +        info.n_channels = parameters.format == Sane.Frame.GRAY ? 1 : 3; +        info.dpi = job.dpi; // FIXME: This is the requested DPI, not the actual DPI +        info.device = current_device; + +        if (page_number != notified_page) +        { +            notify (new NotifyGotPageInfo (info)); +            notified_page = page_number; +        } + +        /* Prepare for read */ +        var buffer_size = parameters.bytes_per_line + 1; /* Use +1 so buffer is not resized if driver returns one line per read */ +        buffer = new uchar[buffer_size]; +        n_used = 0; +        line_count = 0; +        pass_number = 0; +        state = ScanState.READ; +    } + +    private void do_complete_page () +    { +        notify (new NotifyPageDone ()); + +        var job = (ScanJob) job_queue.data; + +        /* If multi-pass then scan another page */ +        if (!parameters.last_frame) +        { +            pass_number++; +            state = ScanState.START; +            return; +        } + +        /* Go back for another page */ +        if (job.type != ScanType.SINGLE) +        { +            page_number++; +            pass_number = 0; +            notify (new NotifyPageDone ()); +            state = ScanState.START; +            return; +        } + +        Sane.cancel (handle); +        debug ("sane_cancel ()"); + +        do_complete_document (); +    } + +    private void do_read () +    { +        var job = (ScanJob) job_queue.data; + +        /* Read as many bytes as we expect */ +        var n_to_read = buffer.length - n_used; + +        Sane.Int n_read; +        var b = (uchar *) buffer; +        var status = Sane.read (handle, (uint8[]) (b + n_used), (Sane.Int) n_to_read, out n_read); +        debug ("sane_read (%d) -> (%s, %d)", n_to_read, Sane.status_to_string (status), n_read); + +        /* Completed read */ +        if (status == Sane.Status.EOF) +        { +            if (parameters.lines > 0 && line_count != parameters.lines) +                warning ("Scan completed with %d lines, expected %d lines", parameters.lines, parameters.lines); +            if (n_used > 0) +                warning ("Scan complete with %d bytes of unused data", n_used); +            do_complete_page (); +            return; +        } + +        /* Communication error */ +        if (status != Sane.Status.GOOD) +        { +            warning ("Unable to read frame from device: %s", Sane.strstatus (status)); +            fail_scan (status, +                       /* Error displayed when communication with scanner broken */ +                       _("Error communicating with scanner")); +            return; +        } + +        bool full_read = false; +        if (n_used == 0 && n_read == buffer.length) +            full_read = true; +        n_used += n_read; + +        /* Feed out lines */ +        if (n_used >= parameters.bytes_per_line) +        { +            var line = new ScanLine (); +            switch (parameters.format) +            { +            case Sane.Frame.GRAY: +                line.channel = 0; +                break; +            case Sane.Frame.RGB: +                line.channel = -1; +                break; +            case Sane.Frame.RED: +                line.channel = 0; +                break; +            case Sane.Frame.GREEN: +                line.channel = 1; +                break; +            case Sane.Frame.BLUE: +                line.channel = 2; +                break; +            } +            line.width = parameters.pixels_per_line; +            line.depth = parameters.depth; +            line.data = (owned) buffer; +            line.data_length = parameters.bytes_per_line; +            line.number = line_count; +            line.n_lines = n_used / line.data_length; + +            line_count += line.n_lines; + +            /* Increase buffer size if did full read */ +            var buffer_size = buffer.length; +            if (full_read) +                buffer_size += parameters.bytes_per_line; + +            buffer = new uchar[buffer_size]; +            var n_remaining = n_used - (line.n_lines * line.data_length); +            n_used = 0; +            for (var i = 0; i < n_remaining; i++) +            { +                buffer[i] = line.data[i + (line.n_lines * line.data_length)]; +                n_used++; +            } + +            /* Reduce bit depth if requested lower than received */ +            // FIXME: This a hack and only works on 8 bit gray to 2 bit gray +            if (parameters.depth == 8 && parameters.format == Sane.Frame.GRAY && +                job.depth == 2 && job.scan_mode == ScanMode.GRAY) +            { +                uchar block = 0; +                var write_offset = 0; +                var block_shift = 6; +                for (var i = 0; i < line.n_lines; i++) +                { +                    var offset = i * line.data_length; +                    for (var x = 0; x < line.width; x++) +                    { +                         var p = line.data[offset + x]; + +                         uchar sample; +                         if (p >= 192) +                             sample = 3; +                         else if (p >= 128) +                             sample = 2; +                         else if (p >= 64) +                             sample = 1; +                         else +                             sample = 0; + +                         block |= sample << block_shift; +                         if (block_shift == 0) +                         { +                             line.data[write_offset] = block; +                             write_offset++; +                             block = 0; +                             block_shift = 6; +                         } +                         else +                             block_shift -= 2; +                    } + +                    /* Finish each line on a byte boundary */ +                    if (block_shift != 6) +                    { +                        line.data[write_offset] = block; +                        write_offset++; +                        block = 0; +                        block_shift = 6; +                    } +                } + +                line.data_length = (line.width * 2 + 7) / 8; +            } + +            notify (new NotifyGotLine (line)); +        } +    } + +    private void* scan_thread () +    { +        state = ScanState.IDLE; + +        Sane.Int version_code; +        var status = Sane.init (out version_code, authorization_cb); +        debug ("sane_init () -> %s", Sane.status_to_string (status)); +        if (status != Sane.Status.GOOD) +        { +            warning ("Unable to initialize SANE backend: %s", Sane.strstatus(status)); +            return null; +        } +        debug ("SANE version %d.%d.%d", +               Sane.VERSION_MAJOR(version_code), +               Sane.VERSION_MINOR(version_code), +               Sane.VERSION_BUILD(version_code)); + +        /* Scan for devices on first start */ +        redetect (); + +        while (handle_requests ()) +        { +            switch (state) +            { +            case ScanState.IDLE: +                 if (job_queue != null) +                 { +                     set_scanning (true); +                     state = ScanState.OPEN; +                 } +                 break; +            case ScanState.REDETECT: +                do_redetect (); +                break; +            case ScanState.OPEN: +                do_open (); +                break; +            case ScanState.GET_OPTION: +                do_get_option (); +                break; +            case ScanState.START: +                do_start (); +                break; +            case ScanState.GET_PARAMETERS: +                do_get_parameters (); +                break; +            case ScanState.READ: +                do_read (); +                break; +            } +        } + +        return null; +    } + +    public void start () +    { +        try +        { +            thread = Thread.create<void*> (scan_thread, true); +        } +        catch (Error e) +        { +            critical ("Unable to create thread: %s", e.message); +        } +    } + +    public void redetect () +    { +        if (need_redetect) +            return; +        need_redetect = true; + +        debug ("Requesting redetection of scan devices"); + +        request_queue.push (new RequestRedetect ()); +    } + +    public bool is_scanning () +    { +        return scanning; +    } + +    private string get_scan_mode_string (ScanMode mode) +    { +        switch (mode) +        { +        case ScanMode.DEFAULT: +            return "ScanMode.DEFAULT"; +        case ScanMode.COLOR: +            return "ScanMode.COLOR"; +        case ScanMode.GRAY: +            return "ScanMode.GRAY"; +        case ScanMode.LINEART: +            return "ScanMode.LINEART"; +        default: +            return "%d".printf (mode); +        } +    } + +    private string get_scan_type_string (ScanType type) +    { +        switch (type) +        { +        case ScanType.SINGLE: +            return "ScanType.SINGLE"; +        case ScanType.ADF_FRONT: +            return "ScanType.ADF_FRONT"; +        case ScanType.ADF_BACK: +            return "ScanType.ADF_BACK"; +        case ScanType.ADF_BOTH: +            return "ScanType.ADF_BOTH"; +        default: +            return "%d".printf (type); +        } +    } + +    public void scan (string? device, ScanOptions options) +    { +        debug ("Scanner.scan (\"%s\", dpi=%d, scan_mode=%s, depth=%d, type=%s, paper_width=%d, paper_height=%d)", +               device != null ? device : "(null)", options.dpi, get_scan_mode_string (options.scan_mode), options.depth, +               get_scan_type_string (options.type), options.paper_width, options.paper_height); +        var request = new RequestStartScan (); +        request.job = new ScanJob (); +        request.job.device = device; +        request.job.dpi = options.dpi; +        request.job.scan_mode = options.scan_mode; +        request.job.depth = options.depth; +        request.job.type = options.type; +        request.job.page_width = options.paper_width; +        request.job.page_height = options.paper_height; +        request_queue.push (request); +    } + +    public void cancel () +    { +        request_queue.push (new RequestCancel ()); +    } + +    public void free () +    { +        debug ("Stopping scan thread"); + +        request_queue.push (new RequestQuit ()); + +        if (thread != null) +            thread.join (); + +        Sane.exit (); +        debug ("sane_exit ()"); +    } +} diff --git a/src/simple-scan.c b/src/simple-scan.c index bb7e036..1f1f599 100644 --- a/src/simple-scan.c +++ b/src/simple-scan.c @@ -1,7 +1,10 @@ +/* simple-scan.c generated by valac 0.13.1, the Vala compiler + * generated from simple-scan.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later @@ -9,608 +12,1507 @@   * license.   */ -#include <stdlib.h> +#include <glib.h> +#include <glib-object.h> +#include <gudev/gudev.h>  #include <stdio.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> +#include <math.h> +#include <sane/sane.h> +#include <glib/gi18n-lib.h> +#include <glib/gstdio.h>  #include <unistd.h> -#include <gudev/gudev.h> -#include <dbus/dbus-glib.h> +#include <gio/gio.h> +#include <gtk/gtk.h> +#include <locale.h> +#include <config.h> +#include <gobject/gvaluecollector.h> + + +#define TYPE_APPLICATION (application_get_type ()) +#define APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_APPLICATION, Application)) +#define APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_APPLICATION, ApplicationClass)) +#define IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_APPLICATION)) +#define IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_APPLICATION)) +#define APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_APPLICATION, ApplicationClass)) + +typedef struct _Application Application; +typedef struct _ApplicationClass ApplicationClass; +typedef struct _ApplicationPrivate ApplicationPrivate; + +#define TYPE_SCAN_DEVICE (scan_device_get_type ()) +#define SCAN_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_DEVICE, ScanDevice)) +#define SCAN_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_DEVICE, ScanDeviceClass)) +#define IS_SCAN_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_DEVICE)) +#define IS_SCAN_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_DEVICE)) +#define SCAN_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_DEVICE, ScanDeviceClass)) + +typedef struct _ScanDevice ScanDevice; +typedef struct _ScanDeviceClass ScanDeviceClass; + +#define TYPE_SIMPLE_SCAN (simple_scan_get_type ()) +#define SIMPLE_SCAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SIMPLE_SCAN, SimpleScan)) +#define SIMPLE_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SIMPLE_SCAN, SimpleScanClass)) +#define IS_SIMPLE_SCAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SIMPLE_SCAN)) +#define IS_SIMPLE_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SIMPLE_SCAN)) +#define SIMPLE_SCAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SIMPLE_SCAN, SimpleScanClass)) + +typedef struct _SimpleScan SimpleScan; +typedef struct _SimpleScanClass SimpleScanClass; + +#define TYPE_SCANNER (scanner_get_type ()) +#define SCANNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCANNER, Scanner)) +#define SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCANNER, ScannerClass)) +#define IS_SCANNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCANNER)) +#define IS_SCANNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCANNER)) +#define SCANNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCANNER, ScannerClass)) + +typedef struct _Scanner Scanner; +typedef struct _ScannerClass ScannerClass; + +#define TYPE_BOOK (book_get_type ()) +#define BOOK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOOK, Book)) +#define BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BOOK, BookClass)) +#define IS_BOOK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOOK)) +#define IS_BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BOOK)) +#define BOOK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BOOK, BookClass)) + +typedef struct _Book Book; +typedef struct _BookClass BookClass; +#define _scan_device_unref0(var) ((var == NULL) ? NULL : (var = (scan_device_unref (var), NULL))) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _simple_scan_unref0(var) ((var == NULL) ? NULL : (var = (simple_scan_unref (var), NULL))) +#define _scanner_unref0(var) ((var == NULL) ? NULL : (var = (scanner_unref (var), NULL))) +#define _book_unref0(var) ((var == NULL) ? NULL : (var = (book_unref (var), NULL))) + +#define TYPE_SCAN_OPTIONS (scan_options_get_type ()) +#define SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_OPTIONS, ScanOptions)) +#define SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_OPTIONS, ScanOptionsClass)) +#define IS_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_OPTIONS)) +#define IS_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_OPTIONS)) +#define SCAN_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_OPTIONS, ScanOptionsClass)) + +typedef struct _ScanOptions ScanOptions; +typedef struct _ScanOptionsClass ScanOptionsClass; + +#define TYPE_SCAN_PAGE_INFO (scan_page_info_get_type ()) +#define SCAN_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_PAGE_INFO, ScanPageInfo)) +#define SCAN_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_PAGE_INFO, ScanPageInfoClass)) +#define IS_SCAN_PAGE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_PAGE_INFO)) +#define IS_SCAN_PAGE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_PAGE_INFO)) +#define SCAN_PAGE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_PAGE_INFO, ScanPageInfoClass)) + +typedef struct _ScanPageInfo ScanPageInfo; +typedef struct _ScanPageInfoClass ScanPageInfoClass; + +#define TYPE_SCAN_LINE (scan_line_get_type ()) +#define SCAN_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_LINE, ScanLine)) +#define SCAN_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_LINE, ScanLineClass)) +#define IS_SCAN_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_LINE)) +#define IS_SCAN_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_LINE)) +#define SCAN_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_LINE, ScanLineClass)) + +typedef struct _ScanLine ScanLine; +typedef struct _ScanLineClass ScanLineClass; +typedef struct _ScanDevicePrivate ScanDevicePrivate; +#define __g_list_free__scan_device_unref0_0(var) ((var == NULL) ? NULL : (var = (_g_list_free__scan_device_unref0_ (var), NULL))) +#define _g_list_free0(var) ((var == NULL) ? NULL : (var = (g_list_free (var), NULL))) +#define _g_free0(var) (var = (g_free (var), NULL)) + +#define TYPE_PAGE (page_get_type ()) +#define PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE, Page)) +#define PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE, PageClass)) +#define IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE)) +#define IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE)) +#define PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE, PageClass)) + +typedef struct _Page Page; +typedef struct _PageClass PageClass; + +#define TYPE_SCAN_DIRECTION (scan_direction_get_type ()) +#define _page_unref0(var) ((var == NULL) ? NULL : (var = (page_unref (var), NULL))) +typedef struct _ScanPageInfoPrivate ScanPageInfoPrivate; +typedef struct _ScanOptionsPrivate ScanOptionsPrivate; + +#define TYPE_SCAN_MODE (scan_mode_get_type ()) + +#define TYPE_SCAN_TYPE (scan_type_get_type ()) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) +#define _g_option_context_free0(var) ((var == NULL) ? NULL : (var = (g_option_context_free (var), NULL))) +#define _g_timer_destroy0(var) ((var == NULL) ? NULL : (var = (g_timer_destroy (var), NULL))) +#define _fclose0(var) ((var == NULL) ? NULL : (var = (fclose (var), NULL))) +#define _application_unref0(var) ((var == NULL) ? NULL : (var = (application_unref (var), NULL))) +typedef struct _ParamSpecApplication ParamSpecApplication; + +struct _Application { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ApplicationPrivate * priv; +}; + +struct _ApplicationClass { +	GTypeClass parent_class; +	void (*finalize) (Application *self); +}; + +struct _ApplicationPrivate { +	ScanDevice* default_device; +	gboolean have_devices; +	GUdevClient* udev_client; +	SimpleScan* ui; +	Scanner* scanner; +	Book* book; +}; + +struct _ScanDevice { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanDevicePrivate * priv; +	gchar* name; +	gchar* label; +}; + +struct _ScanDeviceClass { +	GTypeClass parent_class; +	void (*finalize) (ScanDevice *self); +}; + +typedef enum  { +	SCAN_DIRECTION_TOP_TO_BOTTOM, +	SCAN_DIRECTION_LEFT_TO_RIGHT, +	SCAN_DIRECTION_BOTTOM_TO_TOP, +	SCAN_DIRECTION_RIGHT_TO_LEFT +} ScanDirection; + +struct _ScanPageInfo { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanPageInfoPrivate * priv; +	gint width; +	gint height; +	gint depth; +	gint n_channels; +	gdouble dpi; +	gchar* device; +}; + +struct _ScanPageInfoClass { +	GTypeClass parent_class; +	void (*finalize) (ScanPageInfo *self); +}; + +typedef enum  { +	SCAN_MODE_DEFAULT, +	SCAN_MODE_COLOR, +	SCAN_MODE_GRAY, +	SCAN_MODE_LINEART +} ScanMode; + +typedef enum  { +	SCAN_TYPE_SINGLE, +	SCAN_TYPE_ADF_FRONT, +	SCAN_TYPE_ADF_BACK, +	SCAN_TYPE_ADF_BOTH +} ScanType; + +struct _ScanOptions { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanOptionsPrivate * priv; +	gint dpi; +	ScanMode scan_mode; +	gint depth; +	ScanType type; +	gint paper_width; +	gint paper_height; +}; + +struct _ScanOptionsClass { +	GTypeClass parent_class; +	void (*finalize) (ScanOptions *self); +}; + +struct _ParamSpecApplication { +	GParamSpec parent_instance; +}; + + +static gpointer application_parent_class = NULL; +static gboolean application_show_version; +static gboolean application_show_version = FALSE; +static gboolean application_debug_enabled; +static gboolean application_debug_enabled = FALSE; +static GTimer* application_log_timer; +static GTimer* application_log_timer = NULL; +static FILE* application_log_file; +static FILE* application_log_file = NULL; + +gpointer application_ref (gpointer instance); +void application_unref (gpointer instance); +GParamSpec* param_spec_application (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_application (GValue* value, gpointer v_object); +void value_take_application (GValue* value, gpointer v_object); +gpointer value_get_application (const GValue* value); +GType application_get_type (void) G_GNUC_CONST; +gpointer scan_device_ref (gpointer instance); +void scan_device_unref (gpointer instance); +GParamSpec* param_spec_scan_device (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_device (GValue* value, gpointer v_object); +void value_take_scan_device (GValue* value, gpointer v_object); +gpointer value_get_scan_device (const GValue* value); +GType scan_device_get_type (void) G_GNUC_CONST; +gpointer simple_scan_ref (gpointer instance); +void simple_scan_unref (gpointer instance); +GParamSpec* param_spec_simple_scan (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_simple_scan (GValue* value, gpointer v_object); +void value_take_simple_scan (GValue* value, gpointer v_object); +gpointer value_get_simple_scan (const GValue* value); +GType simple_scan_get_type (void) G_GNUC_CONST; +gpointer scanner_ref (gpointer instance); +void scanner_unref (gpointer instance); +GParamSpec* param_spec_scanner (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scanner (GValue* value, gpointer v_object); +void value_take_scanner (GValue* value, gpointer v_object); +gpointer value_get_scanner (const GValue* value); +GType scanner_get_type (void) G_GNUC_CONST; +gpointer book_ref (gpointer instance); +void book_unref (gpointer instance); +GParamSpec* param_spec_book (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_book (GValue* value, gpointer v_object); +void value_take_book (GValue* value, gpointer v_object); +gpointer value_get_book (const GValue* value); +GType book_get_type (void) G_GNUC_CONST; +#define APPLICATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_APPLICATION, ApplicationPrivate)) +enum  { +	APPLICATION_DUMMY_PROPERTY +}; +Application* application_new (ScanDevice* device); +Application* application_construct (GType object_type, ScanDevice* device); +SimpleScan* simple_scan_new (void); +SimpleScan* simple_scan_construct (GType object_type); +Book* simple_scan_get_book (SimpleScan* self); +gpointer scan_options_ref (gpointer instance); +void scan_options_unref (gpointer instance); +GParamSpec* param_spec_scan_options (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_options (GValue* value, gpointer v_object); +void value_take_scan_options (GValue* value, gpointer v_object); +gpointer value_get_scan_options (const GValue* value); +GType scan_options_get_type (void) G_GNUC_CONST; +static void application_scan_cb (Application* self, SimpleScan* ui, const gchar* device, ScanOptions* options); +static void _application_scan_cb_simple_scan_start_scan (SimpleScan* _sender, const gchar* device, ScanOptions* options, gpointer self); +static void application_cancel_cb (Application* self, SimpleScan* ui); +static void _application_cancel_cb_simple_scan_stop_scan (SimpleScan* _sender, gpointer self); +static void application_email_cb (Application* self, SimpleScan* ui, const gchar* profile); +static void _application_email_cb_simple_scan_email (SimpleScan* _sender, const gchar* profile, gpointer self); +static void application_quit_cb (Application* self, SimpleScan* ui); +static void _application_quit_cb_simple_scan_quit (SimpleScan* _sender, gpointer self); +Scanner* scanner_get_instance (void); +static void application_update_scan_devices_cb (Application* self, Scanner* scanner, GList* devices); +static void _application_update_scan_devices_cb_scanner_update_devices (Scanner* _sender, GList* devices, gpointer self); +static void application_authorize_cb (Application* self, Scanner* scanner, const gchar* resource); +static void _application_authorize_cb_scanner_request_authorization (Scanner* _sender, const gchar* resource, gpointer self); +static void application_scanner_new_page_cb (Application* self, Scanner* scanner); +static void _application_scanner_new_page_cb_scanner_expect_page (Scanner* _sender, gpointer self); +gpointer scan_page_info_ref (gpointer instance); +void scan_page_info_unref (gpointer instance); +GParamSpec* param_spec_scan_page_info (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_page_info (GValue* value, gpointer v_object); +void value_take_scan_page_info (GValue* value, gpointer v_object); +gpointer value_get_scan_page_info (const GValue* value); +GType scan_page_info_get_type (void) G_GNUC_CONST; +static void application_scanner_page_info_cb (Application* self, Scanner* scanner, ScanPageInfo* info); +static void _application_scanner_page_info_cb_scanner_got_page_info (Scanner* _sender, ScanPageInfo* info, gpointer self); +gpointer scan_line_ref (gpointer instance); +void scan_line_unref (gpointer instance); +GParamSpec* param_spec_scan_line (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_line (GValue* value, gpointer v_object); +void value_take_scan_line (GValue* value, gpointer v_object); +gpointer value_get_scan_line (const GValue* value); +GType scan_line_get_type (void) G_GNUC_CONST; +static void application_scanner_line_cb (Application* self, Scanner* scanner, ScanLine* line); +static void _application_scanner_line_cb_scanner_got_line (Scanner* _sender, ScanLine* line, gpointer self); +static void application_scanner_page_done_cb (Application* self, Scanner* scanner); +static void _application_scanner_page_done_cb_scanner_page_done (Scanner* _sender, gpointer self); +static void application_scanner_document_done_cb (Application* self, Scanner* scanner); +static void _application_scanner_document_done_cb_scanner_document_done (Scanner* _sender, gpointer self); +static void application_scanner_failed_cb (Application* self, Scanner* scanner, gint error_code, const gchar* error_string); +static void _application_scanner_failed_cb_scanner_scan_failed (Scanner* _sender, gint error_code, const gchar* error_string, gpointer self); +static void application_scanner_scanning_changed_cb (Application* self, Scanner* scanner); +static void _application_scanner_scanning_changed_cb_scanner_scanning_changed (Scanner* _sender, gpointer self); +static void application_on_uevent (Application* self, GUdevClient* client, const gchar* action, GUdevDevice* device); +static void _application_on_uevent_g_udev_client_uevent (GUdevClient* _sender, const gchar* action, GUdevDevice* device, gpointer self); +void simple_scan_set_scan_devices (SimpleScan* self, GList* devices); +void simple_scan_set_selected_device (SimpleScan* self, const gchar* device); +static void _scan_device_unref0_ (gpointer var); +static void _g_list_free__scan_device_unref0_ (GList* self); +void application_start (Application* self); +void simple_scan_start (SimpleScan* self); +void scanner_start (Scanner* self); +void simple_scan_authorize (SimpleScan* self, const gchar* resource, gchar** username, gchar** password); +void scanner_authorize (Scanner* self, const gchar* username, const gchar* password); +gpointer page_ref (gpointer instance); +void page_unref (gpointer instance); +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page (GValue* value, gpointer v_object); +void value_take_page (GValue* value, gpointer v_object); +gpointer value_get_page (const GValue* value); +GType page_get_type (void) G_GNUC_CONST; +static Page* application_append_page (Application* self); +Page* book_get_page (Book* self, gint page_number); +gboolean page_has_data (Page* self); +void simple_scan_set_selected_page (SimpleScan* self, Page* page); +void page_start (Page* self); +GType scan_direction_get_type (void) G_GNUC_CONST; +ScanDirection page_get_scan_direction (Page* self); +gint page_get_width (Page* self); +gint page_get_height (Page* self); +gint page_get_dpi (Page* self); +gboolean page_has_crop (Page* self); +gchar* page_get_named_crop (Page* self); +void page_get_crop (Page* self, gint* x, gint* y, gint* width, gint* height); +Page* book_append_page (Book* self, gint width, gint height, gint dpi, ScanDirection scan_direction); +void page_set_named_crop (Page* self, const gchar* name); +void page_set_custom_crop (Page* self, gint width, gint height); +void page_move_crop (Page* self, gint x, gint y); +static gchar* application_get_profile_for_device (Application* self, const gchar* device_name); +void page_set_page_info (Page* self, ScanPageInfo* info); +void page_set_color_profile (Page* self, const gchar* color_profile); +guint book_get_n_pages (Book* self); +void page_parse_scan_line (Page* self, ScanLine* line); +void page_finish (Page* self); +static void application_remove_empty_page (Application* self); +void book_delete_page (Book* self, Page* page); +void simple_scan_show_error (SimpleScan* self, const gchar* error_title, const gchar* error_text, gboolean change_scanner_hint); +void simple_scan_set_scanning (SimpleScan* self, gboolean scanning); +gboolean scanner_is_scanning (Scanner* self); +GType scan_mode_get_type (void) G_GNUC_CONST; +GType scan_type_get_type (void) G_GNUC_CONST; +void simple_scan_set_default_file_name (SimpleScan* self, const gchar* default_file_name); +void scanner_scan (Scanner* self, const gchar* device, ScanOptions* options); +void scanner_cancel (Scanner* self); +static gchar* application_get_temporary_filename (Application* self, const gchar* prefix, const gchar* extension); +void book_save (Book* self, const gchar* type, GFile* file, GError** error); +void page_save (Page* self, const gchar* type, GFile* file, GError** error); +void scanner_free (Scanner* self); +static void application_log_cb (const gchar* log_domain, GLogLevelFlags log_level, const gchar* message); +void scanner_redetect (Scanner* self); +gint application_main (gchar** args, int args_length1); +ScanDevice* scan_device_new (void); +ScanDevice* scan_device_construct (GType object_type); +static void _application_log_cb_glog_func (const gchar* log_domain, GLogLevelFlags log_levels, const gchar* message, gpointer self); +static void application_finalize (Application* obj); +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func); +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func); + +const GOptionEntry APPLICATION_options[3] = {{"version", 'v', 0, G_OPTION_ARG_NONE, &application_show_version, "Show release version", NULL}, {"debug", 'd', 0, G_OPTION_ARG_NONE, &application_debug_enabled, "Print debugging messages", NULL}, {NULL}}; + +static gpointer _scan_device_ref0 (gpointer self) { +	return self ? scan_device_ref (self) : NULL; +} + + +static void _application_scan_cb_simple_scan_start_scan (SimpleScan* _sender, const gchar* device, ScanOptions* options, gpointer self) { +	application_scan_cb (self, _sender, device, options); +} + + +static void _application_cancel_cb_simple_scan_stop_scan (SimpleScan* _sender, gpointer self) { +	application_cancel_cb (self, _sender); +} + + +static void _application_email_cb_simple_scan_email (SimpleScan* _sender, const gchar* profile, gpointer self) { +	application_email_cb (self, _sender, profile); +} + + +static void _application_quit_cb_simple_scan_quit (SimpleScan* _sender, gpointer self) { +	application_quit_cb (self, _sender); +} + + +static void _application_update_scan_devices_cb_scanner_update_devices (Scanner* _sender, GList* devices, gpointer self) { +	application_update_scan_devices_cb (self, _sender, devices); +} + + +static void _application_authorize_cb_scanner_request_authorization (Scanner* _sender, const gchar* resource, gpointer self) { +	application_authorize_cb (self, _sender, resource); +} + + +static void _application_scanner_new_page_cb_scanner_expect_page (Scanner* _sender, gpointer self) { +	application_scanner_new_page_cb (self, _sender); +} + + +static void _application_scanner_page_info_cb_scanner_got_page_info (Scanner* _sender, ScanPageInfo* info, gpointer self) { +	application_scanner_page_info_cb (self, _sender, info); +} + + +static void _application_scanner_line_cb_scanner_got_line (Scanner* _sender, ScanLine* line, gpointer self) { +	application_scanner_line_cb (self, _sender, line); +} + + +static void _application_scanner_page_done_cb_scanner_page_done (Scanner* _sender, gpointer self) { +	application_scanner_page_done_cb (self, _sender); +} + + +static void _application_scanner_document_done_cb_scanner_document_done (Scanner* _sender, gpointer self) { +	application_scanner_document_done_cb (self, _sender); +} + + +static void _application_scanner_failed_cb_scanner_scan_failed (Scanner* _sender, gint error_code, const gchar* error_string, gpointer self) { +	application_scanner_failed_cb (self, _sender, error_code, error_string); +} + + +static void _application_scanner_scanning_changed_cb_scanner_scanning_changed (Scanner* _sender, gpointer self) { +	application_scanner_scanning_changed_cb (self, _sender); +} + + +static void _application_on_uevent_g_udev_client_uevent (GUdevClient* _sender, const gchar* action, GUdevDevice* device, gpointer self) { +	application_on_uevent (self, _sender, action, device); +} + -#include <sane/sane.h> // For SANE_STATUS_CANCELLED +static void _scan_device_unref0_ (gpointer var) { +	(var == NULL) ? NULL : (var = (scan_device_unref (var), NULL)); +} -#include "ui.h" -#include "scanner.h" -#include "book.h" - - -static ScanDevice *default_device = NULL; - -static gboolean have_devices = FALSE; - -static GUdevClient *udev_client; -static SimpleScan *ui; +static void _g_list_free__scan_device_unref0_ (GList* self) { +	g_list_foreach (self, (GFunc) _scan_device_unref0_, NULL); +	g_list_free (self); +} -static Scanner *scanner; -static Book *book; +Application* application_construct (GType object_type, ScanDevice* device) { +	Application* self = NULL; +	ScanDevice* _tmp0_; +	SimpleScan* _tmp1_ = NULL; +	Book* _tmp2_ = NULL; +	Scanner* _tmp3_ = NULL; +	gchar* _tmp4_; +	gchar** _tmp5_ = NULL; +	gchar** subsystems; +	gint subsystems_length1; +	gint _subsystems_size_; +	GUdevClient* _tmp6_ = NULL; +	self = (Application*) g_type_create_instance (object_type); +	_tmp0_ = _scan_device_ref0 (device); +	_scan_device_unref0 (self->priv->default_device); +	self->priv->default_device = _tmp0_; +	_tmp1_ = simple_scan_new (); +	_simple_scan_unref0 (self->priv->ui); +	self->priv->ui = _tmp1_; +	_tmp2_ = simple_scan_get_book (self->priv->ui); +	_book_unref0 (self->priv->book); +	self->priv->book = _tmp2_; +	g_signal_connect (self->priv->ui, "start-scan", (GCallback) _application_scan_cb_simple_scan_start_scan, self); +	g_signal_connect (self->priv->ui, "stop-scan", (GCallback) _application_cancel_cb_simple_scan_stop_scan, self); +	g_signal_connect (self->priv->ui, "email", (GCallback) _application_email_cb_simple_scan_email, self); +	g_signal_connect (self->priv->ui, "quit", (GCallback) _application_quit_cb_simple_scan_quit, self); +	_tmp3_ = scanner_get_instance (); +	_scanner_unref0 (self->priv->scanner); +	self->priv->scanner = _tmp3_; +	g_signal_connect (self->priv->scanner, "update-devices", (GCallback) _application_update_scan_devices_cb_scanner_update_devices, self); +	g_signal_connect (self->priv->scanner, "request-authorization", (GCallback) _application_authorize_cb_scanner_request_authorization, self); +	g_signal_connect (self->priv->scanner, "expect-page", (GCallback) _application_scanner_new_page_cb_scanner_expect_page, self); +	g_signal_connect (self->priv->scanner, "got-page-info", (GCallback) _application_scanner_page_info_cb_scanner_got_page_info, self); +	g_signal_connect (self->priv->scanner, "got-line", (GCallback) _application_scanner_line_cb_scanner_got_line, self); +	g_signal_connect (self->priv->scanner, "page-done", (GCallback) _application_scanner_page_done_cb_scanner_page_done, self); +	g_signal_connect (self->priv->scanner, "document-done", (GCallback) _application_scanner_document_done_cb_scanner_document_done, self); +	g_signal_connect (self->priv->scanner, "scan-failed", (GCallback) _application_scanner_failed_cb_scanner_scan_failed, self); +	g_signal_connect (self->priv->scanner, "scanning-changed", (GCallback) _application_scanner_scanning_changed_cb_scanner_scanning_changed, self); +	_tmp4_ = g_strdup ("usb"); +	_tmp5_ = g_new0 (gchar*, 2 + 1); +	_tmp5_[0] = _tmp4_; +	_tmp5_[1] = NULL; +	subsystems = _tmp5_; +	subsystems_length1 = 2; +	_subsystems_size_ = subsystems_length1; +	_tmp6_ = g_udev_client_new (subsystems); +	_g_object_unref0 (self->priv->udev_client); +	self->priv->udev_client = _tmp6_; +	g_signal_connect (self->priv->udev_client, "uevent", (GCallback) _application_on_uevent_g_udev_client_uevent, self); +	if (self->priv->default_device != NULL) { +		GList* device_list; +		ScanDevice* _tmp7_; +		device_list = NULL; +		_tmp7_ = _scan_device_ref0 (self->priv->default_device); +		device_list = g_list_append (device_list, _tmp7_); +		simple_scan_set_scan_devices (self->priv->ui, device_list); +		simple_scan_set_selected_device (self->priv->ui, self->priv->default_device->name); +		__g_list_free__scan_device_unref0_0 (device_list); +	} +	subsystems = (_vala_array_free (subsystems, subsystems_length1, (GDestroyNotify) g_free), NULL); +	return self; +} -static GTimer *log_timer; -static FILE *log_file; +Application* application_new (ScanDevice* device) { +	return application_construct (TYPE_APPLICATION, device); +} -static gboolean debug = FALSE; +void application_start (Application* self) { +	g_return_if_fail (self != NULL); +	simple_scan_start (self->priv->ui); +	scanner_start (self->priv->scanner); +} -static void -update_scan_devices_cb (Scanner *scanner, GList *devices) -{ -    GList *devices_copy; -   -    devices_copy = g_list_copy (devices); -   -    /* If the default device is not detected add it to the list */ -    if (default_device) { -        GList *i; - -        for (i = devices_copy; i; i = i->next) { -            ScanDevice *device = i->data; -            if (strcmp (device->name, default_device->name) == 0) -                break; -        } - -        if (!i) -            devices_copy = g_list_prepend (devices_copy, default_device); -    } - -    have_devices = devices_copy != NULL; -    ui_set_scan_devices (ui, devices_copy); -   -    g_list_free (devices_copy); -} - - -static void -authorize_cb (Scanner *scanner, const gchar *resource) -{ -    gchar *username = NULL, *password = NULL; -    ui_authorize (ui, resource, &username, &password); -    scanner_authorize (scanner, username, password); -    g_free (username); -    g_free (password); -} - - -static Page * -append_page () -{ -    Page *page; -    ScanDirection scan_direction = TOP_TO_BOTTOM; -    gboolean do_crop = FALSE; -    gchar *named_crop = NULL; -    gint width = 100, height = 100, dpi = 100, cx, cy, cw, ch; - -    /* Use current page if not used */ -    page = book_get_page (book, -1); -    if (page && !page_has_data (page)) { -        ui_set_selected_page (ui, page); -        page_start (page); -        return page; -    } -   -    /* Copy info from previous page */ -    if (page) { -        scan_direction = page_get_scan_direction (page); -        width = page_get_width (page); -        height = page_get_height (page); -        dpi = page_get_dpi (page); - -        do_crop = page_has_crop (page); -        if (do_crop) { -            named_crop = page_get_named_crop (page); -            page_get_crop (page, &cx, &cy, &cw, &ch); -        } -    } - -    page = book_append_page (book, width, height, dpi, scan_direction); -    if (do_crop) { -        if (named_crop)  { -            page_set_named_crop (page, named_crop); -            g_free (named_crop); -        } -        else -            page_set_custom_crop (page, cw, ch); -        page_move_crop (page, cx, cy); -    } -    ui_set_selected_page (ui, page); -    page_start (page); -   -    return page; -} - - -static void -scanner_new_page_cb (Scanner *scanner) -{ -    append_page (); -} - - -static gchar * -get_profile_for_device (const gchar *current_device) -{ -    gboolean ret; -    DBusGConnection *connection; -    DBusGProxy *proxy; -    GError *error = NULL; -    GType custom_g_type_string_string; -    GPtrArray *profile_data_array = NULL; -    gchar *device_id = NULL; -    gchar *icc_profile = NULL; - -    /* Connect to the color manager on the session bus */ -    connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); -    proxy = dbus_g_proxy_new_for_name (connection, -                                       "org.gnome.ColorManager", -                                       "/org/gnome/ColorManager", -                                       "org.gnome.ColorManager"); - -    /* Get color profile */ -    device_id = g_strdup_printf ("sane:%s", current_device); -    custom_g_type_string_string = dbus_g_type_get_collection ("GPtrArray", -                                                              dbus_g_type_get_struct("GValueArray", -                                                                                     G_TYPE_STRING, -                                                                                     G_TYPE_STRING, -                                                                                     G_TYPE_INVALID)); -    ret = dbus_g_proxy_call (proxy, "GetProfilesForDevice", &error, -                             G_TYPE_STRING, device_id, -                             G_TYPE_STRING, "", -                             G_TYPE_INVALID, -                             custom_g_type_string_string, &profile_data_array, -                             G_TYPE_INVALID); -    g_object_unref (proxy); -    g_free (device_id); -    if (!ret) { -        g_debug ("The request failed: %s", error->message); -        g_error_free (error); -        return NULL; -    } - -    if (profile_data_array->len > 0) { -        GValueArray *gva; -        GValue *gv = NULL; - -        /* Just use the preferred profile filename */ -        gva = (GValueArray *) g_ptr_array_index (profile_data_array, 0); -        gv = g_value_array_get_nth (gva, 1); -        icc_profile = g_value_dup_string (gv); -        g_value_unset (gv); -    } -    else -        g_debug ("There are no ICC profiles for the device sane:%s", current_device); -    g_ptr_array_free (profile_data_array, TRUE); - -    return icc_profile; -} - - -static void -scanner_page_info_cb (Scanner *scanner, ScanPageInfo *info) -{ -    Page *page; - -    g_debug ("Page is %d pixels wide, %d pixels high, %d bits per pixel", -             info->width, info->height, info->depth); -    /* Add a new page */ -    page = append_page (); -    page_set_page_info (page, info); +static void application_update_scan_devices_cb (Application* self, Scanner* scanner, GList* devices) { +	GList* _tmp0_ = NULL; +	GList* devices_copy; +	guint _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	_tmp0_ = g_list_copy (devices); +	devices_copy = _tmp0_; +	if (self->priv->default_device != NULL) { +		gboolean default_in_list; +		default_in_list = FALSE; +		{ +			GList* device_collection = NULL; +			GList* device_it = NULL; +			device_collection = devices_copy; +			for (device_it = device_collection; device_it != NULL; device_it = device_it->next) { +				ScanDevice* device = NULL; +				device = (ScanDevice*) device_it->data; +				{ +					if (g_strcmp0 (device->name, self->priv->default_device->name) == 0) { +						default_in_list = TRUE; +						break; +					} +				} +			} +		} +		if (!default_in_list) { +			devices_copy = g_list_prepend (devices_copy, self->priv->default_device); +		} +	} +	_tmp1_ = g_list_length (devices_copy); +	self->priv->have_devices = _tmp1_ > ((guint) 0); +	simple_scan_set_scan_devices (self->priv->ui, devices_copy); +	_g_list_free0 (devices_copy); +} + -    /* Get ICC color profile */ -    /* FIXME: The ICC profile could change */ -    /* FIXME: Don't do a D-bus call for each page, cache color profiles */ -    page_set_color_profile (page, get_profile_for_device (info->device)); +static void application_authorize_cb (Application* self, Scanner* scanner, const gchar* resource) { +	gchar* username = NULL; +	gchar* password = NULL; +	gchar* _tmp0_ = NULL; +	gchar* _tmp1_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	g_return_if_fail (resource != NULL); +	simple_scan_authorize (self->priv->ui, resource, &_tmp0_, &_tmp1_); +	_g_free0 (username); +	username = _tmp0_; +	_g_free0 (password); +	password = _tmp1_; +	scanner_authorize (scanner, username, password); +	_g_free0 (password); +	_g_free0 (username);  } -static void -scanner_line_cb (Scanner *scanner, ScanLine *line) -{ -    Page *page; +static Page* application_append_page (Application* self) { +	Page* result = NULL; +	Page* _tmp0_ = NULL; +	Page* page; +	gboolean _tmp1_ = FALSE; +	ScanDirection scan_direction; +	gboolean do_crop; +	gchar* named_crop; +	gint width; +	gint height; +	gint dpi; +	gint cx; +	gint cy; +	gint cw; +	gint ch; +	Page* _tmp13_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = book_get_page (self->priv->book, -1); +	page = _tmp0_; +	if (page != NULL) { +		gboolean _tmp2_; +		_tmp2_ = page_has_data (page); +		_tmp1_ = !_tmp2_; +	} else { +		_tmp1_ = FALSE; +	} +	if (_tmp1_) { +		simple_scan_set_selected_page (self->priv->ui, page); +		page_start (page); +		result = page; +		return result; +	} +	scan_direction = SCAN_DIRECTION_TOP_TO_BOTTOM; +	do_crop = FALSE; +	named_crop = NULL; +	width = 100; +	height = 100; +	dpi = 100; +	cx = 0; +	cy = 0; +	cw = 0; +	ch = 0; +	if (page != NULL) { +		ScanDirection _tmp3_; +		gint _tmp4_; +		gint _tmp5_; +		gint _tmp6_; +		gboolean _tmp7_; +		_tmp3_ = page_get_scan_direction (page); +		scan_direction = _tmp3_; +		_tmp4_ = page_get_width (page); +		width = _tmp4_; +		_tmp5_ = page_get_height (page); +		height = _tmp5_; +		_tmp6_ = page_get_dpi (page); +		dpi = _tmp6_; +		_tmp7_ = page_has_crop (page); +		do_crop = _tmp7_; +		if (do_crop) { +			gchar* _tmp8_ = NULL; +			gint _tmp9_; +			gint _tmp10_; +			gint _tmp11_; +			gint _tmp12_; +			_tmp8_ = page_get_named_crop (page); +			_g_free0 (named_crop); +			named_crop = _tmp8_; +			page_get_crop (page, &_tmp9_, &_tmp10_, &_tmp11_, &_tmp12_); +			cx = _tmp9_; +			cy = _tmp10_; +			cw = _tmp11_; +			ch = _tmp12_; +		} +	} +	_tmp13_ = book_append_page (self->priv->book, width, height, dpi, scan_direction); +	_page_unref0 (page); +	page = _tmp13_; +	if (do_crop) { +		if (named_crop != NULL) { +			page_set_named_crop (page, named_crop); +		} else { +			page_set_custom_crop (page, cw, ch); +		} +		page_move_crop (page, cx, cy); +	} +	simple_scan_set_selected_page (self->priv->ui, page); +	page_start (page); +	result = page; +	_g_free0 (named_crop); +	return result; +} + -    page = book_get_page (book, book_get_n_pages (book) - 1); -    page_parse_scan_line (page, line); +static void application_scanner_new_page_cb (Application* self, Scanner* scanner) { +	Page* _tmp0_ = NULL; +	Page* _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	_tmp0_ = application_append_page (self); +	_tmp1_ = _tmp0_; +	_page_unref0 (_tmp1_);  } -static void -scanner_page_done_cb (Scanner *scanner) -{ -    Page *page; -    page = book_get_page (book, book_get_n_pages (book) - 1); -    page_finish (page); +static gchar* application_get_profile_for_device (Application* self, const gchar* device_name) { +	gchar* result = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (device_name != NULL, NULL); +	result = NULL; +	return result;  } -static void -remove_empty_page () -{ -    Page *page; +static void application_scanner_page_info_cb (Application* self, Scanner* scanner, ScanPageInfo* info) { +	Page* _tmp0_ = NULL; +	Page* page; +	gchar* _tmp1_ = NULL; +	gchar* _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	g_return_if_fail (info != NULL); +	g_debug ("simple-scan.vala:233: Page is %d pixels wide, %d pixels high, %d bits " \ +"per pixel", info->width, info->height, info->depth); +	_tmp0_ = application_append_page (self); +	page = _tmp0_; +	page_set_page_info (page, info); +	_tmp1_ = application_get_profile_for_device (self, info->device); +	_tmp2_ = _tmp1_; +	page_set_color_profile (page, _tmp2_); +	_g_free0 (_tmp2_); +	_page_unref0 (page); +} -    page = book_get_page (book, book_get_n_pages (book) - 1); -    /* Remove a failed page */ -    if (page_has_data (page)) -        page_finish (page); -    else -        book_delete_page (book, page);  +static void application_scanner_line_cb (Application* self, Scanner* scanner, ScanLine* line) { +	guint _tmp0_; +	Page* _tmp1_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	g_return_if_fail (line != NULL); +	_tmp0_ = book_get_n_pages (self->priv->book); +	_tmp1_ = book_get_page (self->priv->book, ((gint) _tmp0_) - 1); +	page = _tmp1_; +	page_parse_scan_line (page, line); +	_page_unref0 (page);  } -static void -scanner_document_done_cb (Scanner *scanner) -{ -    remove_empty_page (); +static void application_scanner_page_done_cb (Application* self, Scanner* scanner) { +	guint _tmp0_; +	Page* _tmp1_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	_tmp0_ = book_get_n_pages (self->priv->book); +	_tmp1_ = book_get_page (self->priv->book, ((gint) _tmp0_) - 1); +	page = _tmp1_; +	page_finish (page); +	_page_unref0 (page);  } -static void -scanner_failed_cb (Scanner *scanner, GError *error) -{ -    remove_empty_page (); -    if (!g_error_matches (error, SCANNER_TYPE, SANE_STATUS_CANCELLED)) { -        ui_show_error (ui, -                       /* Title of error dialog when scan failed */ -                       _("Failed to scan"), -                       error->message, -                       have_devices); -    } +static void application_remove_empty_page (Application* self) { +	guint _tmp0_; +	Page* _tmp1_ = NULL; +	Page* page; +	gboolean _tmp2_; +	g_return_if_fail (self != NULL); +	_tmp0_ = book_get_n_pages (self->priv->book); +	_tmp1_ = book_get_page (self->priv->book, ((gint) _tmp0_) - 1); +	page = _tmp1_; +	_tmp2_ = page_has_data (page); +	if (_tmp2_) { +		page_finish (page); +	} else { +		book_delete_page (self->priv->book, page); +	} +	_page_unref0 (page);  } -static void -scanner_scanning_changed_cb (Scanner *scanner) -{ -    ui_set_scanning (ui, scanner_is_scanning (scanner)); +static void application_scanner_document_done_cb (Application* self, Scanner* scanner) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	application_remove_empty_page (self);  } -static void -scan_cb (SimpleScan *ui, const gchar *device, ScanOptions *options) -{ -    /* Default filename to use when saving document (and extension will be added, e.g. .jpg) */ -    const gchar *filename_prefix = _("Scanned Document"); -    const gchar *extension; -    gchar *filename; +static void application_scanner_failed_cb (Application* self, Scanner* scanner, gint error_code, const gchar* error_string) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	g_return_if_fail (error_string != NULL); +	application_remove_empty_page (self); +	if (error_code != ((gint) SANE_STATUS_CANCELLED)) { +		const gchar* _tmp0_ = NULL; +		_tmp0_ = _ ("Failed to scan"); +		simple_scan_show_error (self->priv->ui, _tmp0_, error_string, self->priv->have_devices); +	} +} -    if (options->scan_mode == SCAN_MODE_COLOR) -        extension = "jpg"; -    else -        extension = "pdf"; -    g_debug ("Requesting scan at %d dpi from device '%s'", options->dpi, device); +static void application_scanner_scanning_changed_cb (Application* self, Scanner* scanner) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (scanner != NULL); +	_tmp0_ = scanner_is_scanning (scanner); +	simple_scan_set_scanning (self->priv->ui, _tmp0_); +} -    if (!scanner_is_scanning (scanner)) -        append_page (); -    filename = g_strdup_printf ("%s.%s", filename_prefix, extension); -    ui_set_default_file_name (ui, filename); -    g_free (filename); -    scanner_scan (scanner, device, options); +static void application_scan_cb (Application* self, SimpleScan* ui, const gchar* device, ScanOptions* options) { +	gboolean _tmp0_; +	const gchar* _tmp3_ = NULL; +	gchar* _tmp4_; +	gchar* filename_prefix; +	gchar* extension = NULL; +	gchar* _tmp7_ = NULL; +	gchar* filename; +	g_return_if_fail (self != NULL); +	g_return_if_fail (ui != NULL); +	g_return_if_fail (options != NULL); +	g_debug ("simple-scan.vala:293: Requesting scan at %d dpi from device '%s'", options->dpi, device); +	_tmp0_ = scanner_is_scanning (self->priv->scanner); +	if (!_tmp0_) { +		Page* _tmp1_ = NULL; +		Page* _tmp2_; +		_tmp1_ = application_append_page (self); +		_tmp2_ = _tmp1_; +		_page_unref0 (_tmp2_); +	} +	_tmp3_ = _ ("Scanned Document"); +	_tmp4_ = g_strdup (_tmp3_); +	filename_prefix = _tmp4_; +	if (options->scan_mode == SCAN_MODE_COLOR) { +		gchar* _tmp5_; +		_tmp5_ = g_strdup ("jpg"); +		_g_free0 (extension); +		extension = _tmp5_; +	} else { +		gchar* _tmp6_; +		_tmp6_ = g_strdup ("pdf"); +		_g_free0 (extension); +		extension = _tmp6_; +	} +	_tmp7_ = g_strdup_printf ("%s.%s", filename_prefix, extension); +	filename = _tmp7_; +	simple_scan_set_default_file_name (ui, filename); +	scanner_scan (self->priv->scanner, device, options); +	_g_free0 (filename); +	_g_free0 (extension); +	_g_free0 (filename_prefix);  } -static void -cancel_cb (SimpleScan *ui) -{ -    scanner_cancel (scanner); +static void application_cancel_cb (Application* self, SimpleScan* ui) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (ui != NULL); +	scanner_cancel (self->priv->scanner);  } -static gchar * -get_temporary_filename (const gchar *prefix, const gchar *extension) -{ -    gint fd; -    gchar *filename, *path; -    GError *error = NULL; +static gchar* application_get_temporary_filename (Application* self, const gchar* prefix, const gchar* extension) { +	gchar* result = NULL; +	gchar* _tmp0_ = NULL; +	gchar* filename; +	gchar* path = NULL; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (prefix != NULL, NULL); +	g_return_val_if_fail (extension != NULL, NULL); +	_tmp0_ = g_strdup_printf ("%sXXXXXX.%s", prefix, extension); +	filename = _tmp0_; +	{ +		gchar* _tmp1_ = NULL; +		gint _tmp2_; +		gint fd; +		_tmp2_ = g_file_open_tmp (filename, &_tmp1_, &_inner_error_); +		_g_free0 (path); +		path = _tmp1_; +		fd = _tmp2_; +		if (_inner_error_ != NULL) { +			goto __catch3_g_error; +		} +		close (fd); +	} +	goto __finally3; +	__catch3_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("simple-scan.vala:329: Error saving email attachment: %s", e->message); +		result = NULL; +		_g_error_free0 (e); +		_g_free0 (path); +		_g_free0 (filename); +		return result; +	} +	__finally3: +	if (_inner_error_ != NULL) { +		_g_free0 (path); +		_g_free0 (filename); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return NULL; +	} +	result = path; +	_g_free0 (filename); +	return result; +} + -    /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and -     * use the filename but it appears to work in practise */ +static void application_email_cb (Application* self, SimpleScan* ui, const gchar* profile) { +	gboolean saved; +	gchar* _tmp0_; +	gchar* command_line; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (ui != NULL); +	g_return_if_fail (profile != NULL); +	saved = FALSE; +	_tmp0_ = g_strdup ("xdg-email"); +	command_line = _tmp0_; +	if (g_strcmp0 (profile, "text") == 0) { +		gchar* _tmp1_ = NULL; +		gchar* path; +		_tmp1_ = application_get_temporary_filename (self, "scan", "pdf"); +		path = _tmp1_; +		if (path != NULL) { +			GFile* _tmp2_ = NULL; +			GFile* file; +			gchar* _tmp3_ = NULL; +			gchar* _tmp4_; +			gchar* _tmp5_; +			_tmp2_ = g_file_new_for_path (path); +			file = _tmp2_; +			{ +				book_save (self->priv->book, "pdf", file, &_inner_error_); +				if (_inner_error_ != NULL) { +					goto __catch4_g_error; +				} +			} +			goto __finally4; +			__catch4_g_error: +			{ +				GError* e = NULL; +				e = _inner_error_; +				_inner_error_ = NULL; +				g_warning ("simple-scan.vala:355: Unable to save email file: %s", e->message); +				_g_error_free0 (e); +				_g_object_unref0 (file); +				_g_free0 (path); +				_g_free0 (command_line); +				return; +			} +			__finally4: +			if (_inner_error_ != NULL) { +				_g_object_unref0 (file); +				_g_free0 (path); +				_g_free0 (command_line); +				g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +				g_clear_error (&_inner_error_); +				return; +			} +			_tmp3_ = g_strdup_printf (" --attach %s", path); +			_tmp4_ = _tmp3_; +			_tmp5_ = g_strconcat (command_line, _tmp4_, NULL); +			_g_free0 (command_line); +			command_line = _tmp5_; +			_g_free0 (_tmp4_); +			_g_object_unref0 (file); +		} +		_g_free0 (path); +	} else { +		{ +			gint i; +			i = 0; +			{ +				gboolean _tmp6_; +				_tmp6_ = TRUE; +				while (TRUE) { +					guint _tmp7_; +					gchar* _tmp8_ = NULL; +					gchar* path; +					GFile* _tmp9_ = NULL; +					GFile* file; +					gchar* _tmp12_ = NULL; +					gchar* _tmp13_; +					gchar* _tmp14_; +					if (!_tmp6_) { +						i++; +					} +					_tmp6_ = FALSE; +					_tmp7_ = book_get_n_pages (self->priv->book); +					if (!(((guint) i) < _tmp7_)) { +						break; +					} +					_tmp8_ = application_get_temporary_filename (self, "scan", "jpg"); +					path = _tmp8_; +					if (path == NULL) { +						saved = FALSE; +						_g_free0 (path); +						break; +					} +					_tmp9_ = g_file_new_for_path (path); +					file = _tmp9_; +					{ +						Page* _tmp10_ = NULL; +						Page* _tmp11_; +						_tmp10_ = book_get_page (self->priv->book, i); +						_tmp11_ = _tmp10_; +						page_save (_tmp11_, "jpeg", file, &_inner_error_); +						_page_unref0 (_tmp11_); +						if (_inner_error_ != NULL) { +							goto __catch5_g_error; +						} +					} +					goto __finally5; +					__catch5_g_error: +					{ +						GError* e = NULL; +						e = _inner_error_; +						_inner_error_ = NULL; +						g_warning ("simple-scan.vala:379: Unable to save email file: %s", e->message); +						_g_error_free0 (e); +						_g_object_unref0 (file); +						_g_free0 (path); +						_g_free0 (command_line); +						return; +					} +					__finally5: +					if (_inner_error_ != NULL) { +						_g_object_unref0 (file); +						_g_free0 (path); +						_g_free0 (command_line); +						g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +						g_clear_error (&_inner_error_); +						return; +					} +					_tmp12_ = g_strdup_printf (" --attach %s", path); +					_tmp13_ = _tmp12_; +					_tmp14_ = g_strconcat (command_line, _tmp13_, NULL); +					_g_free0 (command_line); +					command_line = _tmp14_; +					_g_free0 (_tmp13_); +					if (!saved) { +						_g_object_unref0 (file); +						_g_free0 (path); +						break; +					} +					_g_object_unref0 (file); +					_g_free0 (path); +				} +			} +		} +	} +	g_debug ("simple-scan.vala:389: Launching email client: %s", command_line); +	{ +		g_spawn_command_line_async (command_line, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch6_g_error; +		} +	} +	goto __finally6; +	__catch6_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("simple-scan.vala:396: Unable to start email: %s", e->message); +		_g_error_free0 (e); +	} +	__finally6: +	if (_inner_error_ != NULL) { +		_g_free0 (command_line); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +	_g_free0 (command_line); +} -    filename = g_strdup_printf ("%sXXXXXX.%s", prefix, extension); -    fd = g_file_open_tmp (filename, &path, &error); -    g_free (filename); -    if (fd < 0) { -        g_warning ("Error saving email attachment: %s", error->message); -        g_clear_error (&error); -        return NULL; -    } -    close (fd); -    return path; +static void application_quit_cb (Application* self, SimpleScan* ui) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (ui != NULL); +	_book_unref0 (self->priv->book); +	self->priv->book = NULL; +	ui = NULL; +	_g_object_unref0 (self->priv->udev_client); +	self->priv->udev_client = NULL; +	scanner_free (self->priv->scanner); +	gtk_main_quit ();  } -static void -email_cb (SimpleScan *ui, const gchar *profile) -{ -    gboolean saved = FALSE; -    GError *error = NULL; -    GString *command_line; -   -    command_line = g_string_new ("xdg-email"); - -    /* Save text files as PDFs */ -    if (strcmp (profile, "text") == 0) { -        gchar *path; - -        /* Open a temporary file */ -        path = get_temporary_filename ("scan", "pdf"); -        if (path) { -            GFile *file; - -            file = g_file_new_for_path (path); -            saved = book_save (book, "pdf", file, &error); -            g_string_append_printf (command_line, " --attach %s", path); -            g_free (path); -            g_object_unref (file); -        } -    } -    else { -        gint i; - -        for (i = 0; i < book_get_n_pages (book); i++) { -            gchar *path; -            GFile *file; - -            path = get_temporary_filename ("scan", "jpg"); -            if (!path) { -                saved = FALSE; -                break; -            } - -            file = g_file_new_for_path (path); -            saved = page_save (book_get_page (book, i), "jpeg", file, &error); -            g_string_append_printf (command_line, " --attach %s", path); -            g_free (path); -            g_object_unref (file); -           -            if (!saved) -                break; -        } -    } - -    if (saved) { -        g_debug ("Launchind email client: %s", command_line->str); -        g_spawn_command_line_async (command_line->str, &error); - -        if (error) { -            g_warning ("Unable to start email: %s", error->message); -            g_clear_error (&error); -        } -    } -    else { -        g_warning ("Unable to save email file: %s", error->message); -        g_clear_error (&error); -    } - -    g_string_free (command_line, TRUE); -} - - -static void -quit_cb (SimpleScan *ui) -{ -    g_object_unref (book); -    g_object_unref (ui); -    g_object_unref (udev_client); -    scanner_free (scanner); -    gtk_main_quit (); -} - - -static void -version() -{ -    /* NOTE: Is not translated so can be easily parsed */ -    fprintf(stderr, "%1$s %2$s\n", SIMPLE_SCAN_BINARY, VERSION); -} - - -static void -usage(int show_gtk) -{ -    fprintf(stderr, -            /* Description on how to use simple-scan displayed on command-line */ -            _("Usage:\n" -              "  %s [DEVICE...] - Scanning utility"), SIMPLE_SCAN_BINARY); - -    fprintf(stderr, -            "\n\n"); - -    fprintf(stderr, -            /* Description on how to use simple-scan displayed on command-line */     -            _("Help Options:\n" -              "  -d, --debug                     Print debugging messages\n" -              "  -v, --version                   Show release version\n" -              "  -h, --help                      Show help options\n" -              "  --help-all                      Show all help options\n" -              "  --help-gtk                      Show GTK+ options")); -    fprintf(stderr, -            "\n\n"); - -    if (show_gtk) { -        fprintf(stderr, -                /* Description on simple-scan command-line GTK+ options displayed on command-line */ -                _("GTK+ Options:\n" -                  "  --class=CLASS                   Program class as used by the window manager\n" -                  "  --name=NAME                     Program name as used by the window manager\n" -                  "  --screen=SCREEN                 X screen to use\n" -                  "  --sync                          Make X calls synchronous\n" -                  "  --gtk-module=MODULES            Load additional GTK+ modules\n" -                  "  --g-fatal-warnings              Make all warnings fatal")); -        fprintf(stderr, -                "\n\n"); -    } -} - - -static void -log_cb (const gchar *log_domain, GLogLevelFlags log_level, -        const gchar *message, gpointer data) -{ -    /* Log everything to a file */ -    if (log_file) { -        const gchar *prefix; - -        switch (log_level & G_LOG_LEVEL_MASK) { -        case G_LOG_LEVEL_ERROR: -            prefix = "ERROR:"; -            break; -        case G_LOG_LEVEL_CRITICAL: -            prefix = "CRITICAL:"; -            break; -        case G_LOG_LEVEL_WARNING: -            prefix = "WARNING:"; -            break; -        case G_LOG_LEVEL_MESSAGE: -            prefix = "MESSAGE:"; -            break; -        case G_LOG_LEVEL_INFO: -            prefix = "INFO:"; -            break; -        case G_LOG_LEVEL_DEBUG: -            prefix = "DEBUG:"; -            break; -        default: -            prefix = "LOG:"; -            break; -        } - -        fprintf (log_file, "[%+.2fs] %s %s\n", g_timer_elapsed (log_timer, NULL), prefix, message); -    } - -    /* Only show debug if requested */ -    if (log_level & G_LOG_LEVEL_DEBUG) { -        if (debug) -            g_log_default_handler (log_domain, log_level, message, data); -    } -    else -        g_log_default_handler (log_domain, log_level, message, data);     -} - - -static void -get_options (int argc, char **argv) -{ -    int i; - -    for (i = 1; i < argc; i++) { -        char *arg = argv[i]; - -        if (strcmp (arg, "-d") == 0 || -            strcmp (arg, "--debug") == 0) { -            debug = TRUE; -        } -        else if (strcmp (arg, "-v") == 0 || -            strcmp (arg, "--version") == 0) { -            version (); -            exit (0); -        } -        else if (strcmp (arg, "-h") == 0 || -                 strcmp (arg, "--help") == 0) { -            usage (FALSE); -            exit (0); -        } -        else if (strcmp (arg, "--help-all") == 0 || -                 strcmp (arg, "--help-gtk") == 0) { -            usage (TRUE); -            exit (0); -        } -        else { -            if (default_device) { -                fprintf (stderr, "Unknown argument: '%s'\n", arg); -                exit (1); -            } -            default_device = g_malloc0 (sizeof (ScanDevice)); -            default_device->name = g_strdup (arg); -            default_device->label = g_strdup (arg); -        } -    }    -} - - -static void -on_uevent (GUdevClient *client, const gchar *action, GUdevDevice *device) -{ -    scanner_redetect (scanner); -} - - -int -main (int argc, char **argv) -{ -    const char *udev_subsystems[] = { "usb", NULL }; -    gchar *path; - -    g_thread_init (NULL); - -    /* Log to a file */ -    log_timer = g_timer_new (); -    path = g_build_filename (g_get_user_cache_dir (), "simple-scan", NULL); -    g_mkdir_with_parents (path, 0700); -    g_free (path); -    path = g_build_filename (g_get_user_cache_dir (), "simple-scan", "simple-scan.log", NULL); -    log_file = fopen (path, "w"); -    g_free (path); -    g_log_set_default_handler (log_cb, NULL); - -    bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); -    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -    textdomain (GETTEXT_PACKAGE); -    -    gtk_init (&argc, &argv); - -    get_options (argc, argv); -   -    g_debug ("Starting Simple Scan %s, PID=%i", VERSION, getpid ()); -   -    ui = ui_new (); -    book = ui_get_book (ui); -    g_signal_connect (ui, "start-scan", G_CALLBACK (scan_cb), NULL); -    g_signal_connect (ui, "stop-scan", G_CALLBACK (cancel_cb), NULL); -    g_signal_connect (ui, "email", G_CALLBACK (email_cb), NULL); -    g_signal_connect (ui, "quit", G_CALLBACK (quit_cb), NULL); - -    scanner = scanner_new (); -    g_signal_connect (G_OBJECT (scanner), "update-devices", G_CALLBACK (update_scan_devices_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "authorize", G_CALLBACK (authorize_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "expect-page", G_CALLBACK (scanner_new_page_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "got-page-info", G_CALLBACK (scanner_page_info_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "got-line", G_CALLBACK (scanner_line_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "page-done", G_CALLBACK (scanner_page_done_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "document-done", G_CALLBACK (scanner_document_done_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "scan-failed", G_CALLBACK (scanner_failed_cb), NULL); -    g_signal_connect (G_OBJECT (scanner), "scanning-changed", G_CALLBACK (scanner_scanning_changed_cb), NULL); - -    udev_client = g_udev_client_new (udev_subsystems); -    g_signal_connect (udev_client, "uevent", G_CALLBACK (on_uevent), NULL); - -    if (default_device) { -        GList device_list; - -        device_list.data = default_device; -        device_list.next = NULL; -        device_list.prev = NULL; -        ui_set_scan_devices (ui, &device_list); -        ui_set_selected_device (ui, default_device->name); -    } - -    ui_start (ui); -    scanner_start (scanner); - -    gtk_main (); - -    return 0; +static void application_log_cb (const gchar* log_domain, GLogLevelFlags log_level, const gchar* message) { +	g_return_if_fail (message != NULL); +	if (application_log_file != NULL) { +		gchar* prefix = NULL; +		gdouble _tmp7_; +		switch (log_level & G_LOG_LEVEL_MASK) { +			case G_LOG_LEVEL_ERROR: +			{ +				gchar* _tmp0_; +				_tmp0_ = g_strdup ("ERROR:"); +				_g_free0 (prefix); +				prefix = _tmp0_; +				break; +			} +			case G_LOG_LEVEL_CRITICAL: +			{ +				gchar* _tmp1_; +				_tmp1_ = g_strdup ("CRITICAL:"); +				_g_free0 (prefix); +				prefix = _tmp1_; +				break; +			} +			case G_LOG_LEVEL_WARNING: +			{ +				gchar* _tmp2_; +				_tmp2_ = g_strdup ("WARNING:"); +				_g_free0 (prefix); +				prefix = _tmp2_; +				break; +			} +			case G_LOG_LEVEL_MESSAGE: +			{ +				gchar* _tmp3_; +				_tmp3_ = g_strdup ("MESSAGE:"); +				_g_free0 (prefix); +				prefix = _tmp3_; +				break; +			} +			case G_LOG_LEVEL_INFO: +			{ +				gchar* _tmp4_; +				_tmp4_ = g_strdup ("INFO:"); +				_g_free0 (prefix); +				prefix = _tmp4_; +				break; +			} +			case G_LOG_LEVEL_DEBUG: +			{ +				gchar* _tmp5_; +				_tmp5_ = g_strdup ("DEBUG:"); +				_g_free0 (prefix); +				prefix = _tmp5_; +				break; +			} +			default: +			{ +				gchar* _tmp6_; +				_tmp6_ = g_strdup ("LOG:"); +				_g_free0 (prefix); +				prefix = _tmp6_; +				break; +			} +		} +		_tmp7_ = g_timer_elapsed (application_log_timer, NULL); +		fprintf (application_log_file, "[%+.2fs] %s %s\n", _tmp7_, prefix, message); +		_g_free0 (prefix); +	} +	if ((log_level & G_LOG_LEVEL_DEBUG) != 0) { +		if (application_debug_enabled) { +			g_log_default_handler (log_domain, log_level, message, NULL); +		} +	} else { +		g_log_default_handler (log_domain, log_level, message, NULL); +	}  } + + +static void application_on_uevent (Application* self, GUdevClient* client, const gchar* action, GUdevDevice* device) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (client != NULL); +	g_return_if_fail (action != NULL); +	g_return_if_fail (device != NULL); +	scanner_redetect (self->priv->scanner); +} + + +static void _application_log_cb_glog_func (const gchar* log_domain, GLogLevelFlags log_levels, const gchar* message, gpointer self) { +	application_log_cb (log_domain, log_levels, message); +} + + +gint application_main (gchar** args, int args_length1) { +	gint result = 0; +	const gchar* _tmp0_ = NULL; +	GOptionContext* _tmp1_ = NULL; +	GOptionContext* c; +	GOptionGroup* _tmp2_ = NULL; +	ScanDevice* device; +	GTimer* _tmp7_ = NULL; +	const gchar* _tmp8_ = NULL; +	gchar* _tmp9_ = NULL; +	gchar* path; +	const gchar* _tmp10_ = NULL; +	gchar* _tmp11_ = NULL; +	FILE* _tmp12_ = NULL; +	pid_t _tmp13_; +	Application* _tmp14_ = NULL; +	Application* app; +	GError * _inner_error_ = NULL; +	setlocale (LC_ALL, ""); +	bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); +	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +	textdomain (GETTEXT_PACKAGE); +	gtk_init (&args_length1, &args); +	_tmp0_ = _ ("[DEVICE...] - Scanning utility"); +	_tmp1_ = g_option_context_new (_tmp0_); +	c = _tmp1_; +	g_option_context_add_main_entries (c, APPLICATION_options, GETTEXT_PACKAGE); +	_tmp2_ = gtk_get_option_group (TRUE); +	g_option_context_add_group (c, _tmp2_); +	{ +		g_option_context_parse (c, &args_length1, &args, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch7_g_error; +		} +	} +	goto __finally7; +	__catch7_g_error: +	{ +		GError* e = NULL; +		const gchar* _tmp3_ = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		fprintf (stderr, "%s\n", e->message); +		_tmp3_ = _ ("Run '%s --help' to see a full list of available command line options."); +		fprintf (stderr, _tmp3_, args[0]); +		fprintf (stderr, "\n"); +		result = EXIT_FAILURE; +		_g_error_free0 (e); +		_g_option_context_free0 (c); +		return result; +	} +	__finally7: +	if (_inner_error_ != NULL) { +		_g_option_context_free0 (c); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return 0; +	} +	if (application_show_version) { +		fprintf (stderr, "simple-scan %s\n", VERSION); +		result = EXIT_SUCCESS; +		_g_option_context_free0 (c); +		return result; +	} +	device = NULL; +	if (args_length1 > 1) { +		ScanDevice* _tmp4_ = NULL; +		gchar* _tmp5_; +		gchar* _tmp6_; +		_tmp4_ = scan_device_new (); +		_scan_device_unref0 (device); +		device = _tmp4_; +		_tmp5_ = g_strdup (args[1]); +		_g_free0 (device->name); +		device->name = _tmp5_; +		_tmp6_ = g_strdup (args[1]); +		_g_free0 (device->label); +		device->label = _tmp6_; +	} +	_tmp7_ = g_timer_new (); +	_g_timer_destroy0 (application_log_timer); +	application_log_timer = _tmp7_; +	_tmp8_ = g_get_user_cache_dir (); +	_tmp9_ = g_build_filename (_tmp8_, "simple-scan", NULL, NULL); +	path = _tmp9_; +	g_mkdir_with_parents (path, 0700); +	_tmp10_ = g_get_user_cache_dir (); +	_tmp11_ = g_build_filename (_tmp10_, "simple-scan", "simple-scan.log", NULL, NULL); +	_g_free0 (path); +	path = _tmp11_; +	_tmp12_ = fopen (path, "w"); +	_fclose0 (application_log_file); +	application_log_file = _tmp12_; +	g_log_set_default_handler (_application_log_cb_glog_func, NULL); +	_tmp13_ = getpid (); +	g_debug ("simple-scan.vala:507: Starting Simple Scan %s, PID=%i", VERSION, (gint) _tmp13_); +	_tmp14_ = application_new (device); +	app = _tmp14_; +	application_start (app); +	gtk_main (); +	result = EXIT_SUCCESS; +	_application_unref0 (app); +	_g_free0 (path); +	_scan_device_unref0 (device); +	_g_option_context_free0 (c); +	return result; +} + + +int main (int argc, char ** argv) { +	g_type_init (); +	return application_main (argv, argc); +} + + +static void value_application_init (GValue* value) { +	value->data[0].v_pointer = NULL; +} + + +static void value_application_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		application_unref (value->data[0].v_pointer); +	} +} + + +static void value_application_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = application_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	} +} + + +static gpointer value_application_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer; +} + + +static gchar* value_application_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		Application* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = application_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL; +} + + +static gchar* value_application_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	Application** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = application_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_application (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecApplication* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_APPLICATION), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_application (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_APPLICATION), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_application (GValue* value, gpointer v_object) { +	Application* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_APPLICATION)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_APPLICATION)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		application_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		application_unref (old); +	} +} + + +void value_take_application (GValue* value, gpointer v_object) { +	Application* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_APPLICATION)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_APPLICATION)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		application_unref (old); +	} +} + + +static void application_class_init (ApplicationClass * klass) { +	application_parent_class = g_type_class_peek_parent (klass); +	APPLICATION_CLASS (klass)->finalize = application_finalize; +	g_type_class_add_private (klass, sizeof (ApplicationPrivate)); +} + + +static void application_instance_init (Application * self) { +	self->priv = APPLICATION_GET_PRIVATE (self); +	self->priv->default_device = NULL; +	self->priv->have_devices = FALSE; +	self->ref_count = 1; +} + + +static void application_finalize (Application* obj) { +	Application * self; +	self = APPLICATION (obj); +	_scan_device_unref0 (self->priv->default_device); +	_g_object_unref0 (self->priv->udev_client); +	_simple_scan_unref0 (self->priv->ui); +	_scanner_unref0 (self->priv->scanner); +	_book_unref0 (self->priv->book); +} + + +GType application_get_type (void) { +	static volatile gsize application_type_id__volatile = 0; +	if (g_once_init_enter (&application_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_application_init, value_application_free_value, value_application_copy_value, value_application_peek_pointer, "p", value_application_collect_value, "p", value_application_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (ApplicationClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) application_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Application), 0, (GInstanceInitFunc) application_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType application_type_id; +		application_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Application", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&application_type_id__volatile, application_type_id); +	} +	return application_type_id__volatile; +} + + +gpointer application_ref (gpointer instance) { +	Application* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void application_unref (gpointer instance) { +	Application* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		APPLICATION_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	if ((array != NULL) && (destroy_func != NULL)) { +		int i; +		for (i = 0; i < array_length; i = i + 1) { +			if (((gpointer*) array)[i] != NULL) { +				destroy_func (((gpointer*) array)[i]); +			} +		} +	} +} + + +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	_vala_array_destroy (array, array_length, destroy_func); +	g_free (array); +} + + + diff --git a/src/simple-scan.vala b/src/simple-scan.vala new file mode 100644 index 0000000..0ced7ad --- /dev/null +++ b/src/simple-scan.vala @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +public class Application +{ +    static bool show_version; +    static bool debug_enabled; +    public static const OptionEntry[] options = +    { +        { "version", 'v', 0, OptionArg.NONE, ref show_version, +          /* Help string for command line --version flag */ +          N_("Show release version"), null}, +        { "debug", 'd', 0, OptionArg.NONE, ref debug_enabled, +          /* Help string for command line --debug flag */ +          N_("Print debugging messages"), null}, +        { null } +    }; +    private static Timer log_timer; +    private static FileStream? log_file; + +    private ScanDevice? default_device = null; +    private bool have_devices = false; +    private GUdev.Client udev_client; +    private SimpleScan ui; +    private Scanner scanner; +    private Book book; + +    public Application (ScanDevice? device = null) +    { +        default_device = device; + +        ui = new SimpleScan (); +        book = ui.get_book (); +        ui.start_scan.connect (scan_cb); +        ui.stop_scan.connect (cancel_cb); +        ui.email.connect (email_cb); +        ui.quit.connect (quit_cb); + +        scanner = Scanner.get_instance (); +        scanner.update_devices.connect (update_scan_devices_cb); +        scanner.request_authorization.connect (authorize_cb); +        scanner.expect_page.connect (scanner_new_page_cb); +        scanner.got_page_info.connect (scanner_page_info_cb); +        scanner.got_line.connect (scanner_line_cb); +        scanner.page_done.connect (scanner_page_done_cb); +        scanner.document_done.connect (scanner_document_done_cb); +        scanner.scan_failed.connect (scanner_failed_cb); +        scanner.scanning_changed.connect (scanner_scanning_changed_cb); + +        string[]? subsystems = { "usb", null }; +        udev_client = new GUdev.Client (subsystems); +        udev_client.uevent.connect (on_uevent); + +        if (default_device != null) +        { +            List<ScanDevice> device_list = null; + +            device_list.append (default_device); +            ui.set_scan_devices (device_list); +            ui.set_selected_device (default_device.name); +        } +    } +     +    public void start () +    { +        ui.start (); +        scanner.start (); +    } + +    private void update_scan_devices_cb (Scanner scanner, List<ScanDevice> devices) +    { +        var devices_copy = devices.copy (); + +        /* If the default device is not detected add it to the list */ +        if (default_device != null) +        { +            var default_in_list = false; +            foreach (var device in devices_copy) +            { +                if (device.name == default_device.name) +                { +                    default_in_list = true; +                    break; +                } +            } + +            if (!default_in_list) +                devices_copy.prepend (default_device); +        } + +        have_devices = devices_copy.length () > 0; +        ui.set_scan_devices (devices_copy); +    } + +    private void authorize_cb (Scanner scanner, string resource) +    { +        string username, password; +        ui.authorize (resource, out username, out password); +        scanner.authorize (username, password); +    } + +    private Page append_page () +    { +        /* Use current page if not used */ +        var page = book.get_page (-1); +        if (page != null && !page.has_data ()) +        { +            ui.set_selected_page (page); +            page.start (); +            return page; +        } + +        /* Copy info from previous page */ +        var scan_direction = ScanDirection.TOP_TO_BOTTOM; +        bool do_crop = false; +        string named_crop = null; +        var width = 100, height = 100, dpi = 100, cx = 0, cy = 0, cw = 0, ch = 0; +        if (page != null) +        { +            scan_direction = page.get_scan_direction (); +            width = page.get_width (); +            height = page.get_height (); +            dpi = page.get_dpi (); + +            do_crop = page.has_crop (); +            if (do_crop) +            { +                named_crop = page.get_named_crop (); +                page.get_crop (out cx, out cy, out cw, out ch); +            } +        } + +        page = book.append_page (width, height, dpi, scan_direction); +        if (do_crop) +        { +            if (named_crop != null) +            { +                page.set_named_crop (named_crop); +            } +            else +                page.set_custom_crop (cw, ch); +            page.move_crop (cx, cy); +        } +        ui.set_selected_page (page); +        page.start (); + +        return page; +    } + +    private void scanner_new_page_cb (Scanner scanner) +    { +        append_page (); +    } + +    private string? get_profile_for_device (string device_name) +    { +#if HAVE_COLORD +        var device_id = "sane:%s".printf (device_name); +        debug ("Getting color profile for device %s", device_name); + +        var client = new Colord.Client (); +        try +        { +            client.connect_sync (); +        } +        catch (Error e) +        { +            debug ("Failed to connect to colord: %s", e.message); +            return null; +        } + +        Colord.Device device; +        try +        { +            device = client.find_device_by_property_sync (Colord.DEVICE_PROPERTY_SERIAL, device_id); +        } +        catch (Error e) +        { +            debug ("Unable to find colord device %s: %s", device_name, e.message); +            return null; +        } + +        try +        { +            device.connect_sync (); +        } +        catch (Error e) +        { +            debug ("Failed to get properties from the device %s: %s", device_name, e.message); +            return null; +        } + +        var profile = device.get_default_profile (); +        if (profile == null) +        { +            debug ("No default color profile for device: %s", device_name); +            return null; +        } + +        try +        { +            profile.connect_sync (); +        } +        catch (Error e) +        { +            debug ("Failed to get properties from the profile %s: %s", device_name, e.message); +            return null; +        } + +        if (profile.filename == null) +        { +            debug ("No icc color profile for the device %s", device_name); +            return null; +        } + +        debug ("Using color profile %s for device %s", profile.filename, device_name); +        return profile.filename; +#else +        return null; +#endif         +    } + +    private void scanner_page_info_cb (Scanner scanner, ScanPageInfo info) +    { +        debug ("Page is %d pixels wide, %d pixels high, %d bits per pixel", +               info.width, info.height, info.depth); + +        /* Add a new page */ +        var page = append_page (); +        page.set_page_info (info); + +        /* Get ICC color profile */ +        /* FIXME: The ICC profile could change */ +        /* FIXME: Don't do a D-bus call for each page, cache color profiles */ +        page.set_color_profile (get_profile_for_device (info.device)); +    } + +    private void scanner_line_cb (Scanner scanner, ScanLine line) +    { +        var page = book.get_page ((int) book.get_n_pages () - 1); +        page.parse_scan_line (line); +    } + +    private void scanner_page_done_cb (Scanner scanner) +    { +        var page = book.get_page ((int) book.get_n_pages () - 1); +        page.finish (); +    } + +    private void remove_empty_page () +    { +        var page = book.get_page ((int) book.get_n_pages () - 1); + +        /* Remove a failed page */ +        if (page.has_data ()) +            page.finish (); +        else +            book.delete_page (page); +    } + +    private void scanner_document_done_cb (Scanner scanner) +    { +        remove_empty_page (); +    } + +    private void scanner_failed_cb (Scanner scanner, int error_code, string error_string) +    { +        remove_empty_page (); +        if (error_code != Sane.Status.CANCELLED) +        { +            ui.show_error (/* Title of error dialog when scan failed */ +                           _("Failed to scan"), +                           error_string, +                           have_devices); +        } +    } + +    private void scanner_scanning_changed_cb (Scanner scanner) +    { +        ui.set_scanning (scanner.is_scanning ()); +    } + +    private void scan_cb (SimpleScan ui, string? device, ScanOptions options) +    { +        debug ("Requesting scan at %d dpi from device '%s'", options.dpi, device); + +        if (!scanner.is_scanning ()) +            append_page (); + +        /* Default filename to use when saving document (and extension will be added, e.g. .jpg) */ +        string filename_prefix = _("Scanned Document"); +        string extension; +        if (options.scan_mode == ScanMode.COLOR) +            extension = "jpg"; +        else +            extension = "pdf"; +        var filename = "%s.%s".printf (filename_prefix, extension); +        ui.set_default_file_name (filename); +        scanner.scan (device, options); +    } + +    private void cancel_cb (SimpleScan ui) +    { +        scanner.cancel (); +    } + +    private string? get_temporary_filename (string prefix, string extension) +    { +        /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and +         * use the filename but it appears to work in practise */ + +        var filename = "%sXXXXXX.%s".printf (prefix, extension); +        string path; +        try +        { +            var fd = FileUtils.open_tmp (filename, out path); +            Posix.close (fd); +        } +        catch (Error e) +        { +            warning ("Error saving email attachment: %s", e.message); +            return null; +        } + +        return path; +    } + +    private void email_cb (SimpleScan ui, string profile) +    { +        var saved = false; +        var command_line = "xdg-email"; + +        /* Save text files as PDFs */ +        if (profile == "text") +        { +            /* Open a temporary file */ +            var path = get_temporary_filename ("scan", "pdf"); +            if (path != null) +            { +                var file = File.new_for_path (path); +                try +                { +                    book.save ("pdf", file); +                } +                catch (Error e) +                { +                    warning ("Unable to save email file: %s", e.message); +                    return; +                } +                command_line += " --attach %s".printf (path); +            } +        } +        else +        { +            for (var i = 0; i < book.get_n_pages (); i++) +            { +                var path = get_temporary_filename ("scan", "jpg"); +                if (path == null) +                { +                    saved = false; +                    break; +                } + +                var file = File.new_for_path (path); +                try +                { +                    book.get_page (i).save ("jpeg", file); +                } +                catch (Error e) +                { +                    warning ("Unable to save email file: %s", e.message); +                    return; +                } +                command_line += " --attach %s".printf (path); + +                if (!saved) +                    break; +            } +        } + +        debug ("Launching email client: %s", command_line); +        try +        { +            Process.spawn_command_line_async (command_line); +        } +        catch (Error e) +        { +            warning ("Unable to start email: %s", e.message); +        } +    } + +    private void quit_cb (SimpleScan ui) +    { +        book = null; +        ui = null; +        udev_client = null; +        scanner.free (); +        Gtk.main_quit (); +    } + +    private static void log_cb (string? log_domain, LogLevelFlags log_level, string message) +    { +        /* Log everything to a file */ +        if (log_file != null)  +        { +            string prefix; + +            switch (log_level & LogLevelFlags.LEVEL_MASK) +            { +            case LogLevelFlags.LEVEL_ERROR: +                prefix = "ERROR:"; +                break; +            case LogLevelFlags.LEVEL_CRITICAL: +                prefix = "CRITICAL:"; +                break; +            case LogLevelFlags.LEVEL_WARNING: +                prefix = "WARNING:"; +                break; +            case LogLevelFlags.LEVEL_MESSAGE: +                prefix = "MESSAGE:"; +                break; +            case LogLevelFlags.LEVEL_INFO: +                prefix = "INFO:"; +                break; +            case LogLevelFlags.LEVEL_DEBUG: +                prefix = "DEBUG:"; +                break; +            default: +                prefix = "LOG:"; +                break; +            } + +            log_file.printf ("[%+.2fs] %s %s\n", log_timer.elapsed (), prefix, message); +        } + +        /* Only show debug if requested */ +        if ((log_level & LogLevelFlags.LEVEL_DEBUG) != 0) +        { +            if (debug_enabled) +                Log.default_handler (log_domain, log_level, message); +        } +        else +            Log.default_handler (log_domain, log_level, message); +    } + +    private void on_uevent (GUdev.Client client, string action, GUdev.Device device) +    { +        scanner.redetect (); +    } + +    public static int main (string[] args) +    { +        Intl.setlocale (LocaleCategory.ALL, ""); +        Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALE_DIR); +        Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); +        Intl.textdomain (Config.GETTEXT_PACKAGE); + +        Gtk.init (ref args); + +        var c = new OptionContext (/* Arguments and description for --help text */ +                                   _("[DEVICE...] - Scanning utility")); +        c.add_main_entries (options, Config.GETTEXT_PACKAGE); +        c.add_group (Gtk.get_option_group (true)); +        try +        { +            c.parse (ref args); +        } +        catch (Error e) +        { +            stderr.printf ("%s\n", e.message); +            stderr.printf (/* Text printed out when an unknown command-line argument provided */ +                           _("Run '%s --help' to see a full list of available command line options."), args[0]); +            stderr.printf ("\n"); +            return Posix.EXIT_FAILURE; +        } +        if (show_version) +        { +            /* Note, not translated so can be easily parsed */ +            stderr.printf ("simple-scan %s\n", Config.VERSION); +            return Posix.EXIT_SUCCESS; +        } + +        ScanDevice? device = null; +        if (args.length > 1) +        { +            device = new ScanDevice (); +            device.name = args[1]; +            device.label = args[1]; +        } + +        /* Log to a file */ +        log_timer = new Timer (); +        var path = Path.build_filename (Environment.get_user_cache_dir (), "simple-scan", null); +        DirUtils.create_with_parents (path, 0700); +        path = Path.build_filename (Environment.get_user_cache_dir (), "simple-scan", "simple-scan.log", null); +        log_file = FileStream.open (path, "w"); +        Log.set_default_handler (log_cb); + +        debug ("Starting Simple Scan %s, PID=%i", Config.VERSION, Posix.getpid ()); + +        Application app = new Application (device); +        app.start (); + +        Gtk.main (); + +        return Posix.EXIT_SUCCESS; +    } +} diff --git a/src/simple_scan_vala.stamp b/src/simple_scan_vala.stamp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/simple_scan_vala.stamp @@ -1,7 +1,10 @@ +/* ui.c generated by valac 0.13.1, the Vala compiler + * generated from ui.vala, do not modify */ +  /* - * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009-2011 Canonical Ltd.   * Author: Robert Ancell <robert.ancell@canonical.com> - *  + *   * This program 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 3 of the License, or (at your option) any later @@ -9,1917 +12,3443 @@   * license.   */ +#include <glib.h> +#include <glib-object.h> +#include <gio/gio.h> +#include <gtk/gtk.h>  #include <stdlib.h>  #include <string.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> -#include <gconf/gconf-client.h> +#include <glib/gi18n-lib.h> +#include <glib/gstdio.h> +#include <unistd.h> +#include <cairo.h> +#include <float.h>  #include <math.h> -#include <unistd.h> // TEMP: Needed for close() in get_temporary_filename() - -#include "ui.h" -#include "book-view.h" - - -#define DEFAULT_TEXT_DPI 150 -#define DEFAULT_PHOTO_DPI 300 - - -enum { -    START_SCAN, -    STOP_SCAN, -    EMAIL, -    QUIT, -    LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0, }; - - -struct SimpleScanPrivate -{ -    GConfClient *client; - -    GtkBuilder *builder; - -    GtkWidget *window, *main_vbox; -    GtkWidget *info_bar, *info_bar_image, *info_bar_label; -    GtkWidget *info_bar_close_button, *info_bar_change_scanner_button; -    GtkWidget *page_move_left_menuitem, *page_move_right_menuitem; -    GtkWidget *page_delete_menuitem, *crop_rotate_menuitem; -    GtkWidget *save_menuitem, *save_as_menuitem, *save_toolbutton; -    GtkWidget *stop_menuitem, *stop_toolbutton; - -    GtkWidget *text_toolbar_menuitem, *text_menu_menuitem; -    GtkWidget *photo_toolbar_menuitem, *photo_menu_menuitem; - -    GtkWidget *authorize_dialog; -    GtkWidget *authorize_label; -    GtkWidget *username_entry, *password_entry; - -    GtkWidget *preferences_dialog; -    GtkWidget *device_combo, *text_dpi_combo, *photo_dpi_combo, *page_side_combo, *paper_size_combo; -    GtkTreeModel *device_model, *text_dpi_model, *photo_dpi_model, *page_side_model, *paper_size_model; -    gboolean setting_devices, user_selected_device; - -    gboolean have_error; -    gchar *error_title, *error_text; -    gboolean error_change_scanner_hint; - -    Book *book; -    gchar *book_uri; -   -    BookView *book_view; -    gboolean updating_page_menu; -    gint default_page_width, default_page_height, default_page_dpi; -    ScanDirection default_page_scan_direction; -   -    gchar *document_hint; - -    gchar *default_file_name; -    gboolean scanning; - -    gint window_width, window_height; -    gboolean window_is_maximized; +#include <gdk-pixbuf/gdk-pixdata.h> +#include <gdk/gdk.h> +#include <config.h> +#include <gobject/gvaluecollector.h> + + +#define TYPE_SIMPLE_SCAN (simple_scan_get_type ()) +#define SIMPLE_SCAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SIMPLE_SCAN, SimpleScan)) +#define SIMPLE_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SIMPLE_SCAN, SimpleScanClass)) +#define IS_SIMPLE_SCAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SIMPLE_SCAN)) +#define IS_SIMPLE_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SIMPLE_SCAN)) +#define SIMPLE_SCAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SIMPLE_SCAN, SimpleScanClass)) + +typedef struct _SimpleScan SimpleScan; +typedef struct _SimpleScanClass SimpleScanClass; +typedef struct _SimpleScanPrivate SimpleScanPrivate; + +#define TYPE_BOOK (book_get_type ()) +#define BOOK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOOK, Book)) +#define BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BOOK, BookClass)) +#define IS_BOOK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOOK)) +#define IS_BOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BOOK)) +#define BOOK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BOOK, BookClass)) + +typedef struct _Book Book; +typedef struct _BookClass BookClass; + +#define TYPE_BOOK_VIEW (book_view_get_type ()) +#define BOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOOK_VIEW, BookView)) +#define BOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_BOOK_VIEW, BookViewClass)) +#define IS_BOOK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOOK_VIEW)) +#define IS_BOOK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_BOOK_VIEW)) +#define BOOK_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_BOOK_VIEW, BookViewClass)) + +typedef struct _BookView BookView; +typedef struct _BookViewClass BookViewClass; + +#define TYPE_SCAN_DIRECTION (scan_direction_get_type ()) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _book_unref0(var) ((var == NULL) ? NULL : (var = (book_unref (var), NULL))) + +#define TYPE_PAGE (page_get_type ()) +#define PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PAGE, Page)) +#define PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PAGE, PageClass)) +#define IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PAGE)) +#define IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PAGE)) +#define PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PAGE, PageClass)) + +typedef struct _Page Page; +typedef struct _PageClass PageClass; + +#define TYPE_SCAN_DEVICE (scan_device_get_type ()) +#define SCAN_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_DEVICE, ScanDevice)) +#define SCAN_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_DEVICE, ScanDeviceClass)) +#define IS_SCAN_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_DEVICE)) +#define IS_SCAN_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_DEVICE)) +#define SCAN_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_DEVICE, ScanDeviceClass)) + +typedef struct _ScanDevice ScanDevice; +typedef struct _ScanDeviceClass ScanDeviceClass; +typedef struct _ScanDevicePrivate ScanDevicePrivate; +#define _scan_device_unref0(var) ((var == NULL) ? NULL : (var = (scan_device_unref (var), NULL))) +#define _page_unref0(var) ((var == NULL) ? NULL : (var = (page_unref (var), NULL))) +#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) + +#define TYPE_SCAN_TYPE (scan_type_get_type ()) + +#define TYPE_SCAN_OPTIONS (scan_options_get_type ()) +#define SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SCAN_OPTIONS, ScanOptions)) +#define SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SCAN_OPTIONS, ScanOptionsClass)) +#define IS_SCAN_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SCAN_OPTIONS)) +#define IS_SCAN_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SCAN_OPTIONS)) +#define SCAN_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SCAN_OPTIONS, ScanOptionsClass)) + +typedef struct _ScanOptions ScanOptions; +typedef struct _ScanOptionsClass ScanOptionsClass; + +#define TYPE_SCAN_MODE (scan_mode_get_type ()) +typedef struct _ScanOptionsPrivate ScanOptionsPrivate; +#define _scan_options_unref0(var) ((var == NULL) ? NULL : (var = (scan_options_unref (var), NULL))) +#define _cairo_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_destroy (var), NULL))) +typedef struct _ParamSpecSimpleScan ParamSpecSimpleScan; + +struct _SimpleScan { +	GTypeInstance parent_instance; +	volatile int ref_count; +	SimpleScanPrivate * priv;  }; -G_DEFINE_TYPE (SimpleScan, ui, G_TYPE_OBJECT); - -static struct -{ -   const gchar *key; -   ScanDirection scan_direction; -} scan_direction_keys[] =  -{ -  { "top-to-bottom", TOP_TO_BOTTOM }, -  { "bottom-to-top", BOTTOM_TO_TOP }, -  { "left-to-right", LEFT_TO_RIGHT }, -  { "right-to-left", RIGHT_TO_LEFT }, -  { NULL, 0 } +struct _SimpleScanClass { +	GTypeClass parent_class; +	void (*finalize) (SimpleScan *self);  }; +typedef enum  { +	SCAN_DIRECTION_TOP_TO_BOTTOM, +	SCAN_DIRECTION_LEFT_TO_RIGHT, +	SCAN_DIRECTION_BOTTOM_TO_TOP, +	SCAN_DIRECTION_RIGHT_TO_LEFT +} ScanDirection; + +struct _SimpleScanPrivate { +	GSettings* settings; +	GtkBuilder* builder; +	GtkWindow* window; +	GtkVBox* main_vbox; +	GtkInfoBar* info_bar; +	GtkImage* info_bar_image; +	GtkLabel* info_bar_label; +	GtkButton* info_bar_close_button; +	GtkButton* info_bar_change_scanner_button; +	GtkMenuItem* page_move_left_menuitem; +	GtkMenuItem* page_move_right_menuitem; +	GtkMenuItem* page_delete_menuitem; +	GtkMenuItem* crop_rotate_menuitem; +	GtkMenuItem* save_menuitem; +	GtkMenuItem* save_as_menuitem; +	GtkToolButton* save_toolbutton; +	GtkMenuItem* stop_menuitem; +	GtkToolButton* stop_toolbutton; +	GtkRadioMenuItem* text_toolbar_menuitem; +	GtkRadioMenuItem* text_menu_menuitem; +	GtkRadioMenuItem* photo_toolbar_menuitem; +	GtkRadioMenuItem* photo_menu_menuitem; +	GtkDialog* authorize_dialog; +	GtkLabel* authorize_label; +	GtkEntry* username_entry; +	GtkEntry* password_entry; +	GtkDialog* preferences_dialog; +	GtkComboBox* device_combo; +	GtkComboBox* text_dpi_combo; +	GtkComboBox* photo_dpi_combo; +	GtkComboBox* page_side_combo; +	GtkComboBox* paper_size_combo; +	GtkListStore* device_model; +	GtkListStore* text_dpi_model; +	GtkListStore* photo_dpi_model; +	GtkListStore* page_side_model; +	GtkListStore* paper_size_model; +	gboolean setting_devices; +	gboolean user_selected_device; +	GtkFileChooserDialog* save_dialog; +	gboolean have_error; +	gchar* error_title; +	gchar* error_text; +	gboolean error_change_scanner_hint; +	Book* book; +	gchar* book_uri; +	BookView* book_view; +	gboolean updating_page_menu; +	gint default_page_width; +	gint default_page_height; +	gint default_page_dpi; +	ScanDirection default_page_scan_direction; +	gchar* document_hint; +	gchar* default_file_name; +	gboolean scanning; +	gint window_width; +	gint window_height; +	gboolean window_is_maximized; +}; -static gboolean -find_scan_device (SimpleScan *ui, const char *device, GtkTreeIter *iter) -{ -    gboolean have_iter = FALSE; - -    if (gtk_tree_model_get_iter_first (ui->priv->device_model, iter)) { -        do { -            gchar *d; -            gtk_tree_model_get (ui->priv->device_model, iter, 0, &d, -1); -            if (strcmp (d, device) == 0) -                have_iter = TRUE; -            g_free (d); -        } while (!have_iter && gtk_tree_model_iter_next (ui->priv->device_model, iter)); -    } -     -    return have_iter; -} - - -static void -show_error_dialog (SimpleScan *ui, const char *error_title, const char *error_text) -{ -    GtkWidget *dialog; - -    dialog = gtk_message_dialog_new (GTK_WINDOW (ui->priv->window), -                                     GTK_DIALOG_MODAL, -                                     GTK_MESSAGE_WARNING, -                                     GTK_BUTTONS_NONE, -                                     "%s", error_title); -    gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, 0); -    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error_text); -    gtk_widget_destroy (dialog); -} - - -void -ui_set_default_file_name (SimpleScan *ui, const gchar *default_file_name) -{ -    g_free (ui->priv->default_file_name); -    ui->priv->default_file_name = g_strdup (default_file_name); -} - - -void -ui_authorize (SimpleScan *ui, const gchar *resource, gchar **username, gchar **password) -{ -    GString *description; - -    description = g_string_new (""); -    g_string_printf (description, -                     /* Label in authorization dialog.  '%s' is replaced with the name of the resource requesting authorization */ -                     _("Username and password required to access '%s'"), -                     resource); - -    gtk_entry_set_text (GTK_ENTRY (ui->priv->username_entry), *username ? *username : ""); -    gtk_entry_set_text (GTK_ENTRY (ui->priv->password_entry), ""); -    gtk_label_set_text (GTK_LABEL (ui->priv->authorize_label), description->str); -    g_string_free (description, TRUE); - -    gtk_widget_show (ui->priv->authorize_dialog); -    gtk_dialog_run (GTK_DIALOG (ui->priv->authorize_dialog)); -    gtk_widget_hide (ui->priv->authorize_dialog); - -    *username = g_strdup (gtk_entry_get_text (GTK_ENTRY (ui->priv->username_entry))); -    *password = g_strdup (gtk_entry_get_text (GTK_ENTRY (ui->priv->password_entry))); -} - - -void device_combo_changed_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -device_combo_changed_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (ui->priv->setting_devices) -        return; -    ui->priv->user_selected_device = TRUE; -} - - -static void -update_info_bar (SimpleScan *ui) -{ -    GtkMessageType type; -    const gchar *title, *text, *image_id; -    gchar *message; -    gboolean show_close_button = FALSE; -    gboolean show_change_scanner_button = FALSE; -   -    if (ui->priv->have_error)  { -        type = GTK_MESSAGE_ERROR; -        image_id = GTK_STOCK_DIALOG_ERROR; -        title = ui->priv->error_title; -        text = ui->priv->error_text; -        show_close_button = TRUE; -        show_change_scanner_button = ui->priv->error_change_scanner_hint; -    } -    else if (gtk_tree_model_iter_n_children (ui->priv->device_model, NULL) == 0) { -        type = GTK_MESSAGE_WARNING; -        image_id = GTK_STOCK_DIALOG_WARNING; -        /* Warning displayed when no scanners are detected */ -        title = _("No scanners detected"); -        /* Hint to user on why there are no scanners detected */ -        text = _("Please check your scanner is connected and powered on"); -    } -    else { -        gtk_widget_hide (ui->priv->info_bar); -        return; -    } - -    gtk_info_bar_set_message_type (GTK_INFO_BAR (ui->priv->info_bar), type); -    gtk_image_set_from_stock (GTK_IMAGE (ui->priv->info_bar_image), image_id, GTK_ICON_SIZE_DIALOG); -    message = g_strdup_printf ("<big><b>%s</b></big>\n\n%s", title, text); -    gtk_label_set_markup (GTK_LABEL (ui->priv->info_bar_label), message); -    g_free (message); -    gtk_widget_set_visible (ui->priv->info_bar_close_button, show_close_button);   -    gtk_widget_set_visible (ui->priv->info_bar_change_scanner_button, show_change_scanner_button); -    gtk_widget_show (ui->priv->info_bar); -} - - -void -ui_set_scan_devices (SimpleScan *ui, GList *devices) -{ -    GList *d; -    gboolean have_selection = FALSE; -    gint index; -    GtkTreeIter iter; -   -    ui->priv->setting_devices = TRUE; -  -    /* If the user hasn't chosen a scanner choose the best available one */ -    if (ui->priv->user_selected_device) -        have_selection = gtk_combo_box_get_active (GTK_COMBO_BOX (ui->priv->device_combo)) >= 0; - -    /* Add new devices */ -    index = 0; -    for (d = devices; d; d = d->next) { -        ScanDevice *device = (ScanDevice *) d->data; -        gint n_delete = -1; - -        /* Find if already exists */ -        if (gtk_tree_model_iter_nth_child (ui->priv->device_model, &iter, NULL, index)) { -            gint i = 0; -            do { -                gchar *name; -                gboolean matched; - -                gtk_tree_model_get (ui->priv->device_model, &iter, 0, &name, -1); -                matched = strcmp (name, device->name) == 0; -                g_free (name); - -                if (matched) { -                    n_delete = i; -                    break; -                } -                i++; -            } while (gtk_tree_model_iter_next (ui->priv->device_model, &iter)); -        } -       -        /* If exists, remove elements up to this one */ -        if (n_delete >= 0) { -            gint i; - -            /* Update label */ -            gtk_list_store_set (GTK_LIST_STORE (ui->priv->device_model), &iter, 1, device->label, -1); - -            for (i = 0; i < n_delete; i++) { -                gtk_tree_model_iter_nth_child (ui->priv->device_model, &iter, NULL, index); -                gtk_list_store_remove (GTK_LIST_STORE (ui->priv->device_model), &iter); -            } -        } -        else { -            gtk_list_store_insert (GTK_LIST_STORE (ui->priv->device_model), &iter, index); -            gtk_list_store_set (GTK_LIST_STORE (ui->priv->device_model), &iter, 0, device->name, 1, device->label, -1); -        } -        index++; -    } - -    /* Remove any remaining devices */ -    while (gtk_tree_model_iter_nth_child (ui->priv->device_model, &iter, NULL, index)) -        gtk_list_store_remove (GTK_LIST_STORE (ui->priv->device_model), &iter); - -    /* Select the first available device */ -    if (!have_selection && devices != NULL) -        gtk_combo_box_set_active (GTK_COMBO_BOX (ui->priv->device_combo), 0); - -    ui->priv->setting_devices = FALSE; - -    update_info_bar (ui); -} - - -static gchar * -get_selected_device (SimpleScan *ui) -{ -    GtkTreeIter iter; - -    if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter)) { -        gchar *device; -        gtk_tree_model_get (ui->priv->device_model, &iter, 0, &device, -1); -        return device; -    } - -    return NULL; -} - - -void -ui_set_selected_device (SimpleScan *ui, const gchar *device) -{ -    GtkTreeIter iter; - -    if (!find_scan_device (ui, device, &iter)) -        return; - -    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter); -    ui->priv->user_selected_device = TRUE; -} - - -static void -add_default_page (SimpleScan *ui) -{ -    Page *page; - -    page = book_append_page (ui->priv->book, -                             ui->priv->default_page_width, -                             ui->priv->default_page_height, -                             ui->priv->default_page_dpi, -                             ui->priv->default_page_scan_direction); -    book_view_select_page (ui->priv->book_view, page); -} - - -static void -on_file_type_changed (GtkTreeSelection *selection, GtkWidget *dialog) -{ -    GtkTreeModel *model; -    GtkTreeIter iter; -    gchar *path, *filename, *extension, *new_filename; - -    if (!gtk_tree_selection_get_selected (selection, &model, &iter)) -        return; - -    gtk_tree_model_get (model, &iter, 1, &extension, -1); -    path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); -    filename = g_path_get_basename (path); - -    /* Replace extension */ -    if (g_strrstr (filename, ".")) -        new_filename = g_strdup_printf ("%.*s%s", (int)(g_strrstr (filename, ".") - filename), filename, extension); -    else -        new_filename = g_strdup_printf ("%s%s", filename, extension); -    gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), new_filename); - -    g_free (path); -    g_free (filename); -    g_free (new_filename); -    g_free (extension); -} - - -static gchar * -choose_file_location (SimpleScan *ui) -{ -    GtkWidget *dialog; -    gint response; -    GtkFileFilter *filter; -    GtkWidget *expander, *file_type_view; -    GtkListStore *file_type_store; -    GtkTreeIter iter; -    GtkTreeViewColumn *column; -    const gchar *extension; -    gchar *directory, *uri = NULL; -    gint i; - -    struct -    { -        gchar *label, *extension; -    } file_types[] = -    { -        /* Save dialog: Label for saving in PDF format */ -        { _("PDF (multi-page document)"), ".pdf" }, -        /* Save dialog: Label for saving in JPEG format */ -        { _("JPEG (compressed)"), ".jpg" }, -        /* Save dialog: Label for saving in PNG format */ -        { _("PNG (lossless)"), ".png" }, -        { NULL, NULL } -    }; - -    /* Get directory to save to */ -    directory = gconf_client_get_string (ui->priv->client, GCONF_DIR "/save_directory", NULL); -    if (!directory || directory[0] == '\0') { -        g_free (directory); -        directory = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); -    } - -    dialog = gtk_file_chooser_dialog_new (/* Save dialog: Dialog title */ -                                          _("Save As..."), -                                          GTK_WINDOW (ui->priv->window), -                                          GTK_FILE_CHOOSER_ACTION_SAVE, -                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, -                                          GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, -                                          NULL); -    gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); -    gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE); -    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), directory); -    gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), ui->priv->default_file_name); -    g_free (directory); - -    /* Filter to only show images by default */ -    filter = gtk_file_filter_new (); -    gtk_file_filter_set_name (filter, -                              /* Save dialog: Filter name to show only image files */ -                              _("Image Files")); -    gtk_file_filter_add_pixbuf_formats (filter); -    gtk_file_filter_add_mime_type (filter, "application/pdf"); -    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); -    filter = gtk_file_filter_new (); -    gtk_file_filter_set_name (filter, -                              /* Save dialog: Filter name to show all files */ -                              _("All Files")); -    gtk_file_filter_add_pattern (filter, "*"); -    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - -    expander = gtk_expander_new_with_mnemonic (/* */ -                                 _("Select File _Type")); -    gtk_expander_set_spacing (GTK_EXPANDER (expander), 5); -    gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), expander); -   -    extension = strstr (ui->priv->default_file_name, "."); -    if (!extension) -        extension = ""; - -    file_type_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); -    for (i = 0; file_types[i].label; i++) { -        gtk_list_store_append (file_type_store, &iter); -        gtk_list_store_set (file_type_store, &iter, 0, file_types[i].label, 1, file_types[i].extension, -1); -    } - -    file_type_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (file_type_store)); -    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (file_type_view), FALSE); -    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (file_type_view), TRUE); -    column = gtk_tree_view_column_new_with_attributes ("", -                                                       gtk_cell_renderer_text_new (), -                                                       "text", 0, NULL); -    gtk_tree_view_append_column (GTK_TREE_VIEW (file_type_view), column); -    gtk_container_add (GTK_CONTAINER (expander), file_type_view); - -    if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (file_type_store), &iter)) { -        do { -            gchar *e; -            gtk_tree_model_get (GTK_TREE_MODEL (file_type_store), &iter, 1, &e, -1); -            if (strcmp (extension, e) == 0) -                gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (file_type_view)), &iter); -            g_free (e); -        } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (file_type_store), &iter)); -    } -    g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (file_type_view)), -                      "changed", -                      G_CALLBACK (on_file_type_changed), -                      dialog); - -    gtk_widget_show_all (expander); - -    response = gtk_dialog_run (GTK_DIALOG (dialog)); - -    if (response == GTK_RESPONSE_ACCEPT) -        uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); - -    gconf_client_set_string (ui->priv->client, GCONF_DIR "/save_directory", -                             gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)), -                             NULL); - -    gtk_widget_destroy (dialog); - -    return uri; -} - - -static gboolean -save_document (SimpleScan *ui, gboolean force_choose_location) -{ -    gboolean result; -    gchar *uri, *uri_lower; -    GError *error = NULL; -    GFile *file; -   -    if (ui->priv->book_uri && !force_choose_location) -        uri = g_strdup (ui->priv->book_uri); -    else -        uri = choose_file_location (ui); -    if (!uri) -        return FALSE; - -    file = g_file_new_for_uri (uri); - -    g_debug ("Saving to '%s'", uri); - -    uri_lower = g_utf8_strdown (uri, -1); -    if (g_str_has_suffix (uri_lower, ".pdf")) -        result = book_save (ui->priv->book, "pdf", file, &error); -    else if (g_str_has_suffix (uri_lower, ".ps")) -        result = book_save (ui->priv->book, "ps", file, &error); -    else if (g_str_has_suffix (uri_lower, ".png")) -        result = book_save (ui->priv->book, "png", file, &error); -    else if (g_str_has_suffix (uri_lower, ".tif") || g_str_has_suffix (uri_lower, ".tiff")) -        result = book_save (ui->priv->book, "tiff", file, &error); -    else -        result = book_save (ui->priv->book, "jpeg", file, &error); - -    g_free (uri_lower); - -    if (result) { -        g_free (ui->priv->book_uri); -        ui->priv->book_uri = uri; -        book_set_needs_saving (ui->priv->book, FALSE); -    } -    else { -        g_free (uri); - -        g_warning ("Error saving file: %s", error->message); -        ui_show_error (ui, -                       /* Title of error dialog when save failed */ -                       _("Failed to save file"), -                       error->message, -                       FALSE); -        g_clear_error (&error); -    } - -    g_object_unref (file); - -    return result; -} - - -static gboolean -prompt_to_save (SimpleScan *ui, const gchar *title, const gchar *discard_label) -{ -    GtkWidget *dialog; -    gint response; - -    if (!book_get_needs_saving (ui->priv->book)) -        return TRUE; - -    dialog = gtk_message_dialog_new (GTK_WINDOW (ui->priv->window), -                                     GTK_DIALOG_MODAL, -                                     GTK_MESSAGE_WARNING, -                                     GTK_BUTTONS_NONE, -                                     "%s", title); -    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", -                                              /* Text in dialog warning when a document is about to be lost*/ -                                              _("If you don't save, changes will be permanently lost.")); -    gtk_dialog_add_button (GTK_DIALOG (dialog), discard_label, GTK_RESPONSE_NO); -    gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); -    gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_SAVE, GTK_RESPONSE_YES); - -    response = gtk_dialog_run (GTK_DIALOG (dialog)); -    gtk_widget_destroy (dialog); -   -    switch (response) { -    case GTK_RESPONSE_YES: -        if (save_document (ui, FALSE)) -            return TRUE; -        else -            return FALSE; -    case GTK_RESPONSE_CANCEL: -        return FALSE; -    case GTK_RESPONSE_NO:       -    default: -        return TRUE; -    } -} - - -static void -clear_document (SimpleScan *ui) -{ -    book_clear (ui->priv->book); -    add_default_page (ui); -    g_free (ui->priv->book_uri); -    ui->priv->book_uri = NULL; -    book_set_needs_saving (ui->priv->book, FALSE); -    gtk_widget_set_sensitive (ui->priv->save_as_menuitem, FALSE); -} - - -void new_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -new_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (!prompt_to_save (ui, -                         /* Text in dialog warning when a document is about to be lost */ -                         _("Save current document?"), -                         /* Button in dialog to create new document and discard unsaved document */ -                         _("Discard Changes"))) -        return; - -    clear_document (ui); -} - - -static void -set_document_hint (SimpleScan *ui, const gchar *document_hint) -{ -    g_free (ui->priv->document_hint); -    ui->priv->document_hint = g_strdup (document_hint); - -    if (strcmp (document_hint, "text") == 0) { -        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->text_toolbar_menuitem), TRUE); -        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->text_menu_menuitem), TRUE); -    } -    else if (strcmp (document_hint, "photo") == 0) { -        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->photo_toolbar_menuitem), TRUE); -        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->photo_menu_menuitem), TRUE); -    } -} - - -void text_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -text_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_document_hint (ui, "text"); -} - - -void photo_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -photo_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_document_hint (ui, "photo"); -} - - -static void -set_page_side (SimpleScan *ui, const gchar *document_hint) -{ -    GtkTreeIter iter; - -    if (gtk_tree_model_get_iter_first (ui->priv->page_side_model, &iter)) { -        do { -            gchar *d; -            gboolean have_match; - -            gtk_tree_model_get (ui->priv->page_side_model, &iter, 0, &d, -1); -            have_match = strcmp (d, document_hint) == 0; -            g_free (d); - -            if (have_match) { -                gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->page_side_combo), &iter);                 -                return; -            } -        } while (gtk_tree_model_iter_next (ui->priv->page_side_model, &iter)); -     } -} - - -static void -set_paper_size (SimpleScan *ui, gint width, gint height) -{ -    GtkTreeIter iter; -    gboolean have_iter; -   -    for (have_iter = gtk_tree_model_get_iter_first (ui->priv->paper_size_model, &iter); -         have_iter; -         have_iter = gtk_tree_model_iter_next (ui->priv->paper_size_model, &iter)) { -        gint w, h; - -        gtk_tree_model_get (ui->priv->paper_size_model, &iter, 0, &w, 1, &h, -1); -        if (w == width && h == height) -            break; -    } -   -    if (!have_iter) -        have_iter = gtk_tree_model_get_iter_first (ui->priv->paper_size_model, &iter); -    if (have_iter) -        gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->paper_size_combo), &iter); -} - - -static gint -get_text_dpi (SimpleScan *ui) -{ -    GtkTreeIter iter; -    gint dpi = DEFAULT_TEXT_DPI; - -    if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->text_dpi_combo), &iter)) -        gtk_tree_model_get (ui->priv->text_dpi_model, &iter, 0, &dpi, -1); -     -    return dpi; -} - - -static gint -get_photo_dpi (SimpleScan *ui) -{ -    GtkTreeIter iter; -    gint dpi = DEFAULT_PHOTO_DPI; - -    if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->photo_dpi_combo), &iter)) -        gtk_tree_model_get (ui->priv->photo_dpi_model, &iter, 0, &dpi, -1); -     -    return dpi; -} - - -static gchar * -get_page_side (SimpleScan *ui) -{ -    GtkTreeIter iter; -    gchar *mode = NULL; - -    if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->page_side_combo), &iter)) -        gtk_tree_model_get (ui->priv->page_side_model, &iter, 0, &mode, -1); -     -    return mode; -} - - -static gboolean -get_paper_size (SimpleScan *ui, gint *width, gint *height) -{ -    GtkTreeIter iter; - -    if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->paper_size_combo), &iter)) { -        gtk_tree_model_get (ui->priv->paper_size_model, &iter, 0, width, 1, height, -1); -        return TRUE; -    } -   -    return FALSE; -} - - -static ScanOptions * -get_scan_options (SimpleScan *ui) -{ -    struct { -        const gchar *name; -        ScanMode mode; -        gint depth; -    } profiles[] = -    { -        { "text",  SCAN_MODE_GRAY,  2 }, -        { "photo", SCAN_MODE_COLOR, 8 }, -        { NULL,    SCAN_MODE_COLOR, 8 } -    }; -    gint i; -    ScanOptions *options; - -    /* Find this profile */ -    // FIXME: Move this into scan-profile.c -    for (i = 0; profiles[i].name && strcmp (profiles[i].name, ui->priv->document_hint) != 0; i++); -   -    options = g_malloc0 (sizeof (ScanOptions)); -    options->scan_mode = profiles[i].mode; -    options->depth = profiles[i].depth; -    if (options->scan_mode == SCAN_MODE_COLOR) -        options->dpi = get_photo_dpi (ui); -    else -        options->dpi = get_text_dpi (ui); -    get_paper_size (ui, &options->paper_width, &options->paper_height); -   -    return options; -} - - -void scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    gchar *device; -    ScanOptions *options; - -    device = get_selected_device (ui); - -    options = get_scan_options (ui); -    options->type = SCAN_SINGLE; -    g_signal_emit (G_OBJECT (ui), signals[START_SCAN], 0, device, options); -    g_free (device); -    g_free (options); -} - - -void stop_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -stop_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    g_signal_emit (G_OBJECT (ui), signals[STOP_SCAN], 0); -} - - -void continuous_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -continuous_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (ui->priv->scanning) { -        g_signal_emit (G_OBJECT (ui), signals[STOP_SCAN], 0); -    } else { -        gchar *device, *side; -        ScanOptions *options; - -        device = get_selected_device (ui); -        options = get_scan_options (ui); -        side = get_page_side (ui); -        if (strcmp (side, "front") == 0) -            options->type = SCAN_ADF_FRONT; -        else if (strcmp (side, "back") == 0) -            options->type = SCAN_ADF_BACK; -        else -            options->type = SCAN_ADF_BOTH; - -        g_signal_emit (G_OBJECT (ui), signals[START_SCAN], 0, device, options); -        g_free (device); -        g_free (side); -        g_free (options); -    } -} - - -void preferences_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -preferences_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    gtk_window_present (GTK_WINDOW (ui->priv->preferences_dialog)); -} - - -gboolean preferences_dialog_delete_event_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -gboolean -preferences_dialog_delete_event_cb (GtkWidget *widget, SimpleScan *ui) -{ -    return TRUE; -} - - -void preferences_dialog_response_cb (GtkWidget *widget, gint response_id, SimpleScan *ui); -G_MODULE_EXPORT -void -preferences_dialog_response_cb (GtkWidget *widget, gint response_id, SimpleScan *ui) -{ -    gtk_widget_hide (ui->priv->preferences_dialog); -} - - -static void -update_page_menu (SimpleScan *ui) -{ -    Book *book; -    gint index; - -    book = book_view_get_book (ui->priv->book_view); -    index = book_get_page_index (book, book_view_get_selected (ui->priv->book_view)); -    gtk_widget_set_sensitive (ui->priv->page_move_left_menuitem, index > 0); -    gtk_widget_set_sensitive (ui->priv->page_move_right_menuitem, index < book_get_n_pages (book) - 1); -} - - -static void -page_selected_cb (BookView *view, Page *page, SimpleScan *ui) -{ -    char *name = NULL; - -    if (page == NULL) -        return; - -    ui->priv->updating_page_menu = TRUE; -   -    update_page_menu (ui); - -    if (page_has_crop (page)) { -        char *crop_name; -       -        // FIXME: Make more generic, move into page-size.c and reuse -        crop_name = page_get_named_crop (page); -        if (crop_name) { -            if (strcmp (crop_name, "A4") == 0) -                name = "a4_menuitem"; -            else if (strcmp (crop_name, "A5") == 0) -                name = "a5_menuitem"; -            else if (strcmp (crop_name, "A6") == 0) -                name = "a6_menuitem"; -            else if (strcmp (crop_name, "letter") == 0) -                name = "letter_menuitem"; -            else if (strcmp (crop_name, "legal") == 0) -                name = "legal_menuitem"; -            else if (strcmp (crop_name, "4x6") == 0) -                name = "4x6_menuitem"; -            g_free (crop_name); -        } -        else -            name = "custom_crop_menuitem"; -    } -    else -        name = "no_crop_menuitem"; - -    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (ui->priv->builder, name)), TRUE); -    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (gtk_builder_get_object (ui->priv->builder, "crop_toolbutton")), page_has_crop (page)); - -    ui->priv->updating_page_menu = FALSE; -} - - -// FIXME: Duplicated from simple-scan.c -static gchar * -get_temporary_filename (const gchar *prefix, const gchar *extension) -{ -    gint fd; -    gchar *filename, *path; -    GError *error = NULL; - -    /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and -     * use the filename but it appears to work in practise */ - -    filename = g_strdup_printf ("%s-XXXXXX.%s", prefix, extension); -    fd = g_file_open_tmp (filename, &path, &error); -    g_free (filename); -    if (fd < 0) { -        g_warning ("Error saving page for viewing: %s", error->message); -        g_clear_error (&error); -        return NULL; -    } -    close (fd); - -    return path; -} - - -static void -show_page_cb (BookView *view, Page *page, SimpleScan *ui) -{ -    gchar *path; -    GFile *file; -    GdkScreen *screen; -    GError *error = NULL; -   -    path = get_temporary_filename ("scanned-page", "tiff"); -    if (!path) -        return; -    file = g_file_new_for_path (path); -    g_free (path); - -    screen = gtk_widget_get_screen (GTK_WIDGET (ui->priv->window)); - -    if (page_save (page, "tiff", file, &error)) { -        gchar *uri = g_file_get_uri (file); -        gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error); -        g_free (uri); -    } - -    g_object_unref (file); - -    if (error) { -        show_error_dialog (ui, -                           /* Error message display when unable to preview image */ -                           _("Unable to open image preview application"), -                           error->message); -        g_clear_error (&error); -    } -} - - -static void -show_page_menu_cb (BookView *view, SimpleScan *ui) -{ -    gtk_menu_popup (GTK_MENU (gtk_builder_get_object (ui->priv->builder, "page_menu")), NULL, NULL, NULL, NULL, -                    3, gtk_get_current_event_time()); -} - - -void rotate_left_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -rotate_left_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    Page *page; - -    if (ui->priv->updating_page_menu) -        return; -    page = book_view_get_selected (ui->priv->book_view); -    page_rotate_left (page); -} - - -void rotate_right_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -rotate_right_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    Page *page; - -    if (ui->priv->updating_page_menu) -        return; -    page = book_view_get_selected (ui->priv->book_view); -    page_rotate_right (page); -} - - -static void -set_crop (SimpleScan *ui, const gchar *crop_name) -{ -    Page *page; -     -    gtk_widget_set_sensitive (ui->priv->crop_rotate_menuitem, crop_name != NULL); - -    if (ui->priv->updating_page_menu) -        return; -     -    page = book_view_get_selected (ui->priv->book_view); -    if (!page) -        return; -     -    if (!crop_name) { -        page_set_no_crop (page); -        return; -    } - -    if (strcmp (crop_name, "custom") == 0) { -        gint width, height, crop_width, crop_height; - -        width = page_get_width (page); -        height = page_get_height (page); - -        crop_width = (int) (width * 0.8 + 0.5); -        crop_height = (int) (height * 0.8 + 0.5); -        page_set_custom_crop (page, crop_width, crop_height); -        page_move_crop (page, (width - crop_width) / 2, (height - crop_height) / 2); - -        return; -    } - -    page_set_named_crop (page, crop_name); -} - - -void no_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -no_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, NULL); -} - - -void custom_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -custom_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "custom"); -} - -void crop_toolbutton_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -crop_toolbutton_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (ui->priv->updating_page_menu) -        return; -   -    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (widget))) -        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (ui->priv->builder, "custom_crop_menuitem")), TRUE); -    else -        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (ui->priv->builder, "no_crop_menuitem")), TRUE); -} - - -void four_by_six_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -four_by_six_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "4x6"); -} - -                          -void legal_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -legal_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "legal"); -} - -                          -void letter_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -letter_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "letter"); -} - -                          -void a6_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -a6_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "A6"); -} - - -void a5_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -a5_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "A5"); -} +struct _ScanDevice { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanDevicePrivate * priv; +	gchar* name; +	gchar* label; +}; -                          -void a4_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -a4_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui) -{ -    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) -        set_crop (ui, "A4"); -} +struct _ScanDeviceClass { +	GTypeClass parent_class; +	void (*finalize) (ScanDevice *self); +}; +typedef enum  { +	SCAN_TYPE_SINGLE, +	SCAN_TYPE_ADF_FRONT, +	SCAN_TYPE_ADF_BACK, +	SCAN_TYPE_ADF_BOTH +} ScanType; + +typedef enum  { +	SCAN_MODE_DEFAULT, +	SCAN_MODE_COLOR, +	SCAN_MODE_GRAY, +	SCAN_MODE_LINEART +} ScanMode; + +struct _ScanOptions { +	GTypeInstance parent_instance; +	volatile int ref_count; +	ScanOptionsPrivate * priv; +	gint dpi; +	ScanMode scan_mode; +	gint depth; +	ScanType type; +	gint paper_width; +	gint paper_height; +}; -void crop_rotate_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -crop_rotate_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    Page *page; - -    page = book_view_get_selected (ui->priv->book_view); -    if (!page) -        return; -     -    page_rotate_crop (page); -} +struct _ScanOptionsClass { +	GTypeClass parent_class; +	void (*finalize) (ScanOptions *self); +}; +struct _ParamSpecSimpleScan { +	GParamSpec parent_instance; +}; -void page_move_left_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -page_move_left_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    Book *book = book_view_get_book (ui->priv->book_view); -    Page *page = book_view_get_selected (ui->priv->book_view); -    gint index; -    index = book_get_page_index (book, page); -    if (index > 0) -        book_move_page (book, page, index - 1); +static gpointer simple_scan_parent_class = NULL; + +gpointer simple_scan_ref (gpointer instance); +void simple_scan_unref (gpointer instance); +GParamSpec* param_spec_simple_scan (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_simple_scan (GValue* value, gpointer v_object); +void value_take_simple_scan (GValue* value, gpointer v_object); +gpointer value_get_simple_scan (const GValue* value); +GType simple_scan_get_type (void) G_GNUC_CONST; +gpointer book_ref (gpointer instance); +void book_unref (gpointer instance); +GParamSpec* param_spec_book (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_book (GValue* value, gpointer v_object); +void value_take_book (GValue* value, gpointer v_object); +gpointer value_get_book (const GValue* value); +GType book_get_type (void) G_GNUC_CONST; +GType book_view_get_type (void) G_GNUC_CONST; +GType scan_direction_get_type (void) G_GNUC_CONST; +#define SIMPLE_SCAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_SIMPLE_SCAN, SimpleScanPrivate)) +enum  { +	SIMPLE_SCAN_DUMMY_PROPERTY +}; +#define SIMPLE_SCAN_DEFAULT_TEXT_DPI 150 +#define SIMPLE_SCAN_DEFAULT_PHOTO_DPI 300 +SimpleScan* simple_scan_new (void); +SimpleScan* simple_scan_construct (GType object_type); +Book* book_new (void); +Book* book_construct (GType object_type); +gpointer page_ref (gpointer instance); +void page_unref (gpointer instance); +GParamSpec* param_spec_page (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_page (GValue* value, gpointer v_object); +void value_take_page (GValue* value, gpointer v_object); +gpointer value_get_page (const GValue* value); +GType page_get_type (void) G_GNUC_CONST; +static void simple_scan_page_removed_cb (SimpleScan* self, Book* book, Page* page); +static void _simple_scan_page_removed_cb_book_page_removed (Book* _sender, Page* page, gpointer self); +static void simple_scan_page_added_cb (SimpleScan* self, Book* book, Page* page); +static void _simple_scan_page_added_cb_book_page_added (Book* _sender, Page* page, gpointer self); +static void simple_scan_load (SimpleScan* self); +static gboolean simple_scan_find_scan_device (SimpleScan* self, const gchar* device, GtkTreeIter* iter); +static void simple_scan_show_error_dialog (SimpleScan* self, const gchar* error_title, const gchar* error_text); +void simple_scan_set_default_file_name (SimpleScan* self, const gchar* default_file_name); +void simple_scan_authorize (SimpleScan* self, const gchar* resource, gchar** username, gchar** password); +void G_MODULE_EXPORT device_combo_changed_cb (GtkWidget* widget, SimpleScan* self); +static void simple_scan_update_info_bar (SimpleScan* self); +gpointer scan_device_ref (gpointer instance); +void scan_device_unref (gpointer instance); +GParamSpec* param_spec_scan_device (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_device (GValue* value, gpointer v_object); +void value_take_scan_device (GValue* value, gpointer v_object); +gpointer value_get_scan_device (const GValue* value); +GType scan_device_get_type (void) G_GNUC_CONST; +void simple_scan_set_scan_devices (SimpleScan* self, GList* devices); +static gchar* simple_scan_get_selected_device (SimpleScan* self); +void simple_scan_set_selected_device (SimpleScan* self, const gchar* device); +static void simple_scan_add_default_page (SimpleScan* self); +Page* book_append_page (Book* self, gint width, gint height, gint dpi, ScanDirection scan_direction); +void book_view_select_page (BookView* self, Page* page); +static void simple_scan_on_file_type_changed (SimpleScan* self, GtkTreeSelection* selection); +static gchar* simple_scan_choose_file_location (SimpleScan* self); +static void _simple_scan_on_file_type_changed_gtk_tree_selection_changed (GtkTreeSelection* _sender, gpointer self); +static gboolean simple_scan_save_document (SimpleScan* self, gboolean force_choose_location); +void book_save (Book* self, const gchar* type, GFile* file, GError** error); +void simple_scan_show_error (SimpleScan* self, const gchar* error_title, const gchar* error_text, gboolean change_scanner_hint); +void book_set_needs_saving (Book* self, gboolean needs_saving); +static gboolean simple_scan_prompt_to_save (SimpleScan* self, const gchar* title, const gchar* discard_label); +gboolean book_get_needs_saving (Book* self); +static void simple_scan_clear_document (SimpleScan* self); +void book_clear (Book* self); +void G_MODULE_EXPORT new_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +static void simple_scan_set_document_hint (SimpleScan* self, const gchar* document_hint); +void G_MODULE_EXPORT text_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT photo_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +GType scan_type_get_type (void) G_GNUC_CONST; +static void simple_scan_set_page_side (SimpleScan* self, ScanType page_side); +static void simple_scan_set_paper_size (SimpleScan* self, gint width, gint height); +static gint simple_scan_get_text_dpi (SimpleScan* self); +static gint simple_scan_get_photo_dpi (SimpleScan* self); +static ScanType simple_scan_get_page_side (SimpleScan* self); +static gboolean simple_scan_get_paper_size (SimpleScan* self, gint* width, gint* height); +gpointer scan_options_ref (gpointer instance); +void scan_options_unref (gpointer instance); +GParamSpec* param_spec_scan_options (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags); +void value_set_scan_options (GValue* value, gpointer v_object); +void value_take_scan_options (GValue* value, gpointer v_object); +gpointer value_get_scan_options (const GValue* value); +GType scan_options_get_type (void) G_GNUC_CONST; +static ScanOptions* simple_scan_get_scan_options (SimpleScan* self); +ScanOptions* scan_options_new (void); +ScanOptions* scan_options_construct (GType object_type); +GType scan_mode_get_type (void) G_GNUC_CONST; +void G_MODULE_EXPORT scan_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT stop_scan_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT continuous_scan_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT preferences_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +gboolean G_MODULE_EXPORT preferences_dialog_delete_event_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT preferences_dialog_response_cb (GtkWidget* widget, gint response_id, SimpleScan* self); +static void simple_scan_update_page_menu (SimpleScan* self); +Page* book_view_get_selected (BookView* self); +guint book_get_page_index (Book* self, Page* page); +guint book_get_n_pages (Book* self); +static void simple_scan_page_selected_cb (SimpleScan* self, BookView* view, Page* page); +gboolean page_has_crop (Page* self); +gchar* page_get_named_crop (Page* self); +static gchar* simple_scan_get_temporary_filename (SimpleScan* self, const gchar* prefix, const gchar* extension); +static void simple_scan_show_page_cb (SimpleScan* self, BookView* view, Page* page); +void page_save (Page* self, const gchar* type, GFile* file, GError** error); +static void simple_scan_show_page_menu_cb (SimpleScan* self, BookView* view); +void G_MODULE_EXPORT rotate_left_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void page_rotate_left (Page* self); +void G_MODULE_EXPORT rotate_right_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void page_rotate_right (Page* self); +static void simple_scan_set_crop (SimpleScan* self, const gchar* crop_name); +void page_set_no_crop (Page* self); +gint page_get_width (Page* self); +gint page_get_height (Page* self); +void page_set_custom_crop (Page* self, gint width, gint height); +void page_move_crop (Page* self, gint x, gint y); +void page_set_named_crop (Page* self, const gchar* name); +void G_MODULE_EXPORT no_crop_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT custom_crop_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT crop_toolbutton_toggled_cb (GtkToggleToolButton* widget, SimpleScan* self); +void G_MODULE_EXPORT four_by_six_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT legal_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT letter_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT a6_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT a5_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT a4_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self); +void G_MODULE_EXPORT crop_rotate_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +void page_rotate_crop (Page* self); +void G_MODULE_EXPORT page_move_left_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +void book_move_page (Book* self, Page* page, guint location); +void G_MODULE_EXPORT page_move_right_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT page_delete_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +Book* book_view_get_book (BookView* self); +void book_delete_page (Book* self, Page* page); +void G_MODULE_EXPORT save_file_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT save_as_file_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +static void simple_scan_draw_page (SimpleScan* self, GtkPrintOperation* operation, GtkPrintContext* print_context, gint page_number); +Page* book_get_page (Book* self, gint page_number); +gboolean page_is_landscape (Page* self); +gint page_get_dpi (Page* self); +GdkPixbuf* page_get_image (Page* self, gboolean apply_crop); +void G_MODULE_EXPORT email_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT print_button_clicked_cb (GtkWidget* widget, SimpleScan* self); +static void _simple_scan_draw_page_gtk_print_operation_draw_page (GtkPrintOperation* _sender, GtkPrintContext* context, gint page_nr, gpointer self); +void G_MODULE_EXPORT help_contents_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +void G_MODULE_EXPORT about_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +static gboolean simple_scan_on_quit (SimpleScan* self); +void G_MODULE_EXPORT quit_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self); +gboolean G_MODULE_EXPORT simple_scan_window_configure_event_cb (GtkWidget* widget, GdkEventConfigure* event, SimpleScan* self); +static void simple_scan_info_bar_response_cb (SimpleScan* self, GtkInfoBar* widget, gint response_id); +gboolean G_MODULE_EXPORT simple_scan_window_window_state_event_cb (GtkWidget* widget, GdkEventWindowState* event, SimpleScan* self); +gboolean G_MODULE_EXPORT window_delete_event_cb (GtkWidget* widget, GdkEvent* event, SimpleScan* self); +static void simple_scan_page_size_changed_cb (SimpleScan* self, Page* page); +static void simple_scan_page_scan_direction_changed_cb (SimpleScan* self, Page* page); +ScanDirection page_get_scan_direction (Page* self); +static void _simple_scan_page_size_changed_cb_page_size_changed (Page* _sender, gpointer self); +static void _simple_scan_page_scan_direction_changed_cb_page_scan_direction_changed (Page* _sender, gpointer self); +static void simple_scan_set_dpi_combo (SimpleScan* self, GtkComboBox* combo, gint default_dpi, gint current_dpi); +static void simple_scan_needs_saving_cb (SimpleScan* self, Book* book); +static void _simple_scan_info_bar_response_cb_gtk_info_bar_response (GtkInfoBar* _sender, gint response_id, gpointer self); +BookView* book_view_new (Book* book); +BookView* book_view_construct (GType object_type, Book* book); +static void _simple_scan_page_selected_cb_book_view_page_selected (BookView* _sender, Page* page, gpointer self); +static void _simple_scan_show_page_cb_book_view_show_page (BookView* _sender, Page* page, gpointer self); +static void _simple_scan_show_page_menu_cb_book_view_show_menu (BookView* _sender, gpointer self); +static void _simple_scan_needs_saving_cb_book_needs_saving_changed (Book* _sender, gpointer self); +Book* simple_scan_get_book (SimpleScan* self); +void simple_scan_set_selected_page (SimpleScan* self, Page* page); +Page* simple_scan_get_selected_page (SimpleScan* self); +void simple_scan_set_scanning (SimpleScan* self, gboolean scanning); +void simple_scan_start (SimpleScan* self); +static void g_cclosure_user_marshal_VOID__STRING_SCAN_OPTIONS (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); +static void simple_scan_finalize (SimpleScan* obj); +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func); +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func); + + +static void _simple_scan_page_removed_cb_book_page_removed (Book* _sender, Page* page, gpointer self) { +	simple_scan_page_removed_cb (self, _sender, page); +} + + +static void _simple_scan_page_added_cb_book_page_added (Book* _sender, Page* page, gpointer self) { +	simple_scan_page_added_cb (self, _sender, page); +} + + +SimpleScan* simple_scan_construct (GType object_type) { +	SimpleScan* self = NULL; +	Book* _tmp0_ = NULL; +	GSettings* _tmp1_ = NULL; +	self = (SimpleScan*) g_type_create_instance (object_type); +	_tmp0_ = book_new (); +	_book_unref0 (self->priv->book); +	self->priv->book = _tmp0_; +	g_signal_connect (self->priv->book, "page-removed", (GCallback) _simple_scan_page_removed_cb_book_page_removed, self); +	g_signal_connect (self->priv->book, "page-added", (GCallback) _simple_scan_page_added_cb_book_page_added, self); +	_tmp1_ = g_settings_new ("org.gnome.SimpleScan"); +	_g_object_unref0 (self->priv->settings); +	self->priv->settings = _tmp1_; +	simple_scan_load (self); +	return self; +} + + +SimpleScan* simple_scan_new (void) { +	return simple_scan_construct (TYPE_SIMPLE_SCAN); +} + + +static gboolean simple_scan_find_scan_device (SimpleScan* self, const gchar* device, GtkTreeIter* iter) { +	GtkTreeIter _iter = {0}; +	gboolean result = FALSE; +	gboolean have_iter; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (device != NULL, FALSE); +	have_iter = FALSE; +	_tmp1_ = gtk_tree_model_get_iter_first ((GtkTreeModel*) self->priv->device_model, &_tmp0_); +	_iter = _tmp0_; +	if (_tmp1_) { +		{ +			gboolean _tmp2_; +			_tmp2_ = TRUE; +			while (TRUE) { +				gchar* d = NULL; +				if (!_tmp2_) { +					gboolean _tmp3_ = FALSE; +					if (!have_iter) { +						gboolean _tmp4_; +						_tmp4_ = gtk_tree_model_iter_next ((GtkTreeModel*) self->priv->device_model, &_iter); +						_tmp3_ = _tmp4_; +					} else { +						_tmp3_ = FALSE; +					} +					if (!_tmp3_) { +						break; +					} +				} +				_tmp2_ = FALSE; +				gtk_tree_model_get ((GtkTreeModel*) self->priv->device_model, &_iter, 0, &d, -1, -1); +				if (g_strcmp0 (d, device) == 0) { +					have_iter = TRUE; +				} +				_g_free0 (d); +			} +		} +	} +	result = have_iter; +	if (iter) { +		*iter = _iter; +	} +	return result; +} + + +static void simple_scan_show_error_dialog (SimpleScan* self, const gchar* error_title, const gchar* error_text) { +	GtkMessageDialog* _tmp0_ = NULL; +	GtkMessageDialog* dialog; +	g_return_if_fail (self != NULL); +	g_return_if_fail (error_title != NULL); +	g_return_if_fail (error_text != NULL); +	_tmp0_ = (GtkMessageDialog*) gtk_message_dialog_new (self->priv->window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", error_title); +	dialog = g_object_ref_sink (_tmp0_); +	gtk_dialog_add_button ((GtkDialog*) dialog, GTK_STOCK_CLOSE, 0); +	gtk_message_dialog_format_secondary_text (dialog, "%s", error_text, NULL); +	gtk_widget_destroy ((GtkWidget*) dialog); +	_g_object_unref0 (dialog); +} + + +void simple_scan_set_default_file_name (SimpleScan* self, const gchar* default_file_name) { +	gchar* _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (default_file_name != NULL); +	_tmp0_ = g_strdup (default_file_name); +	_g_free0 (self->priv->default_file_name); +	self->priv->default_file_name = _tmp0_; +} + + +void simple_scan_authorize (SimpleScan* self, const gchar* resource, gchar** username, gchar** password) { +	gchar* _username = NULL; +	gchar* _password = NULL; +	const gchar* _tmp0_ = NULL; +	gchar* _tmp1_ = NULL; +	gchar* description; +	const gchar* _tmp2_ = NULL; +	gchar* _tmp3_; +	const gchar* _tmp4_ = NULL; +	gchar* _tmp5_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (resource != NULL); +	_tmp0_ = _ ("Username and password required to access '%s'"); +	_tmp1_ = g_strdup_printf (_tmp0_, resource); +	description = _tmp1_; +	gtk_entry_set_text (self->priv->username_entry, ""); +	gtk_entry_set_text (self->priv->password_entry, ""); +	gtk_label_set_text (self->priv->authorize_label, description); +	gtk_widget_show ((GtkWidget*) self->priv->authorize_dialog); +	gtk_dialog_run (self->priv->authorize_dialog); +	gtk_widget_hide ((GtkWidget*) self->priv->authorize_dialog); +	_tmp2_ = gtk_entry_get_text (self->priv->username_entry); +	_tmp3_ = g_strdup (_tmp2_); +	_g_free0 (_username); +	_username = _tmp3_; +	_tmp4_ = gtk_entry_get_text (self->priv->password_entry); +	_tmp5_ = g_strdup (_tmp4_); +	_g_free0 (_password); +	_password = _tmp5_; +	_g_free0 (description); +	if (username) { +		*username = _username; +	} else { +		_g_free0 (_username); +	} +	if (password) { +		*password = _password; +	} else { +		_g_free0 (_password); +	} +} + + +void G_MODULE_EXPORT device_combo_changed_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	if (self->priv->setting_devices) { +		return; +	} +	self->priv->user_selected_device = TRUE; +} + + +static void simple_scan_update_info_bar (SimpleScan* self) { +	GtkMessageType type = 0; +	gchar* title = NULL; +	gchar* text = NULL; +	gchar* image_id = NULL; +	gboolean show_close_button; +	gboolean show_change_scanner_button; +	gchar* _tmp9_ = NULL; +	gchar* message; +	g_return_if_fail (self != NULL); +	show_close_button = FALSE; +	show_change_scanner_button = FALSE; +	if (self->priv->have_error) { +		gchar* _tmp0_; +		gchar* _tmp1_; +		gchar* _tmp2_; +		type = GTK_MESSAGE_ERROR; +		_tmp0_ = g_strdup (GTK_STOCK_DIALOG_ERROR); +		_g_free0 (image_id); +		image_id = _tmp0_; +		_tmp1_ = g_strdup (self->priv->error_title); +		_g_free0 (title); +		title = _tmp1_; +		_tmp2_ = g_strdup (self->priv->error_text); +		_g_free0 (text); +		text = _tmp2_; +		show_close_button = TRUE; +		show_change_scanner_button = self->priv->error_change_scanner_hint; +	} else { +		gint _tmp3_; +		_tmp3_ = gtk_tree_model_iter_n_children ((GtkTreeModel*) self->priv->device_model, NULL); +		if (_tmp3_ == 0) { +			gchar* _tmp4_; +			const gchar* _tmp5_ = NULL; +			gchar* _tmp6_; +			const gchar* _tmp7_ = NULL; +			gchar* _tmp8_; +			type = GTK_MESSAGE_WARNING; +			_tmp4_ = g_strdup (GTK_STOCK_DIALOG_WARNING); +			_g_free0 (image_id); +			image_id = _tmp4_; +			_tmp5_ = _ ("No scanners detected"); +			_tmp6_ = g_strdup (_tmp5_); +			_g_free0 (title); +			title = _tmp6_; +			_tmp7_ = _ ("Please check your scanner is connected and powered on"); +			_tmp8_ = g_strdup (_tmp7_); +			_g_free0 (text); +			text = _tmp8_; +		} else { +			gtk_widget_hide ((GtkWidget*) self->priv->info_bar); +			_g_free0 (image_id); +			_g_free0 (text); +			_g_free0 (title); +			return; +		} +	} +	gtk_info_bar_set_message_type (self->priv->info_bar, type); +	gtk_image_set_from_stock (self->priv->info_bar_image, image_id, GTK_ICON_SIZE_DIALOG); +	_tmp9_ = g_strdup_printf ("<big><b>%s</b></big>\n\n%s", title, text); +	message = _tmp9_; +	gtk_label_set_markup (self->priv->info_bar_label, message); +	gtk_widget_set_visible ((GtkWidget*) self->priv->info_bar_close_button, show_close_button); +	gtk_widget_set_visible ((GtkWidget*) self->priv->info_bar_change_scanner_button, show_change_scanner_button); +	gtk_widget_show ((GtkWidget*) self->priv->info_bar); +	_g_free0 (message); +	_g_free0 (image_id); +	_g_free0 (text); +	_g_free0 (title); +} + + +static gpointer _scan_device_ref0 (gpointer self) { +	return self ? scan_device_ref (self) : NULL; +} + + +void simple_scan_set_scan_devices (SimpleScan* self, GList* devices) { +	gboolean have_selection; +	gint index = 0; +	GtkTreeIter iter = {0}; +	gboolean _tmp11_ = FALSE; +	g_return_if_fail (self != NULL); +	have_selection = FALSE; +	self->priv->setting_devices = TRUE; +	if (self->priv->user_selected_device) { +		gint _tmp0_; +		_tmp0_ = gtk_combo_box_get_active (self->priv->device_combo); +		have_selection = _tmp0_ >= 0; +	} +	index = 0; +	{ +		GList* device_collection = NULL; +		GList* device_it = NULL; +		device_collection = devices; +		for (device_it = device_collection; device_it != NULL; device_it = device_it->next) { +			ScanDevice* _tmp1_; +			ScanDevice* device = NULL; +			_tmp1_ = _scan_device_ref0 ((ScanDevice*) device_it->data); +			device = _tmp1_; +			{ +				gint n_delete; +				GtkTreeIter _tmp2_ = {0}; +				gboolean _tmp3_; +				n_delete = -1; +				_tmp3_ = gtk_tree_model_iter_nth_child ((GtkTreeModel*) self->priv->device_model, &_tmp2_, NULL, index); +				iter = _tmp2_; +				if (_tmp3_) { +					gint i; +					i = 0; +					{ +						gboolean _tmp4_; +						_tmp4_ = TRUE; +						while (TRUE) { +							gchar* name = NULL; +							gboolean matched = FALSE; +							if (!_tmp4_) { +								gboolean _tmp5_; +								_tmp5_ = gtk_tree_model_iter_next ((GtkTreeModel*) self->priv->device_model, &iter); +								if (!_tmp5_) { +									break; +								} +							} +							_tmp4_ = FALSE; +							gtk_tree_model_get ((GtkTreeModel*) self->priv->device_model, &iter, 0, &name, -1, -1); +							matched = g_strcmp0 (name, device->name) == 0; +							if (matched) { +								n_delete = i; +								_g_free0 (name); +								break; +							} +							i++; +							_g_free0 (name); +						} +					} +				} +				if (n_delete >= 0) { +					gint i = 0; +					gtk_list_store_set (self->priv->device_model, &iter, 1, device->label, -1, -1); +					{ +						gboolean _tmp6_; +						i = 0; +						_tmp6_ = TRUE; +						while (TRUE) { +							GtkTreeIter _tmp7_ = {0}; +							if (!_tmp6_) { +								i++; +							} +							_tmp6_ = FALSE; +							if (!(i < n_delete)) { +								break; +							} +							gtk_tree_model_iter_nth_child ((GtkTreeModel*) self->priv->device_model, &_tmp7_, NULL, index); +							iter = _tmp7_; +							gtk_list_store_remove (self->priv->device_model, &iter); +						} +					} +				} else { +					GtkTreeIter _tmp8_ = {0}; +					gtk_list_store_insert (self->priv->device_model, &_tmp8_, index); +					iter = _tmp8_; +					gtk_list_store_set (self->priv->device_model, &iter, 0, device->name, 1, device->label, -1, -1); +				} +				index++; +				_scan_device_unref0 (device); +			} +		} +	} +	while (TRUE) { +		GtkTreeIter _tmp9_ = {0}; +		gboolean _tmp10_; +		_tmp10_ = gtk_tree_model_iter_nth_child ((GtkTreeModel*) self->priv->device_model, &_tmp9_, NULL, index); +		iter = _tmp9_; +		if (!_tmp10_) { +			break; +		} +		gtk_list_store_remove (self->priv->device_model, &iter); +	} +	if (!have_selection) { +		_tmp11_ = devices != NULL; +	} else { +		_tmp11_ = FALSE; +	} +	if (_tmp11_) { +		gtk_combo_box_set_active (self->priv->device_combo, 0); +	} +	self->priv->setting_devices = FALSE; +	simple_scan_update_info_bar (self); +} + + +static gchar* simple_scan_get_selected_device (SimpleScan* self) { +	gchar* result = NULL; +	GtkTreeIter iter = {0}; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp1_ = gtk_combo_box_get_active_iter (self->priv->device_combo, &_tmp0_); +	iter = _tmp0_; +	if (_tmp1_) { +		gchar* device = NULL; +		gtk_tree_model_get ((GtkTreeModel*) self->priv->device_model, &iter, 0, &device, -1, -1); +		result = device; +		return result; +	} +	result = NULL; +	return result; +} + + +void simple_scan_set_selected_device (SimpleScan* self, const gchar* device) { +	GtkTreeIter iter = {0}; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (device != NULL); +	_tmp1_ = simple_scan_find_scan_device (self, device, &_tmp0_); +	iter = _tmp0_; +	if (!_tmp1_) { +		return; +	} +	gtk_combo_box_set_active_iter (self->priv->device_combo, &iter); +	self->priv->user_selected_device = TRUE; +} + + +static void simple_scan_add_default_page (SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	_tmp0_ = book_append_page (self->priv->book, self->priv->default_page_width, self->priv->default_page_height, self->priv->default_page_dpi, self->priv->default_page_scan_direction); +	page = _tmp0_; +	book_view_select_page (self->priv->book_view, page); +	_page_unref0 (page); +} + + +static gpointer _g_object_ref0 (gpointer self) { +	return self ? g_object_ref (self) : NULL; +} + + +static gint string_last_index_of_char (const gchar* self, gunichar c, gint start_index) { +	gint result = 0; +	gchar* _tmp0_ = NULL; +	gchar* _result_; +	g_return_val_if_fail (self != NULL, 0); +	_tmp0_ = g_utf8_strrchr (((gchar*) self) + start_index, (gssize) (-1), c); +	_result_ = _tmp0_; +	if (_result_ != NULL) { +		result = (gint) (_result_ - ((gchar*) self)); +		return result; +	} else { +		result = -1; +		return result; +	} +} + + +static gchar* string_slice (const gchar* self, glong start, glong end) { +	gchar* result = NULL; +	gint _tmp0_; +	glong string_length; +	gboolean _tmp1_ = FALSE; +	gboolean _tmp2_ = FALSE; +	gchar* _tmp3_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = strlen (self); +	string_length = (glong) _tmp0_; +	if (start < ((glong) 0)) { +		start = string_length + start; +	} +	if (end < ((glong) 0)) { +		end = string_length + end; +	} +	if (start >= ((glong) 0)) { +		_tmp1_ = start <= string_length; +	} else { +		_tmp1_ = FALSE; +	} +	g_return_val_if_fail (_tmp1_, NULL); +	if (end >= ((glong) 0)) { +		_tmp2_ = end <= string_length; +	} else { +		_tmp2_ = FALSE; +	} +	g_return_val_if_fail (_tmp2_, NULL); +	g_return_val_if_fail (start <= end, NULL); +	_tmp3_ = g_strndup (((gchar*) self) + start, (gsize) (end - start)); +	result = _tmp3_; +	return result; +} + + +static void simple_scan_on_file_type_changed (SimpleScan* self, GtkTreeSelection* selection) { +	GtkTreeModel* model = NULL; +	GtkTreeIter iter = {0}; +	GtkTreeModel* _tmp0_ = NULL; +	GtkTreeIter _tmp1_ = {0}; +	gboolean _tmp2_; +	GtkTreeModel* _tmp3_; +	gchar* extension = NULL; +	gchar* _tmp4_ = NULL; +	gchar* path; +	gchar* _tmp5_ = NULL; +	gchar* filename; +	gint _tmp6_; +	gint extension_index; +	gchar* _tmp8_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (selection != NULL); +	_tmp2_ = gtk_tree_selection_get_selected (selection, &_tmp0_, &_tmp1_); +	_g_object_unref0 (model); +	_tmp3_ = _g_object_ref0 (_tmp0_); +	model = _tmp3_; +	iter = _tmp1_; +	if (!_tmp2_) { +		_g_object_unref0 (model); +		return; +	} +	gtk_tree_model_get (model, &iter, 1, &extension, -1, -1); +	_tmp4_ = gtk_file_chooser_get_filename ((GtkFileChooser*) self->priv->save_dialog); +	path = _tmp4_; +	_tmp5_ = g_path_get_basename (path); +	filename = _tmp5_; +	_tmp6_ = string_last_index_of_char (filename, (gunichar) '.', 0); +	extension_index = _tmp6_; +	if (extension_index >= 0) { +		gchar* _tmp7_ = NULL; +		_tmp7_ = string_slice (filename, (glong) 0, (glong) extension_index); +		_g_free0 (filename); +		filename = _tmp7_; +	} +	_tmp8_ = g_strconcat (filename, extension, NULL); +	_g_free0 (filename); +	filename = _tmp8_; +	gtk_file_chooser_set_current_name ((GtkFileChooser*) self->priv->save_dialog, filename); +	_g_free0 (filename); +	_g_free0 (path); +	_g_free0 (extension); +	_g_object_unref0 (model); +} + + +static void _simple_scan_on_file_type_changed_gtk_tree_selection_changed (GtkTreeSelection* _sender, gpointer self) { +	simple_scan_on_file_type_changed (self, _sender); +} + + +static gchar* simple_scan_choose_file_location (SimpleScan* self) { +	gchar* result = NULL; +	gchar* directory; +	gchar* _tmp0_ = NULL; +	gboolean _tmp1_ = FALSE; +	const gchar* _tmp4_ = NULL; +	GtkFileChooserDialog* _tmp5_ = NULL; +	GtkFileFilter* _tmp6_ = NULL; +	GtkFileFilter* filter; +	const gchar* _tmp7_ = NULL; +	GtkFileFilter* _tmp8_ = NULL; +	const gchar* _tmp9_ = NULL; +	const gchar* _tmp10_ = NULL; +	GtkExpander* _tmp11_ = NULL; +	GtkExpander* expander; +	gchar* _tmp12_; +	gchar* extension; +	gint _tmp13_; +	gint index; +	GtkListStore* _tmp15_ = NULL; +	GtkListStore* file_type_store; +	GtkTreeIter iter = {0}; +	GtkTreeIter _tmp16_ = {0}; +	const gchar* _tmp17_ = NULL; +	GtkTreeIter _tmp18_ = {0}; +	const gchar* _tmp19_ = NULL; +	GtkTreeIter _tmp20_ = {0}; +	const gchar* _tmp21_ = NULL; +	GtkTreeView* _tmp22_ = NULL; +	GtkTreeView* file_type_view; +	GtkCellRendererText* _tmp23_ = NULL; +	GtkCellRendererText* _tmp24_; +	GtkTreeViewColumn* _tmp25_ = NULL; +	GtkTreeViewColumn* _tmp26_; +	GtkTreeViewColumn* column; +	GtkTreeIter _tmp27_ = {0}; +	gboolean _tmp28_; +	GtkTreeSelection* _tmp32_ = NULL; +	gint _tmp33_; +	gint response; +	gchar* uri; +	gchar* _tmp35_ = NULL; +	gchar* _tmp36_; +	g_return_val_if_fail (self != NULL, NULL); +	directory = NULL; +	_tmp0_ = g_settings_get_string (self->priv->settings, "save-directory"); +	_g_free0 (directory); +	directory = _tmp0_; +	if (directory == NULL) { +		_tmp1_ = TRUE; +	} else { +		_tmp1_ = g_strcmp0 (directory, "") == 0; +	} +	if (_tmp1_) { +		const gchar* _tmp2_ = NULL; +		gchar* _tmp3_; +		_tmp2_ = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); +		_tmp3_ = g_strdup (_tmp2_); +		_g_free0 (directory); +		directory = _tmp3_; +	} +	_tmp4_ = _ ("Save As..."); +	_tmp5_ = (GtkFileChooserDialog*) gtk_file_chooser_dialog_new (_tmp4_, self->priv->window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL, NULL); +	_g_object_unref0 (self->priv->save_dialog); +	self->priv->save_dialog = g_object_ref_sink (_tmp5_); +	gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser*) self->priv->save_dialog, TRUE); +	gtk_file_chooser_set_local_only ((GtkFileChooser*) self->priv->save_dialog, FALSE); +	gtk_file_chooser_set_current_folder ((GtkFileChooser*) self->priv->save_dialog, directory); +	gtk_file_chooser_set_current_name ((GtkFileChooser*) self->priv->save_dialog, self->priv->default_file_name); +	_tmp6_ = gtk_file_filter_new (); +	filter = g_object_ref_sink (_tmp6_); +	_tmp7_ = _ ("Image Files"); +	gtk_buildable_set_name ((GtkBuildable*) filter, _tmp7_); +	gtk_file_filter_add_pixbuf_formats (filter); +	gtk_file_filter_add_mime_type (filter, "application/pdf"); +	gtk_file_chooser_add_filter ((GtkFileChooser*) self->priv->save_dialog, filter); +	_tmp8_ = gtk_file_filter_new (); +	_g_object_unref0 (filter); +	filter = g_object_ref_sink (_tmp8_); +	_tmp9_ = _ ("All Files"); +	gtk_buildable_set_name ((GtkBuildable*) filter, _tmp9_); +	gtk_file_filter_add_pattern (filter, "*"); +	gtk_file_chooser_add_filter ((GtkFileChooser*) self->priv->save_dialog, filter); +	_tmp10_ = _ ("Select File _Type"); +	_tmp11_ = (GtkExpander*) gtk_expander_new_with_mnemonic (_tmp10_); +	expander = g_object_ref_sink (_tmp11_); +	gtk_expander_set_spacing (expander, 5); +	gtk_file_chooser_set_extra_widget ((GtkFileChooser*) self->priv->save_dialog, (GtkWidget*) expander); +	_tmp12_ = g_strdup (""); +	extension = _tmp12_; +	_tmp13_ = string_last_index_of_char (self->priv->default_file_name, (gunichar) '.', 0); +	index = _tmp13_; +	if (index >= 0) { +		gchar* _tmp14_ = NULL; +		_tmp14_ = string_slice (self->priv->default_file_name, (glong) 0, (glong) index); +		_g_free0 (extension); +		extension = _tmp14_; +	} +	_tmp15_ = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); +	file_type_store = _tmp15_; +	gtk_list_store_append (file_type_store, &_tmp16_); +	iter = _tmp16_; +	_tmp17_ = _ ("PDF (multi-page document)"); +	gtk_list_store_set (file_type_store, &iter, 0, _tmp17_, 1, ".pdf", -1, -1); +	gtk_list_store_append (file_type_store, &_tmp18_); +	iter = _tmp18_; +	_tmp19_ = _ ("JPEG (compressed)"); +	gtk_list_store_set (file_type_store, &iter, 0, _tmp19_, 1, ".jpg", -1, -1); +	gtk_list_store_append (file_type_store, &_tmp20_); +	iter = _tmp20_; +	_tmp21_ = _ ("PNG (lossless)"); +	gtk_list_store_set (file_type_store, &iter, 0, _tmp21_, 1, ".png", -1, -1); +	_tmp22_ = (GtkTreeView*) gtk_tree_view_new_with_model ((GtkTreeModel*) file_type_store); +	file_type_view = g_object_ref_sink (_tmp22_); +	gtk_tree_view_set_headers_visible (file_type_view, FALSE); +	gtk_tree_view_set_rules_hint (file_type_view, TRUE); +	_tmp23_ = (GtkCellRendererText*) gtk_cell_renderer_text_new (); +	_tmp24_ = g_object_ref_sink (_tmp23_); +	_tmp25_ = gtk_tree_view_column_new_with_attributes ("", (GtkCellRenderer*) _tmp24_, "text", 0, NULL, NULL); +	_tmp26_ = g_object_ref_sink (_tmp25_); +	_g_object_unref0 (_tmp24_); +	column = _tmp26_; +	gtk_tree_view_append_column (file_type_view, column); +	gtk_container_add ((GtkContainer*) expander, (GtkWidget*) file_type_view); +	_tmp28_ = gtk_tree_model_get_iter_first ((GtkTreeModel*) file_type_store, &_tmp27_); +	iter = _tmp27_; +	if (_tmp28_) { +		{ +			gboolean _tmp29_; +			_tmp29_ = TRUE; +			while (TRUE) { +				gchar* e = NULL; +				if (!_tmp29_) { +					gboolean _tmp30_; +					_tmp30_ = gtk_tree_model_iter_next ((GtkTreeModel*) file_type_store, &iter); +					if (!_tmp30_) { +						break; +					} +				} +				_tmp29_ = FALSE; +				gtk_tree_model_get ((GtkTreeModel*) file_type_store, &iter, 1, &e, -1, -1); +				if (g_strcmp0 (extension, e) == 0) { +					GtkTreeSelection* _tmp31_ = NULL; +					_tmp31_ = gtk_tree_view_get_selection (file_type_view); +					gtk_tree_selection_select_iter (_tmp31_, &iter); +				} +				_g_free0 (e); +			} +		} +	} +	_tmp32_ = gtk_tree_view_get_selection (file_type_view); +	g_signal_connect (_tmp32_, "changed", (GCallback) _simple_scan_on_file_type_changed_gtk_tree_selection_changed, self); +	gtk_widget_show_all ((GtkWidget*) expander); +	_tmp33_ = gtk_dialog_run ((GtkDialog*) self->priv->save_dialog); +	response = _tmp33_; +	uri = NULL; +	if (response == ((gint) GTK_RESPONSE_ACCEPT)) { +		gchar* _tmp34_ = NULL; +		_tmp34_ = gtk_file_chooser_get_uri ((GtkFileChooser*) self->priv->save_dialog); +		_g_free0 (uri); +		uri = _tmp34_; +	} +	_tmp35_ = gtk_file_chooser_get_current_folder ((GtkFileChooser*) self->priv->save_dialog); +	_tmp36_ = _tmp35_; +	g_settings_set_string (self->priv->settings, "save-directory", _tmp36_); +	_g_free0 (_tmp36_); +	gtk_widget_destroy ((GtkWidget*) self->priv->save_dialog); +	_g_object_unref0 (self->priv->save_dialog); +	self->priv->save_dialog = NULL; +	result = uri; +	_g_object_unref0 (column); +	_g_object_unref0 (file_type_view); +	_g_object_unref0 (file_type_store); +	_g_free0 (extension); +	_g_object_unref0 (expander); +	_g_object_unref0 (filter); +	_g_free0 (directory); +	return result; +} + + +static gboolean simple_scan_save_document (SimpleScan* self, gboolean force_choose_location) { +	gboolean result = FALSE; +	gchar* uri = NULL; +	gboolean _tmp0_ = FALSE; +	GFile* _tmp3_ = NULL; +	GFile* file; +	gchar* _tmp4_ = NULL; +	gchar* uri_lower; +	gchar* _tmp5_; +	gchar* format; +	gboolean _tmp6_; +	gchar* _tmp17_; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, FALSE); +	if (self->priv->book_uri != NULL) { +		_tmp0_ = !force_choose_location; +	} else { +		_tmp0_ = FALSE; +	} +	if (_tmp0_) { +		gchar* _tmp1_; +		_tmp1_ = g_strdup (self->priv->book_uri); +		_g_free0 (uri); +		uri = _tmp1_; +	} else { +		gchar* _tmp2_ = NULL; +		_tmp2_ = simple_scan_choose_file_location (self); +		_g_free0 (uri); +		uri = _tmp2_; +	} +	if (uri == NULL) { +		result = FALSE; +		_g_free0 (uri); +		return result; +	} +	_tmp3_ = g_file_new_for_uri (uri); +	file = _tmp3_; +	g_debug ("ui.vala:445: Saving to '%s'", uri); +	_tmp4_ = g_utf8_strdown (uri, (gssize) (-1)); +	uri_lower = _tmp4_; +	_tmp5_ = g_strdup ("jpeg"); +	format = _tmp5_; +	_tmp6_ = g_str_has_suffix (uri_lower, ".pdf"); +	if (_tmp6_) { +		gchar* _tmp7_; +		_tmp7_ = g_strdup ("pdf"); +		_g_free0 (format); +		format = _tmp7_; +	} else { +		gboolean _tmp8_; +		_tmp8_ = g_str_has_suffix (uri_lower, ".ps"); +		if (_tmp8_) { +			gchar* _tmp9_; +			_tmp9_ = g_strdup ("ps"); +			_g_free0 (format); +			format = _tmp9_; +		} else { +			gboolean _tmp10_; +			_tmp10_ = g_str_has_suffix (uri_lower, ".png"); +			if (_tmp10_) { +				gchar* _tmp11_; +				_tmp11_ = g_strdup ("png"); +				_g_free0 (format); +				format = _tmp11_; +			} else { +				gboolean _tmp12_ = FALSE; +				gboolean _tmp13_; +				_tmp13_ = g_str_has_suffix (uri_lower, ".tif"); +				if (_tmp13_) { +					_tmp12_ = TRUE; +				} else { +					gboolean _tmp14_; +					_tmp14_ = g_str_has_suffix (uri_lower, ".tiff"); +					_tmp12_ = _tmp14_; +				} +				if (_tmp12_) { +					gchar* _tmp15_; +					_tmp15_ = g_strdup ("tiff"); +					_g_free0 (format); +					format = _tmp15_; +				} +			} +		} +	} +	{ +		book_save (self->priv->book, format, file, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch10_g_error; +		} +	} +	goto __finally10; +	__catch10_g_error: +	{ +		GError* e = NULL; +		const gchar* _tmp16_ = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("ui.vala:464: Error saving file: %s", e->message); +		_tmp16_ = _ ("Failed to save file"); +		simple_scan_show_error (self, _tmp16_, e->message, FALSE); +		result = FALSE; +		_g_error_free0 (e); +		_g_free0 (format); +		_g_free0 (uri_lower); +		_g_object_unref0 (file); +		_g_free0 (uri); +		return result; +	} +	__finally10: +	if (_inner_error_ != NULL) { +		_g_free0 (format); +		_g_free0 (uri_lower); +		_g_object_unref0 (file); +		_g_free0 (uri); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return FALSE; +	} +	_tmp17_ = g_strdup (uri); +	_g_free0 (self->priv->book_uri); +	self->priv->book_uri = _tmp17_; +	book_set_needs_saving (self->priv->book, FALSE); +	result = TRUE; +	_g_free0 (format); +	_g_free0 (uri_lower); +	_g_object_unref0 (file); +	_g_free0 (uri); +	return result; +} + + +static gboolean simple_scan_prompt_to_save (SimpleScan* self, const gchar* title, const gchar* discard_label) { +	gboolean result = FALSE; +	gboolean _tmp0_; +	GtkMessageDialog* _tmp1_ = NULL; +	GtkMessageDialog* dialog; +	const gchar* _tmp2_ = NULL; +	gint _tmp3_; +	gint response; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (title != NULL, FALSE); +	g_return_val_if_fail (discard_label != NULL, FALSE); +	_tmp0_ = book_get_needs_saving (self->priv->book); +	if (!_tmp0_) { +		result = TRUE; +		return result; +	} +	_tmp1_ = (GtkMessageDialog*) gtk_message_dialog_new (self->priv->window, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", title); +	dialog = g_object_ref_sink (_tmp1_); +	_tmp2_ = _ ("If you don't save, changes will be permanently lost."); +	gtk_message_dialog_format_secondary_text (dialog, "%s", _tmp2_, NULL); +	gtk_dialog_add_button ((GtkDialog*) dialog, discard_label, (gint) GTK_RESPONSE_NO); +	gtk_dialog_add_button ((GtkDialog*) dialog, GTK_STOCK_CANCEL, (gint) GTK_RESPONSE_CANCEL); +	gtk_dialog_add_button ((GtkDialog*) dialog, GTK_STOCK_SAVE, (gint) GTK_RESPONSE_YES); +	_tmp3_ = gtk_dialog_run ((GtkDialog*) dialog); +	response = _tmp3_; +	gtk_widget_destroy ((GtkWidget*) dialog); +	switch (response) { +		case GTK_RESPONSE_YES: +		{ +			gboolean _tmp4_; +			_tmp4_ = simple_scan_save_document (self, FALSE); +			if (_tmp4_) { +				result = TRUE; +				_g_object_unref0 (dialog); +				return result; +			} else { +				result = FALSE; +				_g_object_unref0 (dialog); +				return result; +			} +		} +		case GTK_RESPONSE_CANCEL: +		{ +			result = FALSE; +			_g_object_unref0 (dialog); +			return result; +		} +		default: +		case GTK_RESPONSE_NO: +		{ +			result = TRUE; +			_g_object_unref0 (dialog); +			return result; +		} +	} +	_g_object_unref0 (dialog); +} + + +static void simple_scan_clear_document (SimpleScan* self) { +	g_return_if_fail (self != NULL); +	book_clear (self->priv->book); +	simple_scan_add_default_page (self); +	_g_free0 (self->priv->book_uri); +	self->priv->book_uri = NULL; +	book_set_needs_saving (self->priv->book, FALSE); +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->save_as_menuitem, FALSE); +} + + +void G_MODULE_EXPORT new_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	const gchar* _tmp0_ = NULL; +	const gchar* _tmp1_ = NULL; +	gboolean _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = _ ("Save current document?"); +	_tmp1_ = _ ("Discard Changes"); +	_tmp2_ = simple_scan_prompt_to_save (self, _tmp0_, _tmp1_); +	if (!_tmp2_) { +		return; +	} +	simple_scan_clear_document (self); +} + + +static void simple_scan_set_document_hint (SimpleScan* self, const gchar* document_hint) { +	gchar* _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (document_hint != NULL); +	_tmp0_ = g_strdup (document_hint); +	_g_free0 (self->priv->document_hint); +	self->priv->document_hint = _tmp0_; +	if (g_strcmp0 (document_hint, "text") == 0) { +		gtk_check_menu_item_set_active ((GtkCheckMenuItem*) self->priv->text_toolbar_menuitem, TRUE); +		gtk_check_menu_item_set_active ((GtkCheckMenuItem*) self->priv->text_menu_menuitem, TRUE); +	} else { +		if (g_strcmp0 (document_hint, "photo") == 0) { +			gtk_check_menu_item_set_active ((GtkCheckMenuItem*) self->priv->photo_toolbar_menuitem, TRUE); +			gtk_check_menu_item_set_active ((GtkCheckMenuItem*) self->priv->photo_menu_menuitem, TRUE); +		} +	} +} + + +void G_MODULE_EXPORT text_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_document_hint (self, "text"); +	} +} + + +void G_MODULE_EXPORT photo_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_document_hint (self, "photo"); +	} +} + + +static void simple_scan_set_page_side (SimpleScan* self, ScanType page_side) { +	GtkTreeIter iter = {0}; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_if_fail (self != NULL); +	_tmp1_ = gtk_tree_model_get_iter_first ((GtkTreeModel*) self->priv->page_side_model, &_tmp0_); +	iter = _tmp0_; +	if (_tmp1_) { +		{ +			gboolean _tmp2_; +			_tmp2_ = TRUE; +			while (TRUE) { +				gint s = 0; +				if (!_tmp2_) { +					gboolean _tmp3_; +					_tmp3_ = gtk_tree_model_iter_next ((GtkTreeModel*) self->priv->page_side_model, &iter); +					if (!_tmp3_) { +						break; +					} +				} +				_tmp2_ = FALSE; +				gtk_tree_model_get ((GtkTreeModel*) self->priv->page_side_model, &iter, 0, &s, -1, -1); +				if (s == ((gint) page_side)) { +					gtk_combo_box_set_active_iter (self->priv->page_side_combo, &iter); +					return; +				} +			} +		} +	} +} + + +static void simple_scan_set_paper_size (SimpleScan* self, gint width, gint height) { +	GtkTreeIter iter = {0}; +	gboolean have_iter = FALSE; +	g_return_if_fail (self != NULL); +	{ +		GtkTreeIter _tmp0_ = {0}; +		gboolean _tmp1_; +		gboolean _tmp2_; +		_tmp1_ = gtk_tree_model_get_iter_first ((GtkTreeModel*) self->priv->paper_size_model, &_tmp0_); +		iter = _tmp0_; +		have_iter = _tmp1_; +		_tmp2_ = TRUE; +		while (TRUE) { +			gint w = 0; +			gint h = 0; +			gboolean _tmp4_ = FALSE; +			if (!_tmp2_) { +				gboolean _tmp3_; +				_tmp3_ = gtk_tree_model_iter_next ((GtkTreeModel*) self->priv->paper_size_model, &iter); +				have_iter = _tmp3_; +			} +			_tmp2_ = FALSE; +			if (!have_iter) { +				break; +			} +			gtk_tree_model_get ((GtkTreeModel*) self->priv->paper_size_model, &iter, 0, &w, 1, &h, -1, -1); +			if (w == width) { +				_tmp4_ = h == height; +			} else { +				_tmp4_ = FALSE; +			} +			if (_tmp4_) { +				break; +			} +		} +	} +	if (!have_iter) { +		GtkTreeIter _tmp5_ = {0}; +		gboolean _tmp6_; +		_tmp6_ = gtk_tree_model_get_iter_first ((GtkTreeModel*) self->priv->paper_size_model, &_tmp5_); +		iter = _tmp5_; +		have_iter = _tmp6_; +	} +	if (have_iter) { +		gtk_combo_box_set_active_iter (self->priv->paper_size_combo, &iter); +	} +} + + +static gint simple_scan_get_text_dpi (SimpleScan* self) { +	gint result = 0; +	GtkTreeIter iter = {0}; +	gint dpi; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	dpi = SIMPLE_SCAN_DEFAULT_TEXT_DPI; +	_tmp1_ = gtk_combo_box_get_active_iter (self->priv->text_dpi_combo, &_tmp0_); +	iter = _tmp0_; +	if (_tmp1_) { +		gtk_tree_model_get ((GtkTreeModel*) self->priv->text_dpi_model, &iter, 0, &dpi, -1, -1); +	} +	result = dpi; +	return result; +} + + +static gint simple_scan_get_photo_dpi (SimpleScan* self) { +	gint result = 0; +	GtkTreeIter iter = {0}; +	gint dpi; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	dpi = SIMPLE_SCAN_DEFAULT_PHOTO_DPI; +	_tmp1_ = gtk_combo_box_get_active_iter (self->priv->photo_dpi_combo, &_tmp0_); +	iter = _tmp0_; +	if (_tmp1_) { +		gtk_tree_model_get ((GtkTreeModel*) self->priv->photo_dpi_model, &iter, 0, &dpi, -1, -1); +	} +	result = dpi; +	return result; +} + + +static ScanType simple_scan_get_page_side (SimpleScan* self) { +	ScanType result = 0; +	GtkTreeIter iter = {0}; +	gint page_side; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_val_if_fail (self != NULL, 0); +	page_side = (gint) SCAN_TYPE_ADF_BOTH; +	_tmp1_ = gtk_combo_box_get_active_iter (self->priv->page_side_combo, &_tmp0_); +	iter = _tmp0_; +	if (_tmp1_) { +		gtk_tree_model_get ((GtkTreeModel*) self->priv->page_side_model, &iter, 0, &page_side, -1, -1); +	} +	result = (ScanType) page_side; +	return result; +} + + +static gboolean simple_scan_get_paper_size (SimpleScan* self, gint* width, gint* height) { +	gint _width = 0; +	gint _height = 0; +	gboolean result = FALSE; +	GtkTreeIter iter = {0}; +	GtkTreeIter _tmp0_ = {0}; +	gboolean _tmp1_; +	g_return_val_if_fail (self != NULL, FALSE); +	_tmp1_ = gtk_combo_box_get_active_iter (self->priv->paper_size_combo, &_tmp0_); +	iter = _tmp0_; +	if (_tmp1_) { +		gtk_tree_model_get ((GtkTreeModel*) self->priv->paper_size_model, &iter, 0, &_width, 1, &_height, -1, -1); +		result = TRUE; +		if (width) { +			*width = _width; +		} +		if (height) { +			*height = _height; +		} +		return result; +	} +	result = FALSE; +	if (width) { +		*width = _width; +	} +	if (height) { +		*height = _height; +	} +	return result; +} + + +static ScanOptions* simple_scan_get_scan_options (SimpleScan* self) { +	ScanOptions* result = NULL; +	ScanOptions* _tmp0_ = NULL; +	ScanOptions* options; +	gint _tmp3_; +	gint _tmp4_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = scan_options_new (); +	options = _tmp0_; +	if (g_strcmp0 (self->priv->document_hint, "text") == 0) { +		gint _tmp1_; +		options->scan_mode = SCAN_MODE_GRAY; +		_tmp1_ = simple_scan_get_text_dpi (self); +		options->dpi = _tmp1_; +		options->depth = 2; +	} else { +		gint _tmp2_; +		options->scan_mode = SCAN_MODE_COLOR; +		_tmp2_ = simple_scan_get_photo_dpi (self); +		options->dpi = _tmp2_; +		options->depth = 8; +	} +	simple_scan_get_paper_size (self, &_tmp3_, &_tmp4_); +	options->paper_width = _tmp3_; +	options->paper_height = _tmp4_; +	result = options; +	return result; +} + + +void G_MODULE_EXPORT scan_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	ScanOptions* _tmp0_ = NULL; +	ScanOptions* options; +	gchar* _tmp1_ = NULL; +	gchar* _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = simple_scan_get_scan_options (self); +	options = _tmp0_; +	options->type = SCAN_TYPE_SINGLE; +	_tmp1_ = simple_scan_get_selected_device (self); +	_tmp2_ = _tmp1_; +	g_signal_emit_by_name (self, "start-scan", _tmp2_, options); +	_g_free0 (_tmp2_); +	_scan_options_unref0 (options); +} + + +void G_MODULE_EXPORT stop_scan_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	g_signal_emit_by_name (self, "stop-scan"); +} + + +void G_MODULE_EXPORT continuous_scan_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	if (self->priv->scanning) { +		g_signal_emit_by_name (self, "stop-scan"); +	} else { +		ScanOptions* _tmp0_ = NULL; +		ScanOptions* options; +		ScanType _tmp1_; +		gchar* _tmp2_ = NULL; +		gchar* _tmp3_; +		_tmp0_ = simple_scan_get_scan_options (self); +		options = _tmp0_; +		_tmp1_ = simple_scan_get_page_side (self); +		options->type = _tmp1_; +		_tmp2_ = simple_scan_get_selected_device (self); +		_tmp3_ = _tmp2_; +		g_signal_emit_by_name (self, "start-scan", _tmp3_, options); +		_g_free0 (_tmp3_); +		_scan_options_unref0 (options); +	} +} + + +void G_MODULE_EXPORT preferences_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	gtk_window_present ((GtkWindow*) self->priv->preferences_dialog); +} + + +gboolean G_MODULE_EXPORT preferences_dialog_delete_event_cb (GtkWidget* widget, SimpleScan* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	result = TRUE; +	return result; +} + + +void G_MODULE_EXPORT preferences_dialog_response_cb (GtkWidget* widget, gint response_id, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	gtk_widget_hide ((GtkWidget*) self->priv->preferences_dialog); +} + + +static void simple_scan_update_page_menu (SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	if (page == NULL) { +		gtk_widget_set_sensitive ((GtkWidget*) self->priv->page_move_left_menuitem, FALSE); +		gtk_widget_set_sensitive ((GtkWidget*) self->priv->page_move_right_menuitem, FALSE); +	} else { +		guint _tmp1_; +		guint index; +		guint _tmp2_; +		_tmp1_ = book_get_page_index (self->priv->book, page); +		index = _tmp1_; +		gtk_widget_set_sensitive ((GtkWidget*) self->priv->page_move_left_menuitem, index > ((guint) 0)); +		_tmp2_ = book_get_n_pages (self->priv->book); +		gtk_widget_set_sensitive ((GtkWidget*) self->priv->page_move_right_menuitem, index < (_tmp2_ - 1)); +	} +	_page_unref0 (page); +} + + +static void simple_scan_page_selected_cb (SimpleScan* self, BookView* view, Page* page) { +	gchar* name; +	gboolean _tmp0_; +	GObject* _tmp10_ = NULL; +	GtkRadioMenuItem* _tmp11_; +	GtkRadioMenuItem* menuitem; +	GObject* _tmp12_ = NULL; +	GtkToggleToolButton* _tmp13_; +	GtkToggleToolButton* toolbutton; +	gboolean _tmp14_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (view != NULL); +	if (page == NULL) { +		return; +	} +	self->priv->updating_page_menu = TRUE; +	simple_scan_update_page_menu (self); +	name = NULL; +	_tmp0_ = page_has_crop (page); +	if (_tmp0_) { +		gchar* _tmp1_ = NULL; +		gchar* crop_name; +		_tmp1_ = page_get_named_crop (page); +		crop_name = _tmp1_; +		if (crop_name != NULL) { +			if (g_strcmp0 (crop_name, "A4") == 0) { +				gchar* _tmp2_; +				_tmp2_ = g_strdup ("a4_menuitem"); +				_g_free0 (name); +				name = _tmp2_; +			} else { +				if (g_strcmp0 (crop_name, "A5") == 0) { +					gchar* _tmp3_; +					_tmp3_ = g_strdup ("a5_menuitem"); +					_g_free0 (name); +					name = _tmp3_; +				} else { +					if (g_strcmp0 (crop_name, "A6") == 0) { +						gchar* _tmp4_; +						_tmp4_ = g_strdup ("a6_menuitem"); +						_g_free0 (name); +						name = _tmp4_; +					} else { +						if (g_strcmp0 (crop_name, "letter") == 0) { +							gchar* _tmp5_; +							_tmp5_ = g_strdup ("letter_menuitem"); +							_g_free0 (name); +							name = _tmp5_; +						} else { +							if (g_strcmp0 (crop_name, "legal") == 0) { +								gchar* _tmp6_; +								_tmp6_ = g_strdup ("legal_menuitem"); +								_g_free0 (name); +								name = _tmp6_; +							} else { +								if (g_strcmp0 (crop_name, "4x6") == 0) { +									gchar* _tmp7_; +									_tmp7_ = g_strdup ("4x6_menuitem"); +									_g_free0 (name); +									name = _tmp7_; +								} +							} +						} +					} +				} +			} +		} else { +			gchar* _tmp8_; +			_tmp8_ = g_strdup ("custom_crop_menuitem"); +			_g_free0 (name); +			name = _tmp8_; +		} +		_g_free0 (crop_name); +	} else { +		gchar* _tmp9_; +		_tmp9_ = g_strdup ("no_crop_menuitem"); +		_g_free0 (name); +		name = _tmp9_; +	} +	_tmp10_ = gtk_builder_get_object (self->priv->builder, name); +	_tmp11_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp10_)); +	menuitem = _tmp11_; +	gtk_check_menu_item_set_active ((GtkCheckMenuItem*) menuitem, TRUE); +	_tmp12_ = gtk_builder_get_object (self->priv->builder, "crop_toolbutton"); +	_tmp13_ = _g_object_ref0 (GTK_TOGGLE_TOOL_BUTTON (_tmp12_)); +	toolbutton = _tmp13_; +	_tmp14_ = page_has_crop (page); +	gtk_toggle_tool_button_set_active (toolbutton, _tmp14_); +	self->priv->updating_page_menu = FALSE; +	_g_object_unref0 (toolbutton); +	_g_object_unref0 (menuitem); +	_g_free0 (name); +} + + +static gchar* simple_scan_get_temporary_filename (SimpleScan* self, const gchar* prefix, const gchar* extension) { +	gchar* result = NULL; +	gchar* _tmp0_ = NULL; +	gchar* filename; +	gchar* path = NULL; +	GError * _inner_error_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	g_return_val_if_fail (prefix != NULL, NULL); +	g_return_val_if_fail (extension != NULL, NULL); +	_tmp0_ = g_strdup_printf ("%sXXXXXX.%s", prefix, extension); +	filename = _tmp0_; +	{ +		gchar* _tmp1_ = NULL; +		gint _tmp2_; +		gint fd; +		_tmp2_ = g_file_open_tmp (filename, &_tmp1_, &_inner_error_); +		_g_free0 (path); +		path = _tmp1_; +		fd = _tmp2_; +		if (_inner_error_ != NULL) { +			goto __catch11_g_error; +		} +		close (fd); +	} +	goto __finally11; +	__catch11_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("ui.vala:788: Error saving email attachment: %s", e->message); +		result = NULL; +		_g_error_free0 (e); +		_g_free0 (path); +		_g_free0 (filename); +		return result; +	} +	__finally11: +	if (_inner_error_ != NULL) { +		_g_free0 (path); +		_g_free0 (filename); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return NULL; +	} +	result = path; +	_g_free0 (filename); +	return result; +} + + +static void simple_scan_show_page_cb (SimpleScan* self, BookView* view, Page* page) { +	gchar* _tmp0_ = NULL; +	gchar* path; +	GFile* _tmp1_ = NULL; +	GFile* file; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (view != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = simple_scan_get_temporary_filename (self, "scanned-page", "tiff"); +	path = _tmp0_; +	if (path == NULL) { +		_g_free0 (path); +		return; +	} +	_tmp1_ = g_file_new_for_path (path); +	file = _tmp1_; +	{ +		page_save (page, "tiff", file, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch12_g_error; +		} +	} +	goto __finally12; +	__catch12_g_error: +	{ +		GError* e = NULL; +		const gchar* _tmp2_ = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		_tmp2_ = _ ("Unable to save image for preview"); +		simple_scan_show_error_dialog (self, _tmp2_, e->message); +		_g_error_free0 (e); +		_g_object_unref0 (file); +		_g_free0 (path); +		return; +	} +	__finally12: +	if (_inner_error_ != NULL) { +		_g_object_unref0 (file); +		_g_free0 (path); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +	{ +		GdkScreen* _tmp3_ = NULL; +		gchar* _tmp4_ = NULL; +		gchar* _tmp5_; +		guint32 _tmp6_; +		_tmp3_ = gtk_window_get_screen (self->priv->window); +		_tmp4_ = g_file_get_uri (file); +		_tmp5_ = _tmp4_; +		_tmp6_ = gtk_get_current_event_time (); +		gtk_show_uri (_tmp3_, _tmp5_, _tmp6_, &_inner_error_); +		_g_free0 (_tmp5_); +		if (_inner_error_ != NULL) { +			goto __catch13_g_error; +		} +	} +	goto __finally13; +	__catch13_g_error: +	{ +		GError* e = NULL; +		const gchar* _tmp7_ = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		_tmp7_ = _ ("Unable to open image preview application"); +		simple_scan_show_error_dialog (self, _tmp7_, e->message); +		_g_error_free0 (e); +	} +	__finally13: +	if (_inner_error_ != NULL) { +		_g_object_unref0 (file); +		_g_free0 (path); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +	_g_object_unref0 (file); +	_g_free0 (path); +} + + +static void simple_scan_show_page_menu_cb (SimpleScan* self, BookView* view) { +	GObject* _tmp0_ = NULL; +	GtkMenu* _tmp1_; +	GtkMenu* menu; +	guint32 _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (view != NULL); +	_tmp0_ = gtk_builder_get_object (self->priv->builder, "page_menu"); +	_tmp1_ = _g_object_ref0 (GTK_MENU (_tmp0_)); +	menu = _tmp1_; +	_tmp2_ = gtk_get_current_event_time (); +	gtk_menu_popup (menu, NULL, NULL, NULL, NULL, (guint) 3, _tmp2_); +	_g_object_unref0 (menu); +} + + +void G_MODULE_EXPORT rotate_left_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	if (self->priv->updating_page_menu) { +		return; +	} +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	if (page != NULL) { +		page_rotate_left (page); +	} +	_page_unref0 (page); +} + + +void G_MODULE_EXPORT rotate_right_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	if (self->priv->updating_page_menu) { +		return; +	} +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	if (page != NULL) { +		page_rotate_right (page); +	} +	_page_unref0 (page); +} + + +static void simple_scan_set_crop (SimpleScan* self, const gchar* crop_name) { +	Page* _tmp0_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->crop_rotate_menuitem, crop_name != NULL); +	if (self->priv->updating_page_menu) { +		return; +	} +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	if (page == NULL) { +		_page_unref0 (page); +		return; +	} +	if (crop_name == NULL) { +		page_set_no_crop (page); +		_page_unref0 (page); +		return; +	} else { +		if (g_strcmp0 (crop_name, "custom") == 0) { +			gint _tmp1_; +			gint width; +			gint _tmp2_; +			gint height; +			gint crop_width; +			gint crop_height; +			_tmp1_ = page_get_width (page); +			width = _tmp1_; +			_tmp2_ = page_get_height (page); +			height = _tmp2_; +			crop_width = (gint) ((width * 0.8) + 0.5); +			crop_height = (gint) ((height * 0.8) + 0.5); +			page_set_custom_crop (page, crop_width, crop_height); +			page_move_crop (page, (width - crop_width) / 2, (height - crop_height) / 2); +		} else { +			page_set_named_crop (page, crop_name); +		} +	} +	_page_unref0 (page); +} + + +void G_MODULE_EXPORT no_crop_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, NULL); +	} +} + + +void G_MODULE_EXPORT custom_crop_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "custom"); +	} +} + + +void G_MODULE_EXPORT crop_toolbutton_toggled_cb (GtkToggleToolButton* widget, SimpleScan* self) { +	GtkRadioMenuItem* menuitem = NULL; +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	if (self->priv->updating_page_menu) { +		return; +	} +	_tmp0_ = gtk_toggle_tool_button_get_active (widget); +	if (_tmp0_) { +		GObject* _tmp1_ = NULL; +		GtkRadioMenuItem* _tmp2_; +		_tmp1_ = gtk_builder_get_object (self->priv->builder, "custom_crop_menuitem"); +		_tmp2_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp1_)); +		_g_object_unref0 (menuitem); +		menuitem = _tmp2_; +	} else { +		GObject* _tmp3_ = NULL; +		GtkRadioMenuItem* _tmp4_; +		_tmp3_ = gtk_builder_get_object (self->priv->builder, "no_crop_menuitem"); +		_tmp4_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp3_)); +		_g_object_unref0 (menuitem); +		menuitem = _tmp4_; +	} +	gtk_check_menu_item_set_active ((GtkCheckMenuItem*) menuitem, TRUE); +	_g_object_unref0 (menuitem); +} + + +void G_MODULE_EXPORT four_by_six_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "4x6"); +	} +} + + +void G_MODULE_EXPORT legal_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "legal"); +	} +} + + +void G_MODULE_EXPORT letter_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "letter"); +	} +} + + +void G_MODULE_EXPORT a6_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "A6"); +	} +} + + +void G_MODULE_EXPORT a5_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "A5"); +	} +} + + +void G_MODULE_EXPORT a4_menuitem_toggled_cb (GtkCheckMenuItem* widget, SimpleScan* self) { +	gboolean _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_check_menu_item_get_active (widget); +	if (_tmp0_) { +		simple_scan_set_crop (self, "A4"); +	} +} + + +void G_MODULE_EXPORT crop_rotate_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	if (page == NULL) { +		_page_unref0 (page); +		return; +	} +	page_rotate_crop (page); +	_page_unref0 (page); +} + + +void G_MODULE_EXPORT page_move_left_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	guint _tmp1_; +	guint index; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	_tmp1_ = book_get_page_index (self->priv->book, page); +	index = _tmp1_; +	if (index > ((guint) 0)) { +		book_move_page (self->priv->book, page, index - 1); +	} +	simple_scan_update_page_menu (self); +	_page_unref0 (page); +} + + +void G_MODULE_EXPORT page_move_right_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	Page* _tmp0_ = NULL; +	Page* page; +	guint _tmp1_; +	guint index; +	guint _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	page = _tmp0_; +	_tmp1_ = book_get_page_index (self->priv->book, page); +	index = _tmp1_; +	_tmp2_ = book_get_n_pages (self->priv->book); +	if (index < (_tmp2_ - 1)) { +		guint _tmp3_; +		_tmp3_ = book_get_page_index (self->priv->book, page); +		book_move_page (self->priv->book, page, _tmp3_ + 1); +	} +	simple_scan_update_page_menu (self); +	_page_unref0 (page); +} + + +void G_MODULE_EXPORT page_delete_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	Book* _tmp0_ = NULL; +	Book* _tmp1_; +	Page* _tmp2_ = NULL; +	Page* _tmp3_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = book_view_get_book (self->priv->book_view); +	_tmp1_ = _tmp0_; +	_tmp2_ = book_view_get_selected (self->priv->book_view); +	_tmp3_ = _tmp2_; +	book_delete_page (_tmp1_, _tmp3_); +	_page_unref0 (_tmp3_); +	_book_unref0 (_tmp1_); +} + + +void G_MODULE_EXPORT save_file_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	simple_scan_save_document (self, FALSE); +} + + +void G_MODULE_EXPORT save_as_file_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	simple_scan_save_document (self, TRUE); +} + + +static gpointer _cairo_reference0 (gpointer self) { +	return self ? cairo_reference (self) : NULL; +} + + +static void simple_scan_draw_page (SimpleScan* self, GtkPrintOperation* operation, GtkPrintContext* print_context, gint page_number) { +	cairo_t* _tmp0_ = NULL; +	cairo_t* _tmp1_; +	cairo_t* context; +	Page* _tmp2_ = NULL; +	Page* page; +	gboolean is_landscape; +	gdouble _tmp3_; +	gdouble _tmp4_; +	gboolean _tmp5_; +	gdouble _tmp7_; +	gint _tmp8_; +	gdouble _tmp9_; +	gint _tmp10_; +	GdkPixbuf* _tmp11_ = NULL; +	GdkPixbuf* image; +	g_return_if_fail (self != NULL); +	g_return_if_fail (operation != NULL); +	g_return_if_fail (print_context != NULL); +	_tmp0_ = gtk_print_context_get_cairo_context (print_context); +	_tmp1_ = _cairo_reference0 (_tmp0_); +	context = _tmp1_; +	_tmp2_ = book_get_page (self->priv->book, page_number); +	page = _tmp2_; +	is_landscape = FALSE; +	_tmp3_ = gtk_print_context_get_width (print_context); +	_tmp4_ = gtk_print_context_get_height (print_context); +	if (_tmp3_ > _tmp4_) { +		is_landscape = TRUE; +	} +	_tmp5_ = page_is_landscape (page); +	if (_tmp5_ != is_landscape) { +		gdouble _tmp6_; +		_tmp6_ = gtk_print_context_get_width (print_context); +		cairo_translate (context, _tmp6_, (gdouble) 0); +		cairo_rotate (context, G_PI_2); +	} +	_tmp7_ = gtk_print_context_get_dpi_x (print_context); +	_tmp8_ = page_get_dpi (page); +	_tmp9_ = gtk_print_context_get_dpi_y (print_context); +	_tmp10_ = page_get_dpi (page); +	cairo_scale (context, _tmp7_ / _tmp8_, _tmp9_ / _tmp10_); +	_tmp11_ = page_get_image (page, TRUE); +	image = _tmp11_; +	gdk_cairo_set_source_pixbuf (context, image, (gdouble) 0, (gdouble) 0); +	cairo_paint (context); +	_g_object_unref0 (image); +	_page_unref0 (page); +	_cairo_destroy0 (context); +} + + +void G_MODULE_EXPORT email_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	g_signal_emit_by_name (self, "email", self->priv->document_hint); +} + + +static void _simple_scan_draw_page_gtk_print_operation_draw_page (GtkPrintOperation* _sender, GtkPrintContext* context, gint page_nr, gpointer self) { +	simple_scan_draw_page (self, _sender, context, page_nr); +} + + +void G_MODULE_EXPORT print_button_clicked_cb (GtkWidget* widget, SimpleScan* self) { +	GtkPrintOperation* _tmp0_ = NULL; +	GtkPrintOperation* print; +	guint _tmp1_; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = gtk_print_operation_new (); +	print = _tmp0_; +	_tmp1_ = book_get_n_pages (self->priv->book); +	gtk_print_operation_set_n_pages (print, (gint) _tmp1_); +	g_signal_connect (print, "draw-page", (GCallback) _simple_scan_draw_page_gtk_print_operation_draw_page, self); +	{ +		gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, self->priv->window, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch14_g_error; +		} +	} +	goto __finally14; +	__catch14_g_error: +	{ +		GError* e = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_warning ("ui.vala:1044: Error printing: %s", e->message); +		_g_error_free0 (e); +	} +	__finally14: +	if (_inner_error_ != NULL) { +		_g_object_unref0 (print); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +	_g_object_unref0 (print); +} + + +void G_MODULE_EXPORT help_contents_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	{ +		GdkScreen* _tmp0_ = NULL; +		guint32 _tmp1_; +		_tmp0_ = gtk_window_get_screen (self->priv->window); +		_tmp1_ = gtk_get_current_event_time (); +		gtk_show_uri (_tmp0_, "ghelp:simple-scan", _tmp1_, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch15_g_error; +		} +	} +	goto __finally15; +	__catch15_g_error: +	{ +		GError* e = NULL; +		const gchar* _tmp2_ = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		_tmp2_ = _ ("Unable to open help file"); +		simple_scan_show_error_dialog (self, _tmp2_, e->message); +		_g_error_free0 (e); +	} +	__finally15: +	if (_inner_error_ != NULL) { +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +} + + +void G_MODULE_EXPORT about_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	gchar* _tmp0_; +	gchar** _tmp1_ = NULL; +	gchar** authors; +	gint authors_length1; +	gint _authors_size_; +	const gchar* _tmp2_ = NULL; +	gchar* _tmp3_; +	gchar* license; +	const gchar* _tmp4_ = NULL; +	gchar* _tmp5_; +	gchar* title; +	const gchar* _tmp6_ = NULL; +	gchar* _tmp7_; +	gchar* description; +	const gchar* _tmp8_ = NULL; +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	_tmp0_ = g_strdup ("Robert Ancell <robert.ancell@canonical.com>"); +	_tmp1_ = g_new0 (gchar*, 1 + 1); +	_tmp1_[0] = _tmp0_; +	authors = _tmp1_; +	authors_length1 = 1; +	_authors_size_ = authors_length1; +	_tmp2_ = _ ("This program is free software: you can redistribute it and/or modify\n" \ +"it under the terms of the GNU General Public License as published by\n" \ +"the Free Software Foundation, either version 3 of the License, or\n" \ +"(at your option) any later version.\n" \ +"\n" \ +"This program is distributed in the hope that it will be useful,\n" \ +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \ +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" \ +"GNU General Public License for more details.\n" \ +"\n" \ +"You should have received a copy of the GNU General Public License\n" \ +"along with this program.  If not, see <http://www.gnu.org/licenses/>."); +	_tmp3_ = g_strdup (_tmp2_); +	license = _tmp3_; +	_tmp4_ = _ ("About Simple Scan"); +	_tmp5_ = g_strdup (_tmp4_); +	title = _tmp5_; +	_tmp6_ = _ ("Simple document scanning tool"); +	_tmp7_ = g_strdup (_tmp6_); +	description = _tmp7_; +	_tmp8_ = _ ("translator-credits"); +	gtk_show_about_dialog (self->priv->window, "title", title, "program-name", "Simple Scan", "version", VERSION, "comments", description, "logo-icon-name", "scanner", "authors", authors, "translator-credits", _tmp8_, "website", "https://launchpad.net/simple-scan", "copyright", "Copyright © 2009-2011 Canonical Ltd.", "license", license, "wrap-license", TRUE, NULL, NULL); +	_g_free0 (description); +	_g_free0 (title); +	_g_free0 (license); +	authors = (_vala_array_free (authors, authors_length1, (GDestroyNotify) g_free), NULL); +} + + +static gboolean simple_scan_on_quit (SimpleScan* self) { +	gboolean result = FALSE; +	const gchar* _tmp0_ = NULL; +	const gchar* _tmp1_ = NULL; +	gboolean _tmp2_; +	gchar* _tmp3_ = NULL; +	gchar* device; +	gint paper_width; +	gint paper_height; +	gint _tmp4_; +	gint _tmp5_; +	gint _tmp6_; +	gint _tmp7_; +	ScanType _tmp8_; +	g_return_val_if_fail (self != NULL, FALSE); +	_tmp0_ = _ ("Save document before quitting?"); +	_tmp1_ = _ ("Quit without Saving"); +	_tmp2_ = simple_scan_prompt_to_save (self, _tmp0_, _tmp1_); +	if (!_tmp2_) { +		result = FALSE; +		return result; +	} +	_tmp3_ = simple_scan_get_selected_device (self); +	device = _tmp3_; +	paper_width = 0; +	paper_height = 0; +	simple_scan_get_paper_size (self, &_tmp4_, &_tmp5_); +	paper_width = _tmp4_; +	paper_height = _tmp5_; +	if (device != NULL) { +		g_settings_set_string (self->priv->settings, "selected-device", device); +	} +	g_settings_set_string (self->priv->settings, "document-type", self->priv->document_hint); +	_tmp6_ = simple_scan_get_text_dpi (self); +	g_settings_set_int (self->priv->settings, "text-dpi", _tmp6_); +	_tmp7_ = simple_scan_get_photo_dpi (self); +	g_settings_set_int (self->priv->settings, "photo-dpi", _tmp7_); +	_tmp8_ = simple_scan_get_page_side (self); +	g_settings_set_enum (self->priv->settings, "page-side", (gint) _tmp8_); +	g_settings_set_int (self->priv->settings, "paper-width", paper_width); +	g_settings_set_int (self->priv->settings, "paper-height", paper_height); +	g_settings_set_int (self->priv->settings, "window-width", self->priv->window_width); +	g_settings_set_int (self->priv->settings, "window-height", self->priv->window_height); +	g_settings_set_boolean (self->priv->settings, "window-is-maximized", self->priv->window_is_maximized); +	g_settings_set_enum (self->priv->settings, "scan-direction", (gint) self->priv->default_page_scan_direction); +	g_settings_set_int (self->priv->settings, "page-width", self->priv->default_page_width); +	g_settings_set_int (self->priv->settings, "page-height", self->priv->default_page_height); +	g_settings_set_int (self->priv->settings, "page-dpi", self->priv->default_page_dpi); +	g_signal_emit_by_name (self, "quit"); +	result = TRUE; +	_g_free0 (device); +	return result; +} + + +void G_MODULE_EXPORT quit_menuitem_activate_cb (GtkWidget* widget, SimpleScan* self) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	simple_scan_on_quit (self); +} + + +gboolean G_MODULE_EXPORT simple_scan_window_configure_event_cb (GtkWidget* widget, GdkEventConfigure* event, SimpleScan* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	if (!self->priv->window_is_maximized) { +		self->priv->window_width = (*event).width; +		self->priv->window_height = (*event).height; +	} +	result = FALSE; +	return result; +} + + +static void simple_scan_info_bar_response_cb (SimpleScan* self, GtkInfoBar* widget, gint response_id) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (widget != NULL); +	if (response_id == 1) { +		gtk_widget_grab_focus ((GtkWidget*) self->priv->device_combo); +		gtk_window_present ((GtkWindow*) self->priv->preferences_dialog); +	} else { +		self->priv->have_error = FALSE; +		_g_free0 (self->priv->error_title); +		self->priv->error_title = NULL; +		_g_free0 (self->priv->error_text); +		self->priv->error_text = NULL; +		simple_scan_update_info_bar (self); +	} +} + + +gboolean G_MODULE_EXPORT simple_scan_window_window_state_event_cb (GtkWidget* widget, GdkEventWindowState* event, SimpleScan* self) { +	gboolean result = FALSE; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	if (((*event).changed_mask & GDK_WINDOW_STATE_MAXIMIZED) != 0) { +		self->priv->window_is_maximized = ((*event).new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0; +	} +	result = FALSE; +	return result; +} + + +gboolean G_MODULE_EXPORT window_delete_event_cb (GtkWidget* widget, GdkEvent* event, SimpleScan* self) { +	gboolean result = FALSE; +	gboolean _tmp0_; +	g_return_val_if_fail (self != NULL, FALSE); +	g_return_val_if_fail (widget != NULL, FALSE); +	g_return_val_if_fail (event != NULL, FALSE); +	_tmp0_ = simple_scan_on_quit (self); +	result = !_tmp0_; +	return result; +} + + +static void simple_scan_page_size_changed_cb (SimpleScan* self, Page* page) { +	gint _tmp0_; +	gint _tmp1_; +	gint _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = page_get_width (page); +	self->priv->default_page_width = _tmp0_; +	_tmp1_ = page_get_height (page); +	self->priv->default_page_height = _tmp1_; +	_tmp2_ = page_get_dpi (page); +	self->priv->default_page_dpi = _tmp2_; +} + + +static void simple_scan_page_scan_direction_changed_cb (SimpleScan* self, Page* page) { +	ScanDirection _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = page_get_scan_direction (page); +	self->priv->default_page_scan_direction = _tmp0_; +} + + +static void _simple_scan_page_size_changed_cb_page_size_changed (Page* _sender, gpointer self) { +	simple_scan_page_size_changed_cb (self, _sender); +} + + +static void _simple_scan_page_scan_direction_changed_cb_page_scan_direction_changed (Page* _sender, gpointer self) { +	simple_scan_page_scan_direction_changed_cb (self, _sender); +} + + +static void simple_scan_page_added_cb (SimpleScan* self, Book* book, Page* page) { +	gint _tmp0_; +	gint _tmp1_; +	gint _tmp2_; +	ScanDirection _tmp3_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = page_get_width (page); +	self->priv->default_page_width = _tmp0_; +	_tmp1_ = page_get_height (page); +	self->priv->default_page_height = _tmp1_; +	_tmp2_ = page_get_dpi (page); +	self->priv->default_page_dpi = _tmp2_; +	_tmp3_ = page_get_scan_direction (page); +	self->priv->default_page_scan_direction = _tmp3_; +	g_signal_connect (page, "size-changed", (GCallback) _simple_scan_page_size_changed_cb_page_size_changed, self); +	g_signal_connect (page, "scan-direction-changed", (GCallback) _simple_scan_page_scan_direction_changed_cb_page_scan_direction_changed, self); +	simple_scan_update_page_menu (self); +} + + +static void simple_scan_page_removed_cb (SimpleScan* self, Book* book, Page* page) { +	guint _tmp0_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	g_return_if_fail (page != NULL); +	_tmp0_ = book_get_n_pages (book); +	if (_tmp0_ == ((guint) 1)) { +		simple_scan_add_default_page (self); +	} +	simple_scan_update_page_menu (self); +} + + +static void simple_scan_set_dpi_combo (SimpleScan* self, GtkComboBox* combo, gint default_dpi, gint current_dpi) { +	GtkCellRendererText* _tmp0_ = NULL; +	GtkCellRendererText* renderer; +	GtkTreeModel* _tmp1_ = NULL; +	GtkListStore* _tmp2_; +	GtkListStore* model; +	gint* _tmp3_ = NULL; +	gint* scan_resolutions; +	gint scan_resolutions_length1; +	gint _scan_resolutions_size_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (combo != NULL); +	_tmp0_ = (GtkCellRendererText*) gtk_cell_renderer_text_new (); +	renderer = g_object_ref_sink (_tmp0_); +	gtk_cell_layout_pack_start ((GtkCellLayout*) combo, (GtkCellRenderer*) renderer, TRUE); +	gtk_cell_layout_add_attribute ((GtkCellLayout*) combo, (GtkCellRenderer*) renderer, "text", 1); +	_tmp1_ = gtk_combo_box_get_model (combo); +	_tmp2_ = _g_object_ref0 (GTK_LIST_STORE (_tmp1_)); +	model = _tmp2_; +	_tmp3_ = g_new0 (gint, 6); +	_tmp3_[0] = 75; +	_tmp3_[1] = 150; +	_tmp3_[2] = 300; +	_tmp3_[3] = 600; +	_tmp3_[4] = 1200; +	_tmp3_[5] = 2400; +	scan_resolutions = _tmp3_; +	scan_resolutions_length1 = 6; +	_scan_resolutions_size_ = scan_resolutions_length1; +	{ +		gint* dpi_collection = NULL; +		gint dpi_collection_length1 = 0; +		gint _dpi_collection_size_ = 0; +		gint dpi_it; +		dpi_collection = scan_resolutions; +		dpi_collection_length1 = scan_resolutions_length1; +		for (dpi_it = 0; dpi_it < scan_resolutions_length1; dpi_it = dpi_it + 1) { +			gint dpi = 0; +			dpi = dpi_collection[dpi_it]; +			{ +				gchar* label = NULL; +				GtkTreeIter iter = {0}; +				GtkTreeIter _tmp12_ = {0}; +				if (dpi == default_dpi) { +					const gchar* _tmp4_ = NULL; +					gchar* _tmp5_ = NULL; +					_tmp4_ = _ ("%d dpi (default)"); +					_tmp5_ = g_strdup_printf (_tmp4_, dpi); +					_g_free0 (label); +					label = _tmp5_; +				} else { +					if (dpi == 75) { +						const gchar* _tmp6_ = NULL; +						gchar* _tmp7_ = NULL; +						_tmp6_ = _ ("%d dpi (draft)"); +						_tmp7_ = g_strdup_printf (_tmp6_, dpi); +						_g_free0 (label); +						label = _tmp7_; +					} else { +						if (dpi == 1200) { +							const gchar* _tmp8_ = NULL; +							gchar* _tmp9_ = NULL; +							_tmp8_ = _ ("%d dpi (high resolution)"); +							_tmp9_ = g_strdup_printf (_tmp8_, dpi); +							_g_free0 (label); +							label = _tmp9_; +						} else { +							const gchar* _tmp10_ = NULL; +							gchar* _tmp11_ = NULL; +							_tmp10_ = _ ("%d dpi"); +							_tmp11_ = g_strdup_printf (_tmp10_, dpi); +							_g_free0 (label); +							label = _tmp11_; +						} +					} +				} +				gtk_list_store_append (model, &_tmp12_); +				iter = _tmp12_; +				gtk_list_store_set (model, &iter, 0, dpi, 1, label, -1, -1); +				if (dpi == current_dpi) { +					gtk_combo_box_set_active_iter (combo, &iter); +				} +				_g_free0 (label); +			} +		} +	} +	scan_resolutions = (g_free (scan_resolutions), NULL); +	_g_object_unref0 (model); +	_g_object_unref0 (renderer); +} + + +static void simple_scan_needs_saving_cb (SimpleScan* self, Book* book) { +	gboolean _tmp0_; +	gboolean _tmp1_; +	gboolean _tmp2_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (book != NULL); +	_tmp0_ = book_get_needs_saving (book); +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->save_menuitem, _tmp0_); +	_tmp1_ = book_get_needs_saving (book); +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->save_toolbutton, _tmp1_); +	_tmp2_ = book_get_needs_saving (book); +	if (_tmp2_) { +		gtk_widget_set_sensitive ((GtkWidget*) self->priv->save_as_menuitem, TRUE); +	} +} + + +static void _simple_scan_info_bar_response_cb_gtk_info_bar_response (GtkInfoBar* _sender, gint response_id, gpointer self) { +	simple_scan_info_bar_response_cb (self, _sender, response_id); +} + + +static void _simple_scan_page_selected_cb_book_view_page_selected (BookView* _sender, Page* page, gpointer self) { +	simple_scan_page_selected_cb (self, _sender, page); +} + + +static void _simple_scan_show_page_cb_book_view_show_page (BookView* _sender, Page* page, gpointer self) { +	simple_scan_show_page_cb (self, _sender, page); +} + + +static void _simple_scan_show_page_menu_cb_book_view_show_menu (BookView* _sender, gpointer self) { +	simple_scan_show_page_menu_cb (self, _sender); +} + + +static void _simple_scan_needs_saving_cb_book_needs_saving_changed (Book* _sender, gpointer self) { +	simple_scan_needs_saving_cb (self, _sender); +} + + +static void simple_scan_load (SimpleScan* self) { +	GtkIconTheme* _tmp0_ = NULL; +	GtkBuilder* _tmp1_ = NULL; +	gchar* _tmp2_ = NULL; +	gchar* filename; +	GObject* _tmp5_ = NULL; +	GtkWindow* _tmp6_; +	GObject* _tmp7_ = NULL; +	GtkVBox* _tmp8_; +	GObject* _tmp9_ = NULL; +	GtkMenuItem* _tmp10_; +	GObject* _tmp11_ = NULL; +	GtkMenuItem* _tmp12_; +	GObject* _tmp13_ = NULL; +	GtkMenuItem* _tmp14_; +	GObject* _tmp15_ = NULL; +	GtkMenuItem* _tmp16_; +	GObject* _tmp17_ = NULL; +	GtkMenuItem* _tmp18_; +	GObject* _tmp19_ = NULL; +	GtkMenuItem* _tmp20_; +	GObject* _tmp21_ = NULL; +	GtkToolButton* _tmp22_; +	GObject* _tmp23_ = NULL; +	GtkMenuItem* _tmp24_; +	GObject* _tmp25_ = NULL; +	GtkToolButton* _tmp26_; +	GObject* _tmp27_ = NULL; +	GtkRadioMenuItem* _tmp28_; +	GObject* _tmp29_ = NULL; +	GtkRadioMenuItem* _tmp30_; +	GObject* _tmp31_ = NULL; +	GtkRadioMenuItem* _tmp32_; +	GObject* _tmp33_ = NULL; +	GtkRadioMenuItem* _tmp34_; +	GObject* _tmp35_ = NULL; +	GtkDialog* _tmp36_; +	GObject* _tmp37_ = NULL; +	GtkLabel* _tmp38_; +	GObject* _tmp39_ = NULL; +	GtkEntry* _tmp40_; +	GObject* _tmp41_ = NULL; +	GtkEntry* _tmp42_; +	GObject* _tmp43_ = NULL; +	GtkDialog* _tmp44_; +	GObject* _tmp45_ = NULL; +	GtkComboBox* _tmp46_; +	GtkTreeModel* _tmp47_ = NULL; +	GtkListStore* _tmp48_; +	GObject* _tmp49_ = NULL; +	GtkComboBox* _tmp50_; +	GtkTreeModel* _tmp51_ = NULL; +	GtkListStore* _tmp52_; +	GObject* _tmp53_ = NULL; +	GtkComboBox* _tmp54_; +	GtkTreeModel* _tmp55_ = NULL; +	GtkListStore* _tmp56_; +	GObject* _tmp57_ = NULL; +	GtkComboBox* _tmp58_; +	GtkTreeModel* _tmp59_ = NULL; +	GtkListStore* _tmp60_; +	GObject* _tmp61_ = NULL; +	GtkComboBox* _tmp62_; +	GtkTreeModel* _tmp63_ = NULL; +	GtkListStore* _tmp64_; +	GtkInfoBar* _tmp65_ = NULL; +	GtkHBox* _tmp66_ = NULL; +	GtkHBox* hbox; +	GtkWidget* _tmp67_ = NULL; +	GtkContainer* _tmp68_; +	GtkContainer* content_area; +	GtkImage* _tmp69_ = NULL; +	GtkLabel* _tmp70_ = NULL; +	GtkWidget* _tmp71_ = NULL; +	GtkButton* _tmp72_; +	const gchar* _tmp73_ = NULL; +	GtkWidget* _tmp74_ = NULL; +	GtkButton* _tmp75_; +	GtkTreeIter iter = {0}; +	GtkTreeIter _tmp76_ = {0}; +	const gchar* _tmp77_ = NULL; +	GtkTreeIter _tmp78_ = {0}; +	GtkTreeIter _tmp79_ = {0}; +	GtkTreeIter _tmp80_ = {0}; +	GtkTreeIter _tmp81_ = {0}; +	GtkTreeIter _tmp82_ = {0}; +	GtkTreeIter _tmp83_ = {0}; +	gint _tmp84_; +	gint dpi; +	gint _tmp85_; +	GtkCellRendererText* _tmp86_ = NULL; +	GtkCellRendererText* renderer; +	GtkCellRendererText* _tmp87_ = NULL; +	gint _tmp88_; +	GtkCellRendererText* _tmp89_ = NULL; +	gint _tmp90_; +	gint paper_width; +	gint _tmp91_; +	gint paper_height; +	gchar* _tmp92_ = NULL; +	gchar* device; +	gchar* _tmp95_ = NULL; +	gchar* document_type; +	BookView* _tmp96_ = NULL; +	gint _tmp97_; +	gint _tmp98_; +	gint _tmp99_; +	gint _tmp100_; +	gint _tmp101_; +	gint _tmp102_; +	gboolean _tmp103_; +	guint _tmp104_; +	GError * _inner_error_ = NULL; +	g_return_if_fail (self != NULL); +	_tmp0_ = gtk_icon_theme_get_default (); +	gtk_icon_theme_append_search_path (_tmp0_, ICON_DIR); +	gtk_window_set_default_icon_name ("scanner"); +	_tmp1_ = gtk_builder_new (); +	_g_object_unref0 (self->priv->builder); +	self->priv->builder = _tmp1_; +	_tmp2_ = g_build_filename (UI_DIR, "simple-scan.ui", NULL, NULL); +	filename = _tmp2_; +	{ +		gtk_builder_add_from_file (self->priv->builder, filename, &_inner_error_); +		if (_inner_error_ != NULL) { +			goto __catch16_g_error; +		} +	} +	goto __finally16; +	__catch16_g_error: +	{ +		GError* e = NULL; +		const gchar* _tmp3_ = NULL; +		const gchar* _tmp4_ = NULL; +		e = _inner_error_; +		_inner_error_ = NULL; +		g_critical ("ui.vala:1261: Unable to load UI %s: %s\n", filename, e->message); +		_tmp3_ = _ ("Files missing"); +		_tmp4_ = _ ("Please check your installation"); +		simple_scan_show_error_dialog (self, _tmp3_, _tmp4_); +		exit (EXIT_FAILURE); +		_g_error_free0 (e); +	} +	__finally16: +	if (_inner_error_ != NULL) { +		_g_free0 (filename); +		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); +		g_clear_error (&_inner_error_); +		return; +	} +	gtk_builder_connect_signals (self->priv->builder, self); +	_tmp5_ = gtk_builder_get_object (self->priv->builder, "simple_scan_window"); +	_tmp6_ = _g_object_ref0 (GTK_WINDOW (_tmp5_)); +	_g_object_unref0 (self->priv->window); +	self->priv->window = _tmp6_; +	_tmp7_ = gtk_builder_get_object (self->priv->builder, "main_vbox"); +	_tmp8_ = _g_object_ref0 (GTK_VBOX (_tmp7_)); +	_g_object_unref0 (self->priv->main_vbox); +	self->priv->main_vbox = _tmp8_; +	_tmp9_ = gtk_builder_get_object (self->priv->builder, "page_move_left_menuitem"); +	_tmp10_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp9_)); +	_g_object_unref0 (self->priv->page_move_left_menuitem); +	self->priv->page_move_left_menuitem = _tmp10_; +	_tmp11_ = gtk_builder_get_object (self->priv->builder, "page_move_right_menuitem"); +	_tmp12_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp11_)); +	_g_object_unref0 (self->priv->page_move_right_menuitem); +	self->priv->page_move_right_menuitem = _tmp12_; +	_tmp13_ = gtk_builder_get_object (self->priv->builder, "page_delete_menuitem"); +	_tmp14_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp13_)); +	_g_object_unref0 (self->priv->page_delete_menuitem); +	self->priv->page_delete_menuitem = _tmp14_; +	_tmp15_ = gtk_builder_get_object (self->priv->builder, "crop_rotate_menuitem"); +	_tmp16_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp15_)); +	_g_object_unref0 (self->priv->crop_rotate_menuitem); +	self->priv->crop_rotate_menuitem = _tmp16_; +	_tmp17_ = gtk_builder_get_object (self->priv->builder, "save_menuitem"); +	_tmp18_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp17_)); +	_g_object_unref0 (self->priv->save_menuitem); +	self->priv->save_menuitem = _tmp18_; +	_tmp19_ = gtk_builder_get_object (self->priv->builder, "save_as_menuitem"); +	_tmp20_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp19_)); +	_g_object_unref0 (self->priv->save_as_menuitem); +	self->priv->save_as_menuitem = _tmp20_; +	_tmp21_ = gtk_builder_get_object (self->priv->builder, "save_toolbutton"); +	_tmp22_ = _g_object_ref0 (GTK_TOOL_BUTTON (_tmp21_)); +	_g_object_unref0 (self->priv->save_toolbutton); +	self->priv->save_toolbutton = _tmp22_; +	_tmp23_ = gtk_builder_get_object (self->priv->builder, "stop_scan_menuitem"); +	_tmp24_ = _g_object_ref0 (GTK_MENU_ITEM (_tmp23_)); +	_g_object_unref0 (self->priv->stop_menuitem); +	self->priv->stop_menuitem = _tmp24_; +	_tmp25_ = gtk_builder_get_object (self->priv->builder, "stop_toolbutton"); +	_tmp26_ = _g_object_ref0 (GTK_TOOL_BUTTON (_tmp25_)); +	_g_object_unref0 (self->priv->stop_toolbutton); +	self->priv->stop_toolbutton = _tmp26_; +	_tmp27_ = gtk_builder_get_object (self->priv->builder, "text_toolbutton_menuitem"); +	_tmp28_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp27_)); +	_g_object_unref0 (self->priv->text_toolbar_menuitem); +	self->priv->text_toolbar_menuitem = _tmp28_; +	_tmp29_ = gtk_builder_get_object (self->priv->builder, "text_menuitem"); +	_tmp30_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp29_)); +	_g_object_unref0 (self->priv->text_menu_menuitem); +	self->priv->text_menu_menuitem = _tmp30_; +	_tmp31_ = gtk_builder_get_object (self->priv->builder, "photo_toolbutton_menuitem"); +	_tmp32_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp31_)); +	_g_object_unref0 (self->priv->photo_toolbar_menuitem); +	self->priv->photo_toolbar_menuitem = _tmp32_; +	_tmp33_ = gtk_builder_get_object (self->priv->builder, "photo_menuitem"); +	_tmp34_ = _g_object_ref0 (GTK_RADIO_MENU_ITEM (_tmp33_)); +	_g_object_unref0 (self->priv->photo_menu_menuitem); +	self->priv->photo_menu_menuitem = _tmp34_; +	_tmp35_ = gtk_builder_get_object (self->priv->builder, "authorize_dialog"); +	_tmp36_ = _g_object_ref0 (GTK_DIALOG (_tmp35_)); +	_g_object_unref0 (self->priv->authorize_dialog); +	self->priv->authorize_dialog = _tmp36_; +	_tmp37_ = gtk_builder_get_object (self->priv->builder, "authorize_label"); +	_tmp38_ = _g_object_ref0 (GTK_LABEL (_tmp37_)); +	_g_object_unref0 (self->priv->authorize_label); +	self->priv->authorize_label = _tmp38_; +	_tmp39_ = gtk_builder_get_object (self->priv->builder, "username_entry"); +	_tmp40_ = _g_object_ref0 (GTK_ENTRY (_tmp39_)); +	_g_object_unref0 (self->priv->username_entry); +	self->priv->username_entry = _tmp40_; +	_tmp41_ = gtk_builder_get_object (self->priv->builder, "password_entry"); +	_tmp42_ = _g_object_ref0 (GTK_ENTRY (_tmp41_)); +	_g_object_unref0 (self->priv->password_entry); +	self->priv->password_entry = _tmp42_; +	_tmp43_ = gtk_builder_get_object (self->priv->builder, "preferences_dialog"); +	_tmp44_ = _g_object_ref0 (GTK_DIALOG (_tmp43_)); +	_g_object_unref0 (self->priv->preferences_dialog); +	self->priv->preferences_dialog = _tmp44_; +	_tmp45_ = gtk_builder_get_object (self->priv->builder, "device_combo"); +	_tmp46_ = _g_object_ref0 (GTK_COMBO_BOX (_tmp45_)); +	_g_object_unref0 (self->priv->device_combo); +	self->priv->device_combo = _tmp46_; +	_tmp47_ = gtk_combo_box_get_model (self->priv->device_combo); +	_tmp48_ = _g_object_ref0 (GTK_LIST_STORE (_tmp47_)); +	_g_object_unref0 (self->priv->device_model); +	self->priv->device_model = _tmp48_; +	_tmp49_ = gtk_builder_get_object (self->priv->builder, "text_dpi_combo"); +	_tmp50_ = _g_object_ref0 (GTK_COMBO_BOX (_tmp49_)); +	_g_object_unref0 (self->priv->text_dpi_combo); +	self->priv->text_dpi_combo = _tmp50_; +	_tmp51_ = gtk_combo_box_get_model (self->priv->text_dpi_combo); +	_tmp52_ = _g_object_ref0 (GTK_LIST_STORE (_tmp51_)); +	_g_object_unref0 (self->priv->text_dpi_model); +	self->priv->text_dpi_model = _tmp52_; +	_tmp53_ = gtk_builder_get_object (self->priv->builder, "photo_dpi_combo"); +	_tmp54_ = _g_object_ref0 (GTK_COMBO_BOX (_tmp53_)); +	_g_object_unref0 (self->priv->photo_dpi_combo); +	self->priv->photo_dpi_combo = _tmp54_; +	_tmp55_ = gtk_combo_box_get_model (self->priv->photo_dpi_combo); +	_tmp56_ = _g_object_ref0 (GTK_LIST_STORE (_tmp55_)); +	_g_object_unref0 (self->priv->photo_dpi_model); +	self->priv->photo_dpi_model = _tmp56_; +	_tmp57_ = gtk_builder_get_object (self->priv->builder, "page_side_combo"); +	_tmp58_ = _g_object_ref0 (GTK_COMBO_BOX (_tmp57_)); +	_g_object_unref0 (self->priv->page_side_combo); +	self->priv->page_side_combo = _tmp58_; +	_tmp59_ = gtk_combo_box_get_model (self->priv->page_side_combo); +	_tmp60_ = _g_object_ref0 (GTK_LIST_STORE (_tmp59_)); +	_g_object_unref0 (self->priv->page_side_model); +	self->priv->page_side_model = _tmp60_; +	_tmp61_ = gtk_builder_get_object (self->priv->builder, "paper_size_combo"); +	_tmp62_ = _g_object_ref0 (GTK_COMBO_BOX (_tmp61_)); +	_g_object_unref0 (self->priv->paper_size_combo); +	self->priv->paper_size_combo = _tmp62_; +	_tmp63_ = gtk_combo_box_get_model (self->priv->paper_size_combo); +	_tmp64_ = _g_object_ref0 (GTK_LIST_STORE (_tmp63_)); +	_g_object_unref0 (self->priv->paper_size_model); +	self->priv->paper_size_model = _tmp64_; +	_tmp65_ = (GtkInfoBar*) gtk_info_bar_new (); +	_g_object_unref0 (self->priv->info_bar); +	self->priv->info_bar = g_object_ref_sink (_tmp65_); +	g_signal_connect (self->priv->info_bar, "response", (GCallback) _simple_scan_info_bar_response_cb_gtk_info_bar_response, self); +	gtk_box_pack_start ((GtkBox*) self->priv->main_vbox, (GtkWidget*) self->priv->info_bar, FALSE, TRUE, (guint) 0); +	_tmp66_ = (GtkHBox*) gtk_hbox_new (FALSE, 12); +	hbox = g_object_ref_sink (_tmp66_); +	_tmp67_ = gtk_info_bar_get_content_area (self->priv->info_bar); +	_tmp68_ = _g_object_ref0 (GTK_CONTAINER (_tmp67_)); +	content_area = _tmp68_; +	gtk_container_add (content_area, (GtkWidget*) hbox); +	gtk_widget_show ((GtkWidget*) hbox); +	_tmp69_ = (GtkImage*) gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); +	_g_object_unref0 (self->priv->info_bar_image); +	self->priv->info_bar_image = g_object_ref_sink (_tmp69_); +	gtk_box_pack_start ((GtkBox*) hbox, (GtkWidget*) self->priv->info_bar_image, FALSE, TRUE, (guint) 0); +	gtk_widget_show ((GtkWidget*) self->priv->info_bar_image); +	_tmp70_ = (GtkLabel*) gtk_label_new (NULL); +	_g_object_unref0 (self->priv->info_bar_label); +	self->priv->info_bar_label = g_object_ref_sink (_tmp70_); +	gtk_misc_set_alignment ((GtkMisc*) self->priv->info_bar_label, 0.0f, 0.5f); +	gtk_box_pack_start ((GtkBox*) hbox, (GtkWidget*) self->priv->info_bar_label, TRUE, TRUE, (guint) 0); +	gtk_widget_show ((GtkWidget*) self->priv->info_bar_label); +	_tmp71_ = gtk_info_bar_add_button (self->priv->info_bar, GTK_STOCK_CLOSE, (gint) GTK_RESPONSE_CLOSE); +	_tmp72_ = _g_object_ref0 (GTK_BUTTON (_tmp71_)); +	_g_object_unref0 (self->priv->info_bar_close_button); +	self->priv->info_bar_close_button = _tmp72_; +	_tmp73_ = _ ("Change _Scanner"); +	_tmp74_ = gtk_info_bar_add_button (self->priv->info_bar, _tmp73_, 1); +	_tmp75_ = _g_object_ref0 (GTK_BUTTON (_tmp74_)); +	_g_object_unref0 (self->priv->info_bar_change_scanner_button); +	self->priv->info_bar_change_scanner_button = _tmp75_; +	gtk_list_store_append (self->priv->paper_size_model, &_tmp76_); +	iter = _tmp76_; +	_tmp77_ = _ ("Automatic"); +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 0, 1, 0, 2, _tmp77_, -1, -1); +	gtk_list_store_append (self->priv->paper_size_model, &_tmp78_); +	iter = _tmp78_; +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 1050, 1, 1480, 2, "A6", -1, -1); +	gtk_list_store_append (self->priv->paper_size_model, &_tmp79_); +	iter = _tmp79_; +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 1480, 1, 2100, 2, "A5", -1, -1); +	gtk_list_store_append (self->priv->paper_size_model, &_tmp80_); +	iter = _tmp80_; +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 2100, 1, 2970, 2, "A4", -1, -1); +	gtk_list_store_append (self->priv->paper_size_model, &_tmp81_); +	iter = _tmp81_; +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 2159, 1, 2794, 2, "Letter", -1, -1); +	gtk_list_store_append (self->priv->paper_size_model, &_tmp82_); +	iter = _tmp82_; +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 2159, 1, 3556, 2, "Legal", -1, -1); +	gtk_list_store_append (self->priv->paper_size_model, &_tmp83_); +	iter = _tmp83_; +	gtk_list_store_set (self->priv->paper_size_model, &iter, 0, 1016, 1, 1524, 2, "4×6", -1, -1); +	_tmp84_ = g_settings_get_int (self->priv->settings, "text-dpi"); +	dpi = _tmp84_; +	if (dpi <= 0) { +		dpi = SIMPLE_SCAN_DEFAULT_TEXT_DPI; +	} +	simple_scan_set_dpi_combo (self, self->priv->text_dpi_combo, SIMPLE_SCAN_DEFAULT_TEXT_DPI, dpi); +	_tmp85_ = g_settings_get_int (self->priv->settings, "photo-dpi"); +	dpi = _tmp85_; +	if (dpi <= 0) { +		dpi = SIMPLE_SCAN_DEFAULT_PHOTO_DPI; +	} +	simple_scan_set_dpi_combo (self, self->priv->photo_dpi_combo, SIMPLE_SCAN_DEFAULT_PHOTO_DPI, dpi); +	_tmp86_ = (GtkCellRendererText*) gtk_cell_renderer_text_new (); +	renderer = g_object_ref_sink (_tmp86_); +	gtk_cell_layout_pack_start ((GtkCellLayout*) self->priv->device_combo, (GtkCellRenderer*) renderer, TRUE); +	gtk_cell_layout_add_attribute ((GtkCellLayout*) self->priv->device_combo, (GtkCellRenderer*) renderer, "text", 1); +	_tmp87_ = (GtkCellRendererText*) gtk_cell_renderer_text_new (); +	_g_object_unref0 (renderer); +	renderer = g_object_ref_sink (_tmp87_); +	gtk_cell_layout_pack_start ((GtkCellLayout*) self->priv->page_side_combo, (GtkCellRenderer*) renderer, TRUE); +	gtk_cell_layout_add_attribute ((GtkCellLayout*) self->priv->page_side_combo, (GtkCellRenderer*) renderer, "text", 1); +	_tmp88_ = g_settings_get_enum (self->priv->settings, "page-side"); +	simple_scan_set_page_side (self, (ScanType) _tmp88_); +	_tmp89_ = (GtkCellRendererText*) gtk_cell_renderer_text_new (); +	_g_object_unref0 (renderer); +	renderer = g_object_ref_sink (_tmp89_); +	gtk_cell_layout_pack_start ((GtkCellLayout*) self->priv->paper_size_combo, (GtkCellRenderer*) renderer, TRUE); +	gtk_cell_layout_add_attribute ((GtkCellLayout*) self->priv->paper_size_combo, (GtkCellRenderer*) renderer, "text", 2); +	_tmp90_ = g_settings_get_int (self->priv->settings, "paper-width"); +	paper_width = _tmp90_; +	_tmp91_ = g_settings_get_int (self->priv->settings, "paper-height"); +	paper_height = _tmp91_; +	simple_scan_set_paper_size (self, paper_width, paper_height); +	_tmp92_ = g_settings_get_string (self->priv->settings, "selected-device"); +	device = _tmp92_; +	if (device != NULL) { +		GtkTreeIter _tmp93_ = {0}; +		gboolean _tmp94_; +		_tmp94_ = simple_scan_find_scan_device (self, device, &_tmp93_); +		iter = _tmp93_; +		if (_tmp94_) { +			gtk_combo_box_set_active_iter (self->priv->device_combo, &iter); +		} +	} +	_tmp95_ = g_settings_get_string (self->priv->settings, "document-type"); +	document_type = _tmp95_; +	if (document_type != NULL) { +		simple_scan_set_document_hint (self, document_type); +	} +	_tmp96_ = book_view_new (self->priv->book); +	_g_object_unref0 (self->priv->book_view); +	self->priv->book_view = g_object_ref_sink (_tmp96_); +	gtk_container_set_border_width ((GtkContainer*) self->priv->book_view, (guint) 18); +	gtk_box_pack_end ((GtkBox*) self->priv->main_vbox, (GtkWidget*) self->priv->book_view, TRUE, TRUE, (guint) 0); +	g_signal_connect (self->priv->book_view, "page-selected", (GCallback) _simple_scan_page_selected_cb_book_view_page_selected, self); +	g_signal_connect (self->priv->book_view, "show-page", (GCallback) _simple_scan_show_page_cb_book_view_show_page, self); +	g_signal_connect (self->priv->book_view, "show-menu", (GCallback) _simple_scan_show_page_menu_cb_book_view_show_menu, self); +	gtk_widget_show ((GtkWidget*) self->priv->book_view); +	_tmp97_ = g_settings_get_enum (self->priv->settings, "scan-direction"); +	self->priv->default_page_scan_direction = (ScanDirection) _tmp97_; +	_tmp98_ = g_settings_get_int (self->priv->settings, "page-width"); +	self->priv->default_page_width = _tmp98_; +	if (self->priv->default_page_width <= 0) { +		self->priv->default_page_width = 595; +	} +	_tmp99_ = g_settings_get_int (self->priv->settings, "page-height"); +	self->priv->default_page_height = _tmp99_; +	if (self->priv->default_page_height <= 0) { +		self->priv->default_page_height = 842; +	} +	_tmp100_ = g_settings_get_int (self->priv->settings, "page-dpi"); +	self->priv->default_page_dpi = _tmp100_; +	if (self->priv->default_page_dpi <= 0) { +		self->priv->default_page_dpi = 72; +	} +	_tmp101_ = g_settings_get_int (self->priv->settings, "window-width"); +	self->priv->window_width = _tmp101_; +	if (self->priv->window_width <= 0) { +		self->priv->window_width = 600; +	} +	_tmp102_ = g_settings_get_int (self->priv->settings, "window-height"); +	self->priv->window_height = _tmp102_; +	if (self->priv->window_height <= 0) { +		self->priv->window_height = 400; +	} +	g_debug ("ui.vala:1407: Restoring window to %dx%d pixels", self->priv->window_width, self->priv->window_height); +	gtk_window_set_default_size (self->priv->window, self->priv->window_width, self->priv->window_height); +	_tmp103_ = g_settings_get_boolean (self->priv->settings, "window-is-maximized"); +	self->priv->window_is_maximized = _tmp103_; +	if (self->priv->window_is_maximized) { +		g_debug ("ui.vala:1412: Restoring window to maximized"); +		gtk_window_maximize (self->priv->window); +	} +	_tmp104_ = book_get_n_pages (self->priv->book); +	if (_tmp104_ == ((guint) 0)) { +		simple_scan_add_default_page (self); +	} +	book_set_needs_saving (self->priv->book, FALSE); +	g_signal_connect (self->priv->book, "needs-saving-changed", (GCallback) _simple_scan_needs_saving_cb_book_needs_saving_changed, self); +	_g_free0 (document_type); +	_g_free0 (device); +	_g_object_unref0 (renderer); +	_g_object_unref0 (content_area); +	_g_object_unref0 (hbox); +	_g_free0 (filename); +} + + +static gpointer _book_ref0 (gpointer self) { +	return self ? book_ref (self) : NULL; +} + + +Book* simple_scan_get_book (SimpleScan* self) { +	Book* result = NULL; +	Book* _tmp0_; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = _book_ref0 (self->priv->book); +	result = _tmp0_; +	return result; +} + + +void simple_scan_set_selected_page (SimpleScan* self, Page* page) { +	g_return_if_fail (self != NULL); +	g_return_if_fail (page != NULL); +	book_view_select_page (self->priv->book_view, page); +} + + +Page* simple_scan_get_selected_page (SimpleScan* self) { +	Page* result = NULL; +	Page* _tmp0_ = NULL; +	g_return_val_if_fail (self != NULL, NULL); +	_tmp0_ = book_view_get_selected (self->priv->book_view); +	result = _tmp0_; +	return result; +} + + +void simple_scan_set_scanning (SimpleScan* self, gboolean scanning) { +	g_return_if_fail (self != NULL); +	self->priv->scanning = scanning; +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->page_delete_menuitem, !scanning); +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->stop_menuitem, scanning); +	gtk_widget_set_sensitive ((GtkWidget*) self->priv->stop_toolbutton, scanning); +} + + +void simple_scan_show_error (SimpleScan* self, const gchar* error_title, const gchar* error_text, gboolean change_scanner_hint) { +	gchar* _tmp0_; +	gchar* _tmp1_; +	g_return_if_fail (self != NULL); +	g_return_if_fail (error_title != NULL); +	g_return_if_fail (error_text != NULL); +	self->priv->have_error = TRUE; +	_tmp0_ = g_strdup (error_title); +	_g_free0 (self->priv->error_title); +	self->priv->error_title = _tmp0_; +	_tmp1_ = g_strdup (error_text); +	_g_free0 (self->priv->error_text); +	self->priv->error_text = _tmp1_; +	self->priv->error_change_scanner_hint = change_scanner_hint; +	simple_scan_update_info_bar (self); +} + -    update_page_menu (ui); +void simple_scan_start (SimpleScan* self) { +	g_return_if_fail (self != NULL); +	gtk_widget_show ((GtkWidget*) self->priv->window);  } -void page_move_right_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -page_move_right_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    Book *book = book_view_get_book (ui->priv->book_view); -    Page *page = book_view_get_selected (ui->priv->book_view); -    gint index; - -    index = book_get_page_index (book, page); -    if (index < book_get_n_pages (book) - 1) -        book_move_page (book, page, book_get_page_index (book, page) + 1); - -    update_page_menu (ui); +static void g_cclosure_user_marshal_VOID__STRING_SCAN_OPTIONS (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { +	typedef void (*GMarshalFunc_VOID__STRING_SCAN_OPTIONS) (gpointer data1, const char* arg_1, gpointer arg_2, gpointer data2); +	register GMarshalFunc_VOID__STRING_SCAN_OPTIONS callback; +	register GCClosure * cc; +	register gpointer data1; +	register gpointer data2; +	cc = (GCClosure *) closure; +	g_return_if_fail (n_param_values == 3); +	if (G_CCLOSURE_SWAP_DATA (closure)) { +		data1 = closure->data; +		data2 = param_values->data[0].v_pointer; +	} else { +		data1 = param_values->data[0].v_pointer; +		data2 = closure->data; +	} +	callback = (GMarshalFunc_VOID__STRING_SCAN_OPTIONS) (marshal_data ? marshal_data : cc->callback); +	callback (data1, g_value_get_string (param_values + 1), value_get_scan_options (param_values + 2), data2);  } -void page_delete_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -page_delete_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    book_delete_page (book_view_get_book (ui->priv->book_view), -                      book_view_get_selected (ui->priv->book_view)); +static void value_simple_scan_init (GValue* value) { +	value->data[0].v_pointer = NULL;  } -void save_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -save_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    save_document (ui, FALSE); +static void value_simple_scan_free_value (GValue* value) { +	if (value->data[0].v_pointer) { +		simple_scan_unref (value->data[0].v_pointer); +	}  } -void save_as_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -save_as_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    save_document (ui, TRUE); +static void value_simple_scan_copy_value (const GValue* src_value, GValue* dest_value) { +	if (src_value->data[0].v_pointer) { +		dest_value->data[0].v_pointer = simple_scan_ref (src_value->data[0].v_pointer); +	} else { +		dest_value->data[0].v_pointer = NULL; +	}  } -static void -draw_page (GtkPrintOperation *operation, -           GtkPrintContext   *print_context, -           gint               page_number, -           SimpleScan        *ui) -{ -    cairo_t *context; -    Page *page; -    GdkPixbuf *image; -    gboolean is_landscape = FALSE; - -    context = gtk_print_context_get_cairo_context (print_context); -    -    page = book_get_page (ui->priv->book, page_number); - -    /* Rotate to same aspect */ -    if (gtk_print_context_get_width (print_context) > gtk_print_context_get_height (print_context)) -        is_landscape = TRUE; -    if (page_is_landscape (page) != is_landscape) { -        cairo_translate (context, gtk_print_context_get_width (print_context), 0); -        cairo_rotate (context, M_PI_2); -    } -    -    cairo_scale (context, -                 gtk_print_context_get_dpi_x (print_context) / page_get_dpi (page), -                 gtk_print_context_get_dpi_y (print_context) / page_get_dpi (page)); - -    image = page_get_image (page, TRUE); -    gdk_cairo_set_source_pixbuf (context, image, 0, 0); -    cairo_paint (context); - -    g_object_unref (image); -} - - -void email_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -email_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    g_signal_emit (G_OBJECT (ui), signals[EMAIL], 0, ui->priv->document_hint); -} - - -void print_button_clicked_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -print_button_clicked_cb (GtkWidget *widget, SimpleScan *ui) -{ -    GtkPrintOperation *print; -    GtkPrintOperationResult result; -    GError *error = NULL; -    -    print = gtk_print_operation_new (); -    gtk_print_operation_set_n_pages (print, book_get_n_pages (ui->priv->book)); -    g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), ui); - -    result = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, -                                      GTK_WINDOW (ui->priv->window), &error); - -    g_object_unref (print); -} - - -void help_contents_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -help_contents_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    GdkScreen *screen; -    GError *error = NULL; - -    screen = gtk_widget_get_screen (GTK_WIDGET (ui->priv->window)); -    gtk_show_uri (screen, "ghelp:simple-scan", gtk_get_current_event_time (), &error); - -    if (error) -    { -        show_error_dialog (ui, -                           /* Error message displayed when unable to launch help browser */ -                           _("Unable to open help file"), -                           error->message); -        g_clear_error (&error); -    } -} - - -void about_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -about_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    const gchar *authors[] = { "Robert Ancell <robert.ancell@canonical.com>", NULL }; - -    /* The license this software is under (GPL3+) */ -    const char *license = _("This program is free software: you can redistribute it and/or modify\n" -                            "it under the terms of the GNU General Public License as published by\n" -                            "the Free Software Foundation, either version 3 of the License, or\n" -                            "(at your option) any later version.\n" -                            "\n" -                            "This program is distributed in the hope that it will be useful,\n" -                            "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -                            "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" -                            "GNU General Public License for more details.\n" -                            "\n" -                            "You should have received a copy of the GNU General Public License\n" -                            "along with this program.  If not, see <http://www.gnu.org/licenses/>."); - -    /* Title of about dialog */ -    const char *title = _("About Simple Scan"); - -    /* Description of program */ -    const char *description = _("Simple document scanning tool"); - -    gtk_show_about_dialog (GTK_WINDOW (ui->priv->window), -                           "title", title, -                           "program-name", "Simple Scan", -                           "version", VERSION, -                           "comments", description, -                           "logo-icon-name", "scanner", -                           "authors", authors, -                           "translator-credits", _("translator-credits"), -                           "website", "https://launchpad.net/simple-scan", -                           "copyright", "Copyright © 2009 Canonical Ltd.", -                           "license", license, -                           "wrap-license", TRUE, -                           NULL); -} - - -static gboolean -quit (SimpleScan *ui) -{ -    char *device; -    gint paper_width = 0, paper_height = 0; -    gint i; - -    if (!prompt_to_save (ui, -                         /* Text in dialog warning when a document is about to be lost */ -                         _("Save document before quitting?"), -                         /* Button in dialog to quit and discard unsaved document */ -                         _("Quit without Saving"))) -        return FALSE; - -    device = get_selected_device (ui); -    if (device) { -        gconf_client_set_string(ui->priv->client, GCONF_DIR "/selected_device", device, NULL); -        g_free (device); -    } - -    gconf_client_set_string (ui->priv->client, GCONF_DIR "/document_type", ui->priv->document_hint, NULL); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/text_dpi", get_text_dpi (ui), NULL); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/photo_dpi", get_photo_dpi (ui), NULL); -    gconf_client_set_string (ui->priv->client, GCONF_DIR "/page_side", get_page_side (ui), NULL); -    get_paper_size (ui, &paper_width, &paper_height); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/paper_width", paper_width, NULL); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/paper_height", paper_height, NULL); - -    gconf_client_set_int(ui->priv->client, GCONF_DIR "/window_width", ui->priv->window_width, NULL); -    gconf_client_set_int(ui->priv->client, GCONF_DIR "/window_height", ui->priv->window_height, NULL); -    gconf_client_set_bool(ui->priv->client, GCONF_DIR "/window_is_maximized", ui->priv->window_is_maximized, NULL); - -    for (i = 0; scan_direction_keys[i].key != NULL && scan_direction_keys[i].scan_direction != ui->priv->default_page_scan_direction; i++); -    if (scan_direction_keys[i].key != NULL) -        gconf_client_set_string(ui->priv->client, GCONF_DIR "/scan_direction", scan_direction_keys[i].key, NULL); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_width", ui->priv->default_page_width, NULL); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_height", ui->priv->default_page_height, NULL); -    gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_dpi", ui->priv->default_page_dpi, NULL); -    -    g_signal_emit (G_OBJECT (ui), signals[QUIT], 0); - -    return TRUE; -} - - -void quit_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui); -G_MODULE_EXPORT -void -quit_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui) -{ -    quit (ui); -} - - -gboolean simple_scan_window_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, SimpleScan *ui); -G_MODULE_EXPORT -gboolean -simple_scan_window_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, SimpleScan *ui) -{ -    if (!ui->priv->window_is_maximized) { -        ui->priv->window_width = event->width; -        ui->priv->window_height = event->height; -    } - -    return FALSE; -} - - -static void -info_bar_response_cb (GtkWidget *widget, gint response_id, SimpleScan *ui) -{ -    if (response_id == 1) { -        gtk_widget_grab_focus (ui->priv->device_combo); -        gtk_window_present (GTK_WINDOW (ui->priv->preferences_dialog)); -    } -    else { -        ui->priv->have_error = FALSE; -        g_free (ui->priv->error_title); -        ui->priv->error_title = NULL; -        g_free (ui->priv->error_text); -        ui->priv->error_text = NULL; -        update_info_bar (ui);       -    } -} - - -gboolean simple_scan_window_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, SimpleScan *ui); -G_MODULE_EXPORT -gboolean -simple_scan_window_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, SimpleScan *ui) -{ -    if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) -        ui->priv->window_is_maximized = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0; -    return FALSE; -} - - -gboolean window_delete_event_cb (GtkWidget *widget, GdkEvent *event, SimpleScan *ui); -G_MODULE_EXPORT -gboolean -window_delete_event_cb (GtkWidget *widget, GdkEvent *event, SimpleScan *ui) -{ -    return !quit (ui); -} - - -static void -page_size_changed_cb (Page *page, SimpleScan *ui) -{ -    ui->priv->default_page_width = page_get_width (page); -    ui->priv->default_page_height = page_get_height (page); -    ui->priv->default_page_dpi = page_get_dpi (page); +static gpointer value_simple_scan_peek_pointer (const GValue* value) { +	return value->data[0].v_pointer;  } -static void -page_scan_direction_changed_cb (Page *page, SimpleScan *ui) -{ -    ui->priv->default_page_scan_direction = page_get_scan_direction (page); +static gchar* value_simple_scan_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	if (collect_values[0].v_pointer) { +		SimpleScan* object; +		object = collect_values[0].v_pointer; +		if (object->parent_instance.g_class == NULL) { +			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { +			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); +		} +		value->data[0].v_pointer = simple_scan_ref (object); +	} else { +		value->data[0].v_pointer = NULL; +	} +	return NULL;  } -static void -page_added_cb (Book *book, Page *page, SimpleScan *ui) -{ -    ui->priv->default_page_width = page_get_width (page); -    ui->priv->default_page_height = page_get_height (page); -    ui->priv->default_page_dpi = page_get_dpi (page); -    ui->priv->default_page_scan_direction = page_get_scan_direction (page); -    g_signal_connect (page, "size-changed", G_CALLBACK (page_size_changed_cb), ui); -    g_signal_connect (page, "scan-direction-changed", G_CALLBACK (page_scan_direction_changed_cb), ui); - -    update_page_menu (ui); +static gchar* value_simple_scan_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { +	SimpleScan** object_p; +	object_p = collect_values[0].v_pointer; +	if (!object_p) { +		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); +	} +	if (!value->data[0].v_pointer) { +		*object_p = NULL; +	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { +		*object_p = value->data[0].v_pointer; +	} else { +		*object_p = simple_scan_ref (value->data[0].v_pointer); +	} +	return NULL; +} + + +GParamSpec* param_spec_simple_scan (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { +	ParamSpecSimpleScan* spec; +	g_return_val_if_fail (g_type_is_a (object_type, TYPE_SIMPLE_SCAN), NULL); +	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); +	G_PARAM_SPEC (spec)->value_type = object_type; +	return G_PARAM_SPEC (spec); +} + + +gpointer value_get_simple_scan (const GValue* value) { +	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SIMPLE_SCAN), NULL); +	return value->data[0].v_pointer; +} + + +void value_set_simple_scan (GValue* value, gpointer v_object) { +	SimpleScan* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SIMPLE_SCAN)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SIMPLE_SCAN)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +		simple_scan_ref (value->data[0].v_pointer); +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		simple_scan_unref (old); +	} +} + + +void value_take_simple_scan (GValue* value, gpointer v_object) { +	SimpleScan* old; +	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_SIMPLE_SCAN)); +	old = value->data[0].v_pointer; +	if (v_object) { +		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_SIMPLE_SCAN)); +		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); +		value->data[0].v_pointer = v_object; +	} else { +		value->data[0].v_pointer = NULL; +	} +	if (old) { +		simple_scan_unref (old); +	} +} + + +static void simple_scan_class_init (SimpleScanClass * klass) { +	simple_scan_parent_class = g_type_class_peek_parent (klass); +	SIMPLE_SCAN_CLASS (klass)->finalize = simple_scan_finalize; +	g_type_class_add_private (klass, sizeof (SimpleScanPrivate)); +	g_signal_new ("start_scan", TYPE_SIMPLE_SCAN, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__STRING_SCAN_OPTIONS, G_TYPE_NONE, 2, G_TYPE_STRING, TYPE_SCAN_OPTIONS); +	g_signal_new ("stop_scan", TYPE_SIMPLE_SCAN, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +	g_signal_new ("email", TYPE_SIMPLE_SCAN, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); +	g_signal_new ("quit", TYPE_SIMPLE_SCAN, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + + +static void simple_scan_instance_init (SimpleScan * self) { +	gchar* _tmp0_; +	const gchar* _tmp1_ = NULL; +	gchar* _tmp2_; +	self->priv = SIMPLE_SCAN_GET_PRIVATE (self); +	self->priv->book_uri = NULL; +	_tmp0_ = g_strdup ("photo"); +	self->priv->document_hint = _tmp0_; +	_tmp1_ = _ ("Scanned Document.pdf"); +	_tmp2_ = g_strdup (_tmp1_); +	self->priv->default_file_name = _tmp2_; +	self->priv->scanning = FALSE; +	self->ref_count = 1; +} + + +static void simple_scan_finalize (SimpleScan* obj) { +	SimpleScan * self; +	self = SIMPLE_SCAN (obj); +	_g_object_unref0 (self->priv->settings); +	_g_object_unref0 (self->priv->builder); +	_g_object_unref0 (self->priv->window); +	_g_object_unref0 (self->priv->main_vbox); +	_g_object_unref0 (self->priv->info_bar); +	_g_object_unref0 (self->priv->info_bar_image); +	_g_object_unref0 (self->priv->info_bar_label); +	_g_object_unref0 (self->priv->info_bar_close_button); +	_g_object_unref0 (self->priv->info_bar_change_scanner_button); +	_g_object_unref0 (self->priv->page_move_left_menuitem); +	_g_object_unref0 (self->priv->page_move_right_menuitem); +	_g_object_unref0 (self->priv->page_delete_menuitem); +	_g_object_unref0 (self->priv->crop_rotate_menuitem); +	_g_object_unref0 (self->priv->save_menuitem); +	_g_object_unref0 (self->priv->save_as_menuitem); +	_g_object_unref0 (self->priv->save_toolbutton); +	_g_object_unref0 (self->priv->stop_menuitem); +	_g_object_unref0 (self->priv->stop_toolbutton); +	_g_object_unref0 (self->priv->text_toolbar_menuitem); +	_g_object_unref0 (self->priv->text_menu_menuitem); +	_g_object_unref0 (self->priv->photo_toolbar_menuitem); +	_g_object_unref0 (self->priv->photo_menu_menuitem); +	_g_object_unref0 (self->priv->authorize_dialog); +	_g_object_unref0 (self->priv->authorize_label); +	_g_object_unref0 (self->priv->username_entry); +	_g_object_unref0 (self->priv->password_entry); +	_g_object_unref0 (self->priv->preferences_dialog); +	_g_object_unref0 (self->priv->device_combo); +	_g_object_unref0 (self->priv->text_dpi_combo); +	_g_object_unref0 (self->priv->photo_dpi_combo); +	_g_object_unref0 (self->priv->page_side_combo); +	_g_object_unref0 (self->priv->paper_size_combo); +	_g_object_unref0 (self->priv->device_model); +	_g_object_unref0 (self->priv->text_dpi_model); +	_g_object_unref0 (self->priv->photo_dpi_model); +	_g_object_unref0 (self->priv->page_side_model); +	_g_object_unref0 (self->priv->paper_size_model); +	_g_object_unref0 (self->priv->save_dialog); +	_g_free0 (self->priv->error_title); +	_g_free0 (self->priv->error_text); +	_book_unref0 (self->priv->book); +	_g_free0 (self->priv->book_uri); +	_g_object_unref0 (self->priv->book_view); +	_g_free0 (self->priv->document_hint); +	_g_free0 (self->priv->default_file_name); +} + + +GType simple_scan_get_type (void) { +	static volatile gsize simple_scan_type_id__volatile = 0; +	if (g_once_init_enter (&simple_scan_type_id__volatile)) { +		static const GTypeValueTable g_define_type_value_table = { value_simple_scan_init, value_simple_scan_free_value, value_simple_scan_copy_value, value_simple_scan_peek_pointer, "p", value_simple_scan_collect_value, "p", value_simple_scan_lcopy_value }; +		static const GTypeInfo g_define_type_info = { sizeof (SimpleScanClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) simple_scan_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (SimpleScan), 0, (GInstanceInitFunc) simple_scan_instance_init, &g_define_type_value_table }; +		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; +		GType simple_scan_type_id; +		simple_scan_type_id = g_type_register_fundamental (g_type_fundamental_next (), "SimpleScan", &g_define_type_info, &g_define_type_fundamental_info, 0); +		g_once_init_leave (&simple_scan_type_id__volatile, simple_scan_type_id); +	} +	return simple_scan_type_id__volatile; +} + + +gpointer simple_scan_ref (gpointer instance) { +	SimpleScan* self; +	self = instance; +	g_atomic_int_inc (&self->ref_count); +	return instance; +} + + +void simple_scan_unref (gpointer instance) { +	SimpleScan* self; +	self = instance; +	if (g_atomic_int_dec_and_test (&self->ref_count)) { +		SIMPLE_SCAN_GET_CLASS (self)->finalize (self); +		g_type_free_instance ((GTypeInstance *) self); +	} +} + + +static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	if ((array != NULL) && (destroy_func != NULL)) { +		int i; +		for (i = 0; i < array_length; i = i + 1) { +			if (((gpointer*) array)[i] != NULL) { +				destroy_func (((gpointer*) array)[i]); +			} +		} +	} +} + + +static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) { +	_vala_array_destroy (array, array_length, destroy_func); +	g_free (array);  } -static void -page_removed_cb (Book *book, Page *page, SimpleScan *ui) -{ -    /* If this is the last page add a new blank one */ -    if (book_get_n_pages (ui->priv->book) == 1) -        add_default_page (ui); -    update_page_menu (ui); -} - - -static void -set_dpi_combo (GtkWidget *combo, gint default_dpi, gint current_dpi) -{ -    struct -    { -       gint dpi; -       const gchar *label; -    } scan_resolutions[] = -    { -      /* Preferences dialog: Label for minimum resolution in resolution list */ -      { 75,  _("%d dpi (draft)") }, -      /* Preferences dialog: Label for resolution value in resolution list (dpi = dots per inch) */ -      { 150, _("%d dpi") }, -      { 300, _("%d dpi") }, -      { 600, _("%d dpi") }, -      /* Preferences dialog: Label for maximum resolution in resolution list */       -      { 1200, _("%d dpi (high resolution)") }, -      { 2400, _("%d dpi") }, -      { -1, NULL } -    }; -    GtkCellRenderer *renderer; -    GtkTreeModel *model; -    gint i; - -    renderer = gtk_cell_renderer_text_new(); -    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); -    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "text", 1); - -    model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); -    for (i = 0; scan_resolutions[i].dpi > 0; i++) -    { -        GtkTreeIter iter; -        gchar *label; -        gint dpi; - -        dpi = scan_resolutions[i].dpi; - -        if (dpi == default_dpi) -            label = g_strdup_printf (/* Preferences dialog: Label for default resolution in resolution list */ -                                     _("%d dpi (default)"), dpi); -        else -            label = g_strdup_printf (scan_resolutions[i].label, dpi); - -        gtk_list_store_append (GTK_LIST_STORE (model), &iter); -        gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, dpi, 1, label, -1); - -        if (dpi == current_dpi) -            gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter); - -        g_free (label); -    } -} - - -static void -needs_saving_cb (Book *book, GParamSpec *param, SimpleScan *ui) -{ -    gtk_widget_set_sensitive (ui->priv->save_menuitem, book_get_needs_saving (book)); -    gtk_widget_set_sensitive (ui->priv->save_toolbutton, book_get_needs_saving (book)); -    if (book_get_needs_saving (book)) -        gtk_widget_set_sensitive (ui->priv->save_as_menuitem, TRUE); -} - - -static void -ui_load (SimpleScan *ui) -{ -    GtkBuilder *builder; -    GError *error = NULL; -    GtkWidget *hbox; -    GtkCellRenderer *renderer; -    gchar *device, *document_type, *scan_direction, *page_side; -    gint dpi, paper_width, paper_height; - -    gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), ICON_DIR); - -    gtk_window_set_default_icon_name ("scanner"); - -    builder = ui->priv->builder = gtk_builder_new (); -    gtk_builder_add_from_file (builder, UI_DIR "simple-scan.ui", &error); -    if (error) { -        g_critical ("Unable to load UI: %s\n", error->message); -        show_error_dialog (ui, -                           /* Title of dialog when cannot load required files */ -                           _("Files missing"), -                           /* Description in dialog when cannot load required files */ -                           _("Please check your installation")); -        exit (1); -    } -    gtk_builder_connect_signals (builder, ui); - -    ui->priv->window = GTK_WIDGET (gtk_builder_get_object (builder, "simple_scan_window")); -    ui->priv->main_vbox = GTK_WIDGET (gtk_builder_get_object (builder, "main_vbox")); -    ui->priv->page_move_left_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "page_move_left_menuitem")); -    ui->priv->page_move_right_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "page_move_right_menuitem")); -    ui->priv->page_delete_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "page_delete_menuitem")); -    ui->priv->crop_rotate_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "crop_rotate_menuitem")); -    ui->priv->save_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "save_menuitem")); -    ui->priv->save_as_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "save_as_menuitem")); -    ui->priv->save_toolbutton = GTK_WIDGET (gtk_builder_get_object (builder, "save_toolbutton")); -    ui->priv->stop_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "stop_scan_menuitem")); -    ui->priv->stop_toolbutton = GTK_WIDGET (gtk_builder_get_object (builder, "stop_toolbutton")); - -    ui->priv->text_toolbar_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "text_toolbutton_menuitem")); -    ui->priv->text_menu_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "text_menuitem")); -    ui->priv->photo_toolbar_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "photo_toolbutton_menuitem")); -    ui->priv->photo_menu_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "photo_menuitem")); - -    ui->priv->authorize_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "authorize_dialog")); -    ui->priv->authorize_label = GTK_WIDGET (gtk_builder_get_object (builder, "authorize_label")); -    ui->priv->username_entry = GTK_WIDGET (gtk_builder_get_object (builder, "username_entry")); -    ui->priv->password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry")); -    -    ui->priv->preferences_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "preferences_dialog")); -    ui->priv->device_combo = GTK_WIDGET (gtk_builder_get_object (builder, "device_combo")); -    ui->priv->device_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo)); -    ui->priv->text_dpi_combo = GTK_WIDGET (gtk_builder_get_object (builder, "text_dpi_combo")); -    ui->priv->text_dpi_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->text_dpi_combo)); -    ui->priv->photo_dpi_combo = GTK_WIDGET (gtk_builder_get_object (builder, "photo_dpi_combo")); -    ui->priv->photo_dpi_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->photo_dpi_combo)); -    ui->priv->page_side_combo = GTK_WIDGET (gtk_builder_get_object (builder, "page_side_combo")); -    ui->priv->page_side_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->page_side_combo)); -    ui->priv->paper_size_combo = GTK_WIDGET (gtk_builder_get_object (builder, "paper_size_combo")); -    ui->priv->paper_size_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->paper_size_combo)); - -    /* Add InfoBar (not supported in Glade) */ -    ui->priv->info_bar = gtk_info_bar_new (); -    g_signal_connect (ui->priv->info_bar, "response", G_CALLBACK (info_bar_response_cb), ui);   -    gtk_box_pack_start (GTK_BOX(ui->priv->main_vbox), ui->priv->info_bar, FALSE, TRUE, 0); -    hbox = gtk_hbox_new (FALSE, 12); -    gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (ui->priv->info_bar))), hbox); -    gtk_widget_show (hbox); - -    ui->priv->info_bar_image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); -    gtk_box_pack_start (GTK_BOX(hbox), ui->priv->info_bar_image, FALSE, TRUE, 0); -    gtk_widget_show (ui->priv->info_bar_image); - -    ui->priv->info_bar_label = gtk_label_new (NULL); -    gtk_misc_set_alignment (GTK_MISC (ui->priv->info_bar_label), 0.0, 0.5); -    gtk_box_pack_start (GTK_BOX(hbox), ui->priv->info_bar_label, TRUE, TRUE, 0); -    gtk_widget_show (ui->priv->info_bar_label); - -    ui->priv->info_bar_close_button = gtk_info_bar_add_button (GTK_INFO_BAR (ui->priv->info_bar), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); -    ui->priv->info_bar_change_scanner_button = gtk_info_bar_add_button (GTK_INFO_BAR (ui->priv->info_bar), -                                                                        /* Button in error infobar to open preferences dialog and change scanner */ -                                                                        _("Change _Scanner"), 1); - -    GtkTreeIter iter; -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 0, 1, 0, 2, -                        /* Combo box value for automatic paper size */ -                        _("Automatic"), -1); -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 1050, 1, 1480, 2, "A6", -1); -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 1480, 1, 2100, 2, "A5", -1); -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2100, 1, 2970, 2, "A4", -1); -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2159, 1, 2794, 2, "Letter", -1); -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2159, 1, 3556, 2, "Legal", -1); -    gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter); -    gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 1016, 1, 1524, 2, "4×6", -1); - -    dpi = gconf_client_get_int (ui->priv->client, GCONF_DIR "/text_dpi", NULL); -    if (dpi <= 0) -        dpi = DEFAULT_TEXT_DPI; -    set_dpi_combo (ui->priv->text_dpi_combo, DEFAULT_TEXT_DPI, dpi); -    dpi = gconf_client_get_int (ui->priv->client, GCONF_DIR "/photo_dpi", NULL); -    if (dpi <= 0) -        dpi = DEFAULT_PHOTO_DPI; -    set_dpi_combo (ui->priv->photo_dpi_combo, DEFAULT_PHOTO_DPI, dpi); - -    renderer = gtk_cell_renderer_text_new(); -    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->device_combo), renderer, TRUE); -    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->device_combo), renderer, "text", 1); - -    renderer = gtk_cell_renderer_text_new(); -    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->page_side_combo), renderer, TRUE); -    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->page_side_combo), renderer, "text", 1); -    page_side = gconf_client_get_string (ui->priv->client, GCONF_DIR "/page_side", NULL); -    if (page_side) { -        set_page_side (ui, page_side); -        g_free (page_side); -    } - -    renderer = gtk_cell_renderer_text_new(); -    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->paper_size_combo), renderer, TRUE); -    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->paper_size_combo), renderer, "text", 2); -    paper_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/paper_width", NULL); -    paper_height = gconf_client_get_int (ui->priv->client, GCONF_DIR "/paper_height", NULL); -    set_paper_size (ui, paper_width, paper_height); - -    device = gconf_client_get_string (ui->priv->client, GCONF_DIR "/selected_device", NULL); -    if (device) { -        GtkTreeIter iter; -        if (find_scan_device (ui, device, &iter)) -            gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter); -        g_free (device); -    } - -    document_type = gconf_client_get_string (ui->priv->client, GCONF_DIR "/document_type", NULL); -    if (document_type) { -        set_document_hint (ui, document_type); -        g_free (document_type); -    } - -    ui->priv->book_view = book_view_new (ui->priv->book); -    gtk_container_set_border_width (GTK_CONTAINER (ui->priv->book_view), 18); -    gtk_box_pack_end (GTK_BOX (ui->priv->main_vbox), GTK_WIDGET (ui->priv->book_view), TRUE, TRUE, 0); -    g_signal_connect (ui->priv->book_view, "page-selected", G_CALLBACK (page_selected_cb), ui); -    g_signal_connect (ui->priv->book_view, "show-page", G_CALLBACK (show_page_cb), ui); -    g_signal_connect (ui->priv->book_view, "show-menu", G_CALLBACK (show_page_menu_cb), ui); -    gtk_widget_show (GTK_WIDGET (ui->priv->book_view)); - -    /* Find default page details */ -    scan_direction = gconf_client_get_string(ui->priv->client, GCONF_DIR "/scan_direction", NULL); -    ui->priv->default_page_scan_direction = TOP_TO_BOTTOM; -    if (scan_direction) { -        gint i; -        for (i = 0; scan_direction_keys[i].key != NULL && strcmp (scan_direction_keys[i].key, scan_direction) != 0; i++); -        if (scan_direction_keys[i].key != NULL) -            ui->priv->default_page_scan_direction = scan_direction_keys[i].scan_direction; -        g_free (scan_direction); -    } -    ui->priv->default_page_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_width", NULL); -    if (ui->priv->default_page_width <= 0) -        ui->priv->default_page_width = 595; -    ui->priv->default_page_height = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_height", NULL); -    if (ui->priv->default_page_height <= 0) -        ui->priv->default_page_height = 842; -    ui->priv->default_page_dpi = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_dpi", NULL); -    if (ui->priv->default_page_dpi <= 0) -        ui->priv->default_page_dpi = 72; - -    /* Restore window size */ -    ui->priv->window_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/window_width", NULL); -    if (ui->priv->window_width <= 0) -        ui->priv->window_width = 600; -    ui->priv->window_height = gconf_client_get_int (ui->priv->client, GCONF_DIR "/window_height", NULL); -    if (ui->priv->window_height <= 0) -        ui->priv->window_height = 400; -    g_debug ("Restoring window to %dx%d pixels", ui->priv->window_width, ui->priv->window_height); -    gtk_window_set_default_size (GTK_WINDOW (ui->priv->window), ui->priv->window_width, ui->priv->window_height); -    ui->priv->window_is_maximized = gconf_client_get_bool (ui->priv->client, GCONF_DIR "/window_is_maximized", NULL); -    if (ui->priv->window_is_maximized) { -        g_debug ("Restoring window to maximized"); -        gtk_window_maximize (GTK_WINDOW (ui->priv->window)); -    } - -    if (book_get_n_pages (ui->priv->book) == 0) -        add_default_page (ui); -    book_set_needs_saving (ui->priv->book, FALSE); -    g_signal_connect (ui->priv->book, "notify::needs-saving", G_CALLBACK (needs_saving_cb), ui); -} - - -SimpleScan * -ui_new () -{ -    return g_object_new (SIMPLE_SCAN_TYPE, NULL); -} - - -Book * -ui_get_book (SimpleScan *ui) -{ -    return g_object_ref (ui->priv->book); -} - - -void -ui_set_selected_page (SimpleScan *ui, Page *page) -{ -    book_view_select_page (ui->priv->book_view, page); -} - - -Page * -ui_get_selected_page (SimpleScan *ui) -{ -    return book_view_get_selected (ui->priv->book_view); -} - - -void -ui_set_scanning (SimpleScan *ui, gboolean scanning) -{ -    ui->priv->scanning = scanning; -    gtk_widget_set_sensitive (ui->priv->page_delete_menuitem, !scanning); -    gtk_widget_set_sensitive (ui->priv->stop_menuitem, scanning); -    gtk_widget_set_sensitive (ui->priv->stop_toolbutton, scanning); -} - - -void -ui_show_error (SimpleScan *ui, const gchar *error_title, const gchar *error_text, gboolean change_scanner_hint) -{ -    ui->priv->have_error = TRUE; -    g_free (ui->priv->error_title); -    ui->priv->error_title = g_strdup (error_title); -    g_free (ui->priv->error_text); -    ui->priv->error_text = g_strdup (error_text); -    ui->priv->error_change_scanner_hint = change_scanner_hint; -    update_info_bar (ui); -} - - -void -ui_start (SimpleScan *ui) -{ -    gtk_widget_show (ui->priv->window); -} - - -/* Generated with glib-genmarshal */ -static void -g_cclosure_user_marshal_VOID__STRING_POINTER (GClosure     *closure, -                                              GValue       *return_value G_GNUC_UNUSED, -                                              guint         n_param_values, -                                              const GValue *param_values, -                                              gpointer      invocation_hint G_GNUC_UNUSED, -                                              gpointer      marshal_data) -{ -  typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer       data1, -                                                     gconstpointer  arg_1, -                                                     gconstpointer  arg_2, -                                                     gpointer       data2); -  register GMarshalFunc_VOID__STRING_POINTER callback; -  register GCClosure *cc = (GCClosure*) closure; -  register gpointer data1, data2; - -  g_return_if_fail (n_param_values == 3); - -  if (G_CCLOSURE_SWAP_DATA (closure)) -    { -      data1 = closure->data; -      data2 = g_value_peek_pointer (param_values + 0); -    } -  else -    { -      data1 = g_value_peek_pointer (param_values + 0); -      data2 = closure->data; -    } -  callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); - -  callback (data1, -            g_value_get_string (param_values + 1), -            g_value_get_pointer (param_values + 2), -            data2); -} - - -static void -ui_finalize (GObject *object) -{ -    SimpleScan *ui = SIMPLE_SCAN (object); - -    g_object_unref (ui->priv->client); -    ui->priv->client = NULL; -    g_object_unref (ui->priv->builder); -    ui->priv->builder = NULL; -    g_object_unref (ui->priv->book); -    ui->priv->book = NULL; -    gtk_widget_destroy (GTK_WIDGET (ui->priv->book_view)); -    ui->priv->book_view = NULL; - -    G_OBJECT_CLASS (ui_parent_class)->finalize (object); -} - - -static void -ui_class_init (SimpleScanClass *klass) -{ -    GObjectClass *object_class = G_OBJECT_CLASS (klass); - -    object_class->finalize = ui_finalize; - -    signals[START_SCAN] = -        g_signal_new ("start-scan", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (SimpleScanClass, start_scan), -                      NULL, NULL, -                      g_cclosure_user_marshal_VOID__STRING_POINTER, -                      G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER); -    signals[STOP_SCAN] = -        g_signal_new ("stop-scan", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (SimpleScanClass, stop_scan), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); -    signals[EMAIL] = -        g_signal_new ("email", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (SimpleScanClass, email), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__STRING, -                      G_TYPE_NONE, 1, G_TYPE_STRING); -    signals[QUIT] = -        g_signal_new ("quit", -                      G_TYPE_FROM_CLASS (klass), -                      G_SIGNAL_RUN_LAST, -                      G_STRUCT_OFFSET (SimpleScanClass, quit), -                      NULL, NULL, -                      g_cclosure_marshal_VOID__VOID, -                      G_TYPE_NONE, 0); - -    g_type_class_add_private (klass, sizeof (SimpleScanPrivate)); -} - - -static void -ui_init (SimpleScan *ui) -{ -    ui->priv = G_TYPE_INSTANCE_GET_PRIVATE (ui, SIMPLE_SCAN_TYPE, SimpleScanPrivate); - -    ui->priv->book = book_new (); -    g_signal_connect (ui->priv->book, "page-removed", G_CALLBACK (page_removed_cb), ui); -    g_signal_connect (ui->priv->book, "page-added", G_CALLBACK (page_added_cb), ui); -    -    ui->priv->client = gconf_client_get_default(); -    gconf_client_add_dir(ui->priv->client, GCONF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL); - -    ui->priv->document_hint = g_strdup ("photo"); -    ui->priv->default_file_name = g_strdup (_("Scanned Document.pdf")); -    ui->priv->scanning = FALSE; -    ui_load (ui); -} diff --git a/src/ui.h b/src/ui.h deleted file mode 100644 index d43c187..0000000 --- a/src/ui.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2009 Canonical Ltd. - * Author: Robert Ancell <robert.ancell@canonical.com> - *  - * This program 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 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _UI_H_ -#define _UI_H_ - -#include <glib-object.h> -#include "book.h" -#include "scanner.h" - -G_BEGIN_DECLS - -#define SIMPLE_SCAN_TYPE  (ui_get_type ()) -#define SIMPLE_SCAN(obj)  (G_TYPE_CHECK_INSTANCE_CAST ((obj), SIMPLE_SCAN_TYPE, SimpleScan)) - - -typedef struct SimpleScanPrivate SimpleScanPrivate; - -typedef struct -{ -    GObject             parent_instance; -    SimpleScanPrivate  *priv; -} SimpleScan; - -typedef struct -{ -    GObjectClass parent_class; - -    void (*start_scan) (SimpleScan *ui, ScanOptions *options); -    void (*stop_scan) (SimpleScan *ui); -    void (*email) (SimpleScan *ui, const gchar *profile); -    void (*quit) (SimpleScan *ui); -} SimpleScanClass; - - -GType ui_get_type (void); - -SimpleScan *ui_new (void); - -Book *ui_get_book (SimpleScan *ui); - -void ui_set_selected_page (SimpleScan *ui, Page *page); - -Page *ui_get_selected_page (SimpleScan *ui); - -void ui_set_default_file_name (SimpleScan *ui, const gchar *default_file_name); - -void ui_authorize (SimpleScan *ui, const gchar *resource, gchar **username, gchar **password); - -void ui_set_scan_devices (SimpleScan *ui, GList *devices); - -gchar *ui_get_selected_device (SimpleScan *ui); - -void ui_set_selected_device (SimpleScan *ui, const gchar *device); - -void ui_set_scanning (SimpleScan *ui, gboolean scanning); - -void ui_show_error (SimpleScan *ui, const gchar *error_title, const gchar *error_text, gboolean change_scanner_hint); - -void ui_start (SimpleScan *ui); - -#endif /* _UI_H_ */ diff --git a/src/ui.vala b/src/ui.vala new file mode 100644 index 0000000..4287d13 --- /dev/null +++ b/src/ui.vala @@ -0,0 +1,1458 @@ +/* + * Copyright (C) 2009-2011 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com> + * + * This program 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 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +public class SimpleScan +{ +    private const int DEFAULT_TEXT_DPI = 150; +    private const int DEFAULT_PHOTO_DPI = 300; + +    private Settings settings; + +    private Gtk.Builder builder; + +    private Gtk.Window window; +    private Gtk.VBox main_vbox; +    private Gtk.InfoBar info_bar; +    private Gtk.Image info_bar_image; +    private Gtk.Label info_bar_label; +    private Gtk.Button info_bar_close_button; +    private Gtk.Button info_bar_change_scanner_button; +    private Gtk.MenuItem page_move_left_menuitem; +    private Gtk.MenuItem page_move_right_menuitem; +    private Gtk.MenuItem page_delete_menuitem; +    private Gtk.MenuItem crop_rotate_menuitem; +    private Gtk.MenuItem save_menuitem; +    private Gtk.MenuItem save_as_menuitem; +    private Gtk.ToolButton save_toolbutton; +    private Gtk.MenuItem stop_menuitem; +    private Gtk.ToolButton stop_toolbutton; + +    private Gtk.RadioMenuItem text_toolbar_menuitem; +    private Gtk.RadioMenuItem text_menu_menuitem; +    private Gtk.RadioMenuItem photo_toolbar_menuitem; +    private Gtk.RadioMenuItem photo_menu_menuitem; + +    private Gtk.Dialog authorize_dialog; +    private Gtk.Label authorize_label; +    private Gtk.Entry username_entry; +    private Gtk.Entry password_entry; + +    private Gtk.Dialog preferences_dialog; +    private Gtk.ComboBox device_combo; +    private Gtk.ComboBox text_dpi_combo; +    private Gtk.ComboBox photo_dpi_combo; +    private Gtk.ComboBox page_side_combo; +    private Gtk.ComboBox paper_size_combo; +    private Gtk.ListStore device_model; +    private Gtk.ListStore text_dpi_model; +    private Gtk.ListStore photo_dpi_model; +    private Gtk.ListStore page_side_model; +    private Gtk.ListStore paper_size_model; +    private bool setting_devices; +    private bool user_selected_device; + +    private Gtk.FileChooserDialog? save_dialog; + +    private bool have_error; +    private string error_title; +    private string error_text; +    private bool error_change_scanner_hint; + +    private Book book; +    private string? book_uri = null; + +    private BookView book_view; +    private bool updating_page_menu; +    private int default_page_width; +    private int default_page_height; +    private int default_page_dpi; +    private ScanDirection default_page_scan_direction; + +    private string document_hint = "photo"; + +    private string default_file_name = _("Scanned Document.pdf"); +    private bool scanning = false; + +    private int window_width; +    private int window_height; +    private bool window_is_maximized; + +    public signal void start_scan (string? device, ScanOptions options); +    public signal void stop_scan (); +    public signal void email (string profile); +    public signal void quit (); + +    public SimpleScan () +    { +        book = new Book (); +        book.page_removed.connect (page_removed_cb); +        book.page_added.connect (page_added_cb); + +        settings = new Settings ("org.gnome.SimpleScan"); + +        load (); +    } + +    private bool find_scan_device (string device, out Gtk.TreeIter iter) +    { +        bool have_iter = false; + +        if (device_model.get_iter_first (out iter)) +        { +            do +            { +                string d; +                device_model.get (iter, 0, out d, -1); +                if (d == device) +                    have_iter = true; +            } while (!have_iter && device_model.iter_next (ref iter)); +        } + +        return have_iter; +    } + +    private void show_error_dialog (string error_title, string error_text) +    { +        var dialog = new Gtk.MessageDialog (window, +                                            Gtk.DialogFlags.MODAL, +                                            Gtk.MessageType.WARNING, +                                            Gtk.ButtonsType.NONE, +                                            "%s", error_title); +        dialog.add_button (Gtk.Stock.CLOSE, 0); +        dialog.format_secondary_text ("%s", error_text); +        dialog.destroy (); +    } + +    public void set_default_file_name (string default_file_name) +    { +        this.default_file_name = default_file_name; +    } + +    public void authorize (string resource, out string username, out string password) +    { +        /* Label in authorization dialog.  '%s' is replaced with the name of the resource requesting authorization */ +        var description = _("Username and password required to access '%s'").printf (resource); + +        username_entry.set_text (""); +        password_entry.set_text (""); +        authorize_label.set_text (description); + +        authorize_dialog.show (); +        authorize_dialog.run (); +        authorize_dialog.hide (); + +        username = username_entry.get_text (); +        password = password_entry.get_text (); +    } + +    [CCode (cname = "G_MODULE_EXPORT device_combo_changed_cb", instance_pos = -1)] +    public void device_combo_changed_cb (Gtk.Widget widget) +    { +        if (setting_devices) +            return; +        user_selected_device = true; +    } + +    private void update_info_bar () +    { +        Gtk.MessageType type; +        string title, text, image_id; +        bool show_close_button = false; +        bool show_change_scanner_button = false; + +        if (have_error) +        { +            type = Gtk.MessageType.ERROR; +            image_id = Gtk.Stock.DIALOG_ERROR; +            title = error_title; +            text = error_text; +            show_close_button = true; +            show_change_scanner_button = error_change_scanner_hint; +        } +        else if (device_model.iter_n_children (null) == 0) +        { +            type = Gtk.MessageType.WARNING; +            image_id = Gtk.Stock.DIALOG_WARNING; +            /* Warning displayed when no scanners are detected */ +            title = _("No scanners detected"); +            /* Hint to user on why there are no scanners detected */ +            text = _("Please check your scanner is connected and powered on"); +        } +        else +        { +            info_bar.hide (); +            return; +        } + +        info_bar.set_message_type (type); +        info_bar_image.set_from_stock (image_id, Gtk.IconSize.DIALOG); +        var message = "<big><b>%s</b></big>\n\n%s".printf (title, text); +        info_bar_label.set_markup (message); +        info_bar_close_button.set_visible (show_close_button); +        info_bar_change_scanner_button.set_visible (show_change_scanner_button); +        info_bar.show (); +    } + +    public void set_scan_devices (List<ScanDevice> devices) +    { +        bool have_selection = false; +        int index; +        Gtk.TreeIter iter; + +        setting_devices = true; + +        /* If the user hasn't chosen a scanner choose the best available one */ +        if (user_selected_device) +            have_selection = device_combo.get_active () >= 0; + +        /* Add new devices */ +        index = 0; +        foreach (var device in devices) +        { +            int n_delete = -1; + +            /* Find if already exists */ +            if (device_model.iter_nth_child (out iter, null, index)) +            { +                int i = 0; +                do +                { +                    string name; +                    bool matched; + +                    device_model.get (iter, 0, out name, -1); +                    matched = name == device.name; + +                    if (matched) +                    { +                        n_delete = i; +                        break; +                    } +                    i++; +                } while (device_model.iter_next (ref iter)); +            } + +            /* If exists, remove elements up to this one */ +            if (n_delete >= 0) +            { +                int i; + +                /* Update label */ +                device_model.set (iter, 1, device.label, -1); + +                for (i = 0; i < n_delete; i++) +                { +                    device_model.iter_nth_child (out iter, null, index); +                    device_model.remove (iter); +                } +            } +            else +            { +                device_model.insert (out iter, index); +                device_model.set (iter, 0, device.name, 1, device.label, -1); +            } +            index++; +        } + +        /* Remove any remaining devices */ +        while (device_model.iter_nth_child (out iter, null, index)) +            device_model.remove (iter); + +        /* Select the first available device */ +        if (!have_selection && devices != null) +            device_combo.set_active (0); + +        setting_devices = false; + +        update_info_bar (); +    } + +    private string? get_selected_device () +    { +        Gtk.TreeIter iter; + +        if (device_combo.get_active_iter (out iter)) +        { +            string device; +            device_model.get (iter, 0, out device, -1); +            return device; +        } + +        return null; +    } + +    public void set_selected_device (string device) +    { +        Gtk.TreeIter iter; +        if (!find_scan_device (device, out iter)) +            return; + +        device_combo.set_active_iter (iter); +        user_selected_device = true; +    } + +    private void add_default_page () +    { +        var page = book.append_page (default_page_width, +                                     default_page_height, +                                     default_page_dpi, +                                     default_page_scan_direction); +        book_view.select_page (page); +    } + +    private void on_file_type_changed (Gtk.TreeSelection selection) +    { +        Gtk.TreeModel model; +        Gtk.TreeIter iter; +        if (!selection.get_selected (out model, out iter)) +            return; + +        string extension; +        model.get (iter, 1, out extension, -1); +        var path = save_dialog.get_filename (); +        var filename = Path.get_basename (path); + +        /* Replace extension */ +        var extension_index = filename.last_index_of_char ('.'); +        if (extension_index >= 0) +            filename = filename.slice (0, extension_index); +        filename = filename + extension; +        save_dialog.set_current_name (filename); +    } + +    private string choose_file_location () +    { +        /* Get directory to save to */ +        string? directory = null; +        directory = settings.get_string ("save-directory"); +             +        if (directory == null || directory == "") +            directory = Environment.get_user_special_dir (UserDirectory.DOCUMENTS); + +        save_dialog = new Gtk.FileChooserDialog (/* Save dialog: Dialog title */ +                                                 _("Save As..."), +                                                 window, +                                                 Gtk.FileChooserAction.SAVE, +                                                 Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL, +                                                 Gtk.Stock.SAVE, Gtk.ResponseType.ACCEPT, +                                                 null); +        save_dialog.set_do_overwrite_confirmation (true); +        save_dialog.set_local_only (false); +        save_dialog.set_current_folder (directory); +        save_dialog.set_current_name (default_file_name); + +        /* Filter to only show images by default */ +        var filter = new Gtk.FileFilter (); +        filter.set_name (/* Save dialog: Filter name to show only image files */ +                         _("Image Files")); +        filter.add_pixbuf_formats (); +        filter.add_mime_type ("application/pdf"); +        save_dialog.add_filter (filter); +        filter = new Gtk.FileFilter (); +        filter.set_name (/* Save dialog: Filter name to show all files */ +                         _("All Files")); +        filter.add_pattern ("*"); +        save_dialog.add_filter (filter); + +        var expander = new Gtk.Expander.with_mnemonic (/* */ +                                                       _("Select File _Type")); +        expander.set_spacing (5); +        save_dialog.set_extra_widget (expander); + +        string extension = ""; +        var index = default_file_name.last_index_of_char ('.'); +        if (index >= 0) +            extension = default_file_name.slice (0, index); + +        var file_type_store = new Gtk.ListStore (2, typeof (string), typeof (string)); +        Gtk.TreeIter iter; +        file_type_store.append (out iter); +        file_type_store.set (iter, +                             /* Save dialog: Label for saving in PDF format */ +                             0, _("PDF (multi-page document)"), +                             1, ".pdf", +                             -1); +        file_type_store.append (out iter); +        file_type_store.set (iter, +                             /* Save dialog: Label for saving in JPEG format */ +                             0, _("JPEG (compressed)"), +                             1, ".jpg", +                             -1); +        file_type_store.append (out iter); +        file_type_store.set (iter, +                             /* Save dialog: Label for saving in PNG format */ +                             0, _("PNG (lossless)"), +                             1, ".png", +                             -1); + +        var file_type_view = new Gtk.TreeView.with_model (file_type_store); +        file_type_view.set_headers_visible (false); +        file_type_view.set_rules_hint (true); +        var column = new Gtk.TreeViewColumn.with_attributes ("", +                                                             new Gtk.CellRendererText (), +                                                             "text", 0, null); +        file_type_view.append_column (column); +        expander.add (file_type_view); + +        if (file_type_store.get_iter_first (out iter)) +        { +            do +            { +                string e; +                file_type_store.get (iter, 1, out e, -1); +                if (extension == e) +                    file_type_view.get_selection ().select_iter (iter); +            } while (file_type_store.iter_next (ref iter)); +        } +        file_type_view.get_selection ().changed.connect (on_file_type_changed); + +        expander.show_all (); + +        var response = save_dialog.run (); + +        string? uri = null; +        if (response == Gtk.ResponseType.ACCEPT) +            uri = save_dialog.get_uri (); + +        settings.set_string ("save-directory", save_dialog.get_current_folder ()); + +        save_dialog.destroy (); +        save_dialog = null; + +        return uri; +    } + +    private bool save_document (bool force_choose_location) +    { +        string? uri; +        if (book_uri != null && !force_choose_location) +            uri = book_uri; +        else +            uri = choose_file_location (); +        if (uri == null) +            return false; + +        var file = File.new_for_uri (uri); + +        debug ("Saving to '%s'", uri); + +        var uri_lower = uri.down (); +        string format = "jpeg"; +        if (uri_lower.has_suffix (".pdf")) +            format = "pdf"; +        else if (uri_lower.has_suffix (".ps")) +            format = "ps"; +        else if (uri_lower.has_suffix (".png")) +            format = "png"; +        else if (uri_lower.has_suffix (".tif") || uri_lower.has_suffix (".tiff")) +            format = "tiff"; + +        try +        { +            book.save (format, file); +        } +        catch (Error e) +        { +            warning ("Error saving file: %s", e.message); +            show_error (/* Title of error dialog when save failed */ +                        _("Failed to save file"), +                        e.message, +                        false); +            return false; +        } + +        book_uri = uri; +        book.set_needs_saving (false); +        return true; +    } + +    private bool prompt_to_save (string title, string discard_label) +    { +        if (!book.get_needs_saving ()) +            return true; + +        var dialog = new Gtk.MessageDialog (window, +                                            Gtk.DialogFlags.MODAL, +                                            Gtk.MessageType.WARNING, +                                            Gtk.ButtonsType.NONE, +                                            "%s", title); +        dialog.format_secondary_text ("%s", +                                      /* Text in dialog warning when a document is about to be lost*/ +                                      _("If you don't save, changes will be permanently lost.")); +        dialog.add_button (discard_label, Gtk.ResponseType.NO); +        dialog.add_button (Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL); +        dialog.add_button (Gtk.Stock.SAVE, Gtk.ResponseType.YES); + +        var response = dialog.run (); +        dialog.destroy (); + +        switch (response) +        { +        case Gtk.ResponseType.YES: +            if (save_document (false)) +                return true; +            else +                return false; +        case Gtk.ResponseType.CANCEL: +            return false; +        case Gtk.ResponseType.NO: +        default: +            return true; +        } +    } + +    private void clear_document () +    { +        book.clear (); +        add_default_page (); +        book_uri = null; +        book.set_needs_saving (false); +        save_as_menuitem.set_sensitive (false); +    } + +    [CCode (cname = "G_MODULE_EXPORT new_button_clicked_cb", instance_pos = -1)] +    public void new_button_clicked_cb (Gtk.Widget widget) +    { +        if (!prompt_to_save (/* Text in dialog warning when a document is about to be lost */ +                             _("Save current document?"), +                             /* Button in dialog to create new document and discard unsaved document */ +                             _("Discard Changes"))) +            return; + +        clear_document (); +    } + +    private void set_document_hint (string document_hint) +    { +        this.document_hint = document_hint; + +        if (document_hint == "text") +        { +            text_toolbar_menuitem.set_active (true); +            text_menu_menuitem.set_active (true); +        } +        else if (document_hint == "photo") +        { +            photo_toolbar_menuitem.set_active (true); +            photo_menu_menuitem.set_active (true); +        } +    } + +    [CCode (cname = "G_MODULE_EXPORT text_menuitem_toggled_cb", instance_pos = -1)] +    public void text_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_document_hint ("text"); +    } + +    [CCode (cname = "G_MODULE_EXPORT photo_menuitem_toggled_cb", instance_pos = -1)] +    public void photo_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_document_hint ("photo"); +    } + +    private void set_page_side (ScanType page_side) +    { +        Gtk.TreeIter iter; + +        if (page_side_model.get_iter_first (out iter)) +        { +            do +            { +                int s; +                page_side_model.get (iter, 0, out s, -1); +                if (s == page_side) +                { +                    page_side_combo.set_active_iter (iter); +                    return; +                } +            } while (page_side_model.iter_next (ref iter)); +         } +    } + +    private void set_paper_size (int width, int height) +    { +        Gtk.TreeIter iter; +        bool have_iter; + +        for (have_iter = paper_size_model.get_iter_first (out iter); +             have_iter; +             have_iter = paper_size_model.iter_next (ref iter)) +        { +            int w, h; +            paper_size_model.get (iter, 0, out w, 1, out h, -1); +            if (w == width && h == height) +               break; +        } + +        if (!have_iter) +            have_iter = paper_size_model.get_iter_first (out iter); +        if (have_iter) +            paper_size_combo.set_active_iter (iter); +    } + +    private int get_text_dpi () +    { +        Gtk.TreeIter iter; +        int dpi = DEFAULT_TEXT_DPI; + +        if (text_dpi_combo.get_active_iter (out iter)) +            text_dpi_model.get (iter, 0, out dpi, -1); + +        return dpi; +    } + +    private int get_photo_dpi () +    { +        Gtk.TreeIter iter; +        int dpi = DEFAULT_PHOTO_DPI; + +        if (photo_dpi_combo.get_active_iter (out iter)) +            photo_dpi_model.get (iter, 0, out dpi, -1); + +        return dpi; +    } + +    private ScanType get_page_side () +    { +        Gtk.TreeIter iter; +        int page_side = ScanType.ADF_BOTH; + +        if (page_side_combo.get_active_iter (out iter)) +            page_side_model.get (iter, 0, out page_side, -1); + +        return (ScanType) page_side; +    } + +    private bool get_paper_size (out int width, out int height) +    { +        Gtk.TreeIter iter; + +        if (paper_size_combo.get_active_iter (out iter)) +        { +            paper_size_model.get (iter, 0, ref width, 1, ref height, -1); +            return true; +        } + +        return false; +    } + +    private ScanOptions get_scan_options () +    { +        var options = new ScanOptions (); +        if (document_hint == "text") +        { +            options.scan_mode = ScanMode.GRAY; +            options.dpi = get_text_dpi (); +            options.depth = 2; +        } +        else +        { +            options.scan_mode = ScanMode.COLOR; +            options.dpi = get_photo_dpi (); +            options.depth = 8; +        } +        get_paper_size (out options.paper_width, out options.paper_height); + +        return options; +    } + +    [CCode (cname = "G_MODULE_EXPORT scan_button_clicked_cb", instance_pos = -1)] +    public void scan_button_clicked_cb (Gtk.Widget widget) +    { +        var options = get_scan_options (); +        options.type = ScanType.SINGLE; +        start_scan (get_selected_device (), options); +    } + +    [CCode (cname = "G_MODULE_EXPORT stop_scan_button_clicked_cb", instance_pos = -1)] +    public void stop_scan_button_clicked_cb (Gtk.Widget widget) +    { +        stop_scan (); +    } + +    [CCode (cname = "G_MODULE_EXPORT continuous_scan_button_clicked_cb", instance_pos = -1)] +    public void continuous_scan_button_clicked_cb (Gtk.Widget widget) +    { +        if (scanning) +            stop_scan (); +        else +        { +            var options = get_scan_options (); +            options.type = get_page_side (); +            start_scan (get_selected_device (), options); +        } +    } + +    [CCode (cname = "G_MODULE_EXPORT preferences_button_clicked_cb", instance_pos = -1)] +    public void preferences_button_clicked_cb (Gtk.Widget widget) +    { +        preferences_dialog.present (); +    } + +    [CCode (cname = "G_MODULE_EXPORT preferences_dialog_delete_event_cb", instance_pos = -1)] +    public bool preferences_dialog_delete_event_cb (Gtk.Widget widget) +    { +        return true; +    } + +    [CCode (cname = "G_MODULE_EXPORT preferences_dialog_response_cb", instance_pos = -1)] +    public void preferences_dialog_response_cb (Gtk.Widget widget, int response_id) +    { +        preferences_dialog.hide (); +    } + +    private void update_page_menu () +    { +        var page = book_view.get_selected (); +        if (page == null) +        { +            page_move_left_menuitem.set_sensitive (false); +            page_move_right_menuitem.set_sensitive (false); +        } +        else +        { +            var index = book.get_page_index (page); +            page_move_left_menuitem.set_sensitive (index > 0); +            page_move_right_menuitem.set_sensitive (index < book.get_n_pages () - 1); +        } +    } + +    private void page_selected_cb (BookView view, Page? page) +    { +        if (page == null) +            return; + +        updating_page_menu = true; + +        update_page_menu (); + +        string? name = null; +        if (page.has_crop ()) +        { +            // FIXME: Make more generic, move into page-size.c and reuse +            var crop_name = page.get_named_crop (); +            if (crop_name != null) +            { +                if (crop_name == "A4") +                    name = "a4_menuitem"; +                else if (crop_name == "A5") +                    name = "a5_menuitem"; +                else if (crop_name == "A6") +                    name = "a6_menuitem"; +                else if (crop_name == "letter") +                    name = "letter_menuitem"; +                else if (crop_name == "legal") +                    name = "legal_menuitem"; +                else if (crop_name == "4x6") +                    name = "4x6_menuitem"; +            } +            else +                name = "custom_crop_menuitem"; +        } +        else +            name = "no_crop_menuitem"; + +        var menuitem = (Gtk.RadioMenuItem) builder.get_object (name); +        menuitem.set_active (true); +        var toolbutton = (Gtk.ToggleToolButton) builder.get_object ("crop_toolbutton"); +        toolbutton.set_active (page.has_crop ()); + +        updating_page_menu = false; +    } + +    // FIXME: Duplicated from simple-scan.vala +    private string? get_temporary_filename (string prefix, string extension) +    { +        /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and +         * use the filename but it appears to work in practise */ + +        var filename = "%sXXXXXX.%s".printf (prefix, extension); +        string path; +        try +        { +            var fd = FileUtils.open_tmp (filename, out path); +            Posix.close (fd); +        } +        catch (Error e) +        { +            warning ("Error saving email attachment: %s", e.message); +            return null; +        } + +        return path; +    } + +    private void show_page_cb (BookView view, Page page) +    { +        var path = get_temporary_filename ("scanned-page", "tiff"); +        if (path == null) +            return; +        var file = File.new_for_path (path); + +        try +        { +            page.save ("tiff", file); +        } +        catch (Error e) +        { +            show_error_dialog (/* Error message display when unable to save image for preview */ +                               _("Unable to save image for preview"), +                               e.message); +            return; +        } +         +        try +        { +            Gtk.show_uri (window.get_screen (), file.get_uri (), Gtk.get_current_event_time ()); +        } +        catch (Error e) +        { +            show_error_dialog (/* Error message display when unable to preview image */ +                               _("Unable to open image preview application"), +                               e.message); +        } +    } + +    private void show_page_menu_cb (BookView view) +    { +        var menu = (Gtk.Menu) builder.get_object ("page_menu"); +        menu.popup (null, null, null, 3, Gtk.get_current_event_time()); +    } + +    [CCode (cname = "G_MODULE_EXPORT rotate_left_button_clicked_cb", instance_pos = -1)] +    public void rotate_left_button_clicked_cb (Gtk.Widget widget) +    { +        if (updating_page_menu) +            return; +        var page = book_view.get_selected (); +        if (page != null) +            page.rotate_left (); +    } + +    [CCode (cname = "G_MODULE_EXPORT rotate_right_button_clicked_cb", instance_pos = -1)] +    public void rotate_right_button_clicked_cb (Gtk.Widget widget) +    { +        if (updating_page_menu) +            return; +        var page = book_view.get_selected (); +        if (page != null) +            page.rotate_right (); +    } + +    private void set_crop (string? crop_name) +    { +        crop_rotate_menuitem.set_sensitive (crop_name != null); + +        if (updating_page_menu) +            return; + +        var page = book_view.get_selected (); +        if (page == null) +            return; + +        if (crop_name == null) +        { +            page.set_no_crop (); +            return; +        } +        else if (crop_name == "custom") +        { +            var width = page.get_width (); +            var height = page.get_height (); +            var crop_width = (int) (width * 0.8 + 0.5); +            var crop_height = (int) (height * 0.8 + 0.5); +            page.set_custom_crop (crop_width, crop_height); +            page.move_crop ((width - crop_width) / 2, (height - crop_height) / 2); +        } +        else +            page.set_named_crop (crop_name); +    } + +    [CCode (cname = "G_MODULE_EXPORT no_crop_menuitem_toggled_cb", instance_pos = -1)] +    public void no_crop_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop (null); +    } + +    [CCode (cname = "G_MODULE_EXPORT custom_crop_menuitem_toggled_cb", instance_pos = -1)] +    public void custom_crop_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("custom"); +    } + +    [CCode (cname = "G_MODULE_EXPORT crop_toolbutton_toggled_cb", instance_pos = -1)] +    public void crop_toolbutton_toggled_cb (Gtk.ToggleToolButton widget) +    { +        if (updating_page_menu) +            return; + +        Gtk.RadioMenuItem menuitem; +        if (widget.get_active ()) +            menuitem = (Gtk.RadioMenuItem) builder.get_object ("custom_crop_menuitem"); +        else +            menuitem = (Gtk.RadioMenuItem) builder.get_object ("no_crop_menuitem"); +        menuitem.set_active (true); +    } + +    [CCode (cname = "G_MODULE_EXPORT four_by_six_menuitem_toggled_cb", instance_pos = -1)] +    public void four_by_six_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("4x6"); +    } + +    [CCode (cname = "G_MODULE_EXPORT legal_menuitem_toggled_cb", instance_pos = -1)] +    public void legal_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("legal"); +    } + +    [CCode (cname = "G_MODULE_EXPORT letter_menuitem_toggled_cb", instance_pos = -1)] +    public void letter_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("letter"); +    } + +    [CCode (cname = "G_MODULE_EXPORT a6_menuitem_toggled_cb", instance_pos = -1)] +    public void a6_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("A6"); +    } + +    [CCode (cname = "G_MODULE_EXPORT a5_menuitem_toggled_cb", instance_pos = -1)] +    public void a5_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("A5"); +    } + +    [CCode (cname = "G_MODULE_EXPORT a4_menuitem_toggled_cb", instance_pos = -1)] +    public void a4_menuitem_toggled_cb (Gtk.CheckMenuItem widget) +    { +        if (widget.get_active ()) +            set_crop ("A4"); +    } + +    [CCode (cname = "G_MODULE_EXPORT crop_rotate_menuitem_activate_cb", instance_pos = -1)] +    public void crop_rotate_menuitem_activate_cb (Gtk.Widget widget) +    { +        var page = book_view.get_selected (); +        if (page == null) +            return; +        page.rotate_crop (); +    } + +    [CCode (cname = "G_MODULE_EXPORT page_move_left_menuitem_activate_cb", instance_pos = -1)] +    public void page_move_left_menuitem_activate_cb (Gtk.Widget widget) +    { +        var page = book_view.get_selected (); +        var index = book.get_page_index (page); +        if (index > 0) +            book.move_page (page, index - 1); + +        update_page_menu (); +    } + +    [CCode (cname = "G_MODULE_EXPORT page_move_right_menuitem_activate_cb", instance_pos = -1)] +    public void page_move_right_menuitem_activate_cb (Gtk.Widget widget) +    { +        var page = book_view.get_selected (); +        var index = book.get_page_index (page); +        if (index < book.get_n_pages () - 1) +            book.move_page (page, book.get_page_index (page) + 1); + +        update_page_menu (); +    } + +    [CCode (cname = "G_MODULE_EXPORT page_delete_menuitem_activate_cb", instance_pos = -1)] +    public void page_delete_menuitem_activate_cb (Gtk.Widget widget) +    { +        book_view.get_book ().delete_page (book_view.get_selected ()); +    } + +    [CCode (cname = "G_MODULE_EXPORT save_file_button_clicked_cb", instance_pos = -1)] +    public void save_file_button_clicked_cb (Gtk.Widget widget) +    { +        save_document (false); +    } + +    [CCode (cname = "G_MODULE_EXPORT save_as_file_button_clicked_cb", instance_pos = -1)] +    public void save_as_file_button_clicked_cb (Gtk.Widget widget) +    { +        save_document (true); +    } + +    private void draw_page (Gtk.PrintOperation operation, +                            Gtk.PrintContext   print_context, +                            int                page_number) +    { +        var context = print_context.get_cairo_context (); +        var page = book.get_page (page_number); + +        /* Rotate to same aspect */ +        bool is_landscape = false; +        if (print_context.get_width () > print_context.get_height ()) +            is_landscape = true; +        if (page.is_landscape () != is_landscape) +        { +            context.translate (print_context.get_width (), 0); +            context.rotate (Math.PI_2); +        } + +        context.scale (print_context.get_dpi_x () / page.get_dpi (), +                       print_context.get_dpi_y () / page.get_dpi ()); + +        var image = page.get_image (true); +        Gdk.cairo_set_source_pixbuf (context, image, 0, 0); +        context.paint (); +    } + +    [CCode (cname = "G_MODULE_EXPORT email_button_clicked_cb", instance_pos = -1)] +    public void email_button_clicked_cb (Gtk.Widget widget) +    { +        email (document_hint); +    } + +    [CCode (cname = "G_MODULE_EXPORT print_button_clicked_cb", instance_pos = -1)] +    public void print_button_clicked_cb (Gtk.Widget widget) +    { +        var print = new Gtk.PrintOperation (); +        print.set_n_pages ((int) book.get_n_pages ()); +        print.draw_page.connect (draw_page); + +        try +        { +            print.run (Gtk.PrintOperationAction.PRINT_DIALOG, window); +        } +        catch (Error e) +        { +            warning ("Error printing: %s", e.message); +        } +    } + +    [CCode (cname = "G_MODULE_EXPORT help_contents_menuitem_activate_cb", instance_pos = -1)] +    public void help_contents_menuitem_activate_cb (Gtk.Widget widget) +    { +        try +        { +            Gtk.show_uri (window.get_screen (), "ghelp:simple-scan", Gtk.get_current_event_time ()); +        } +        catch (Error e) +        { +            show_error_dialog (/* Error message displayed when unable to launch help browser */ +                               _("Unable to open help file"), +                               e.message); +        } +    } + +    [CCode (cname = "G_MODULE_EXPORT about_menuitem_activate_cb", instance_pos = -1)] +    public void about_menuitem_activate_cb (Gtk.Widget widget) +    { +        string[] authors = { "Robert Ancell <robert.ancell@canonical.com>" }; + +        /* The license this software is under (GPL3+) */ +        string license = _("This program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <http://www.gnu.org/licenses/>."); + +        /* Title of about dialog */ +        string title = _("About Simple Scan"); + +        /* Description of program */ +        string description = _("Simple document scanning tool"); + +        Gtk.show_about_dialog (window, +                               "title", title, +                               "program-name", "Simple Scan", +                               "version", Config.VERSION, +                               "comments", description, +                               "logo-icon-name", "scanner", +                               "authors", authors, +                               "translator-credits", _("translator-credits"), +                               "website", "https://launchpad.net/simple-scan", +                               "copyright", "Copyright © 2009-2011 Canonical Ltd.", +                               "license", license, +                               "wrap-license", true, +                               null); +    } + +    private bool on_quit () +    { +        if (!prompt_to_save (/* Text in dialog warning when a document is about to be lost */ +                             _("Save document before quitting?"), +                             /* Button in dialog to quit and discard unsaved document */ +                             _("Quit without Saving"))) +            return false; + +        var device = get_selected_device (); +        int paper_width = 0, paper_height = 0; +        get_paper_size (out paper_width, out paper_height); + +        if (device != null) +            settings.set_string ("selected-device", device); +        settings.set_string ("document-type", document_hint); +        settings.set_int ("text-dpi", get_text_dpi ()); +        settings.set_int ("photo-dpi", get_photo_dpi ()); +        settings.set_enum ("page-side", get_page_side ()); +        settings.set_int ("paper-width", paper_width); +        settings.set_int ("paper-height", paper_height); +        settings.set_int ("window-width", window_width); +        settings.set_int ("window-height", window_height); +        settings.set_boolean ("window-is-maximized", window_is_maximized); +        settings.set_enum ("scan-direction", default_page_scan_direction); +        settings.set_int ("page-width", default_page_width); +        settings.set_int ("page-height", default_page_height); +        settings.set_int ("page-dpi", default_page_dpi); + +        quit (); + +        return true; +    } + +    [CCode (cname = "G_MODULE_EXPORT quit_menuitem_activate_cb", instance_pos = -1)] +    public void quit_menuitem_activate_cb (Gtk.Widget widget) +    { +        on_quit (); +    } + +    [CCode (cname = "G_MODULE_EXPORT simple_scan_window_configure_event_cb", instance_pos = -1)] +    public bool simple_scan_window_configure_event_cb (Gtk.Widget widget, Gdk.EventConfigure event) +    { +        if (!window_is_maximized) +        { +            window_width = event.width; +            window_height = event.height; +        } + +        return false; +    } + +    private void info_bar_response_cb (Gtk.InfoBar widget, int response_id) +    { +        if (response_id == 1) +        { +            device_combo.grab_focus (); +            preferences_dialog.present (); +        } +        else +        { +            have_error = false; +            error_title = null; +            error_text = null; +            update_info_bar (); +        } +    } + +    [CCode (cname = "G_MODULE_EXPORT simple_scan_window_window_state_event_cb", instance_pos = -1)] +    public bool simple_scan_window_window_state_event_cb (Gtk.Widget widget, Gdk.EventWindowState event) +    { +        if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0) +            window_is_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0; +        return false; +    } + +    [CCode (cname = "G_MODULE_EXPORT window_delete_event_cb", instance_pos = -1)] +    public bool window_delete_event_cb (Gtk.Widget widget, Gdk.Event event) +    { +        return !on_quit (); +    } + +    private void page_size_changed_cb (Page page) +    { +        default_page_width = page.get_width (); +        default_page_height = page.get_height (); +        default_page_dpi = page.get_dpi (); +    } + +    private void page_scan_direction_changed_cb (Page page) +    { +        default_page_scan_direction = page.get_scan_direction (); +    } + +    private void page_added_cb (Book book, Page page) +    { +        default_page_width = page.get_width (); +        default_page_height = page.get_height (); +        default_page_dpi = page.get_dpi (); +        default_page_scan_direction = page.get_scan_direction (); +        page.size_changed.connect (page_size_changed_cb); +        page.scan_direction_changed.connect (page_scan_direction_changed_cb); + +        update_page_menu (); +    } + +    private void page_removed_cb (Book book, Page page) +    { +        /* If this is the last page add a new blank one */ +        if (book.get_n_pages () == 1) +            add_default_page (); + +        update_page_menu (); +    } + +    private void set_dpi_combo (Gtk.ComboBox combo, int default_dpi, int current_dpi) +    { +        var renderer = new Gtk.CellRendererText (); +        combo.pack_start (renderer, true); +        combo.add_attribute (renderer, "text", 1); + +        var model = (Gtk.ListStore) combo.get_model (); +        int[] scan_resolutions = {75, 150, 300, 600, 1200, 2400}; +        foreach (var dpi in scan_resolutions) +        { +            string label; +            if (dpi == default_dpi) +                /* Preferences dialog: Label for default resolution in resolution list */ +                label = _("%d dpi (default)").printf (dpi); +            else if (dpi == 75) +                /* Preferences dialog: Label for minimum resolution in resolution list */ +                label = _("%d dpi (draft)").printf (dpi); +            else if (dpi == 1200) +                /* Preferences dialog: Label for maximum resolution in resolution list */ +                label = _("%d dpi (high resolution)").printf (dpi); +            else +                /* Preferences dialog: Label for resolution value in resolution list (dpi = dots per inch) */ +                label = _("%d dpi").printf (dpi); + +            Gtk.TreeIter iter; +            model.append (out iter); +            model.set (iter, 0, dpi, 1, label, -1); + +            if (dpi == current_dpi) +                combo.set_active_iter (iter); +        } +    } + +    private void needs_saving_cb (Book book) +    { +        save_menuitem.set_sensitive (book.get_needs_saving ()); +        save_toolbutton.set_sensitive (book.get_needs_saving ()); +        if (book.get_needs_saving ()) +            save_as_menuitem.set_sensitive (true); +    } + +    private void load () +    { +        Gtk.IconTheme.get_default ().append_search_path (Config.ICON_DIR); + +        Gtk.Window.set_default_icon_name ("scanner"); + +        builder = new Gtk.Builder (); +        var filename = Path.build_filename (Config.UI_DIR, "simple-scan.ui", null); +        try +        { +            builder.add_from_file (filename); +        } +        catch (Error e) +        { +            critical ("Unable to load UI %s: %s\n", filename, e.message); +            show_error_dialog (/* Title of dialog when cannot load required files */ +                               _("Files missing"), +                               /* Description in dialog when cannot load required files */ +                               _("Please check your installation")); +            Posix.exit (Posix.EXIT_FAILURE); +        } +        builder.connect_signals (this); + +        window = (Gtk.Window) builder.get_object ("simple_scan_window"); +        main_vbox = (Gtk.VBox) builder.get_object ("main_vbox"); +        page_move_left_menuitem = (Gtk.MenuItem) builder.get_object ("page_move_left_menuitem"); +        page_move_right_menuitem = (Gtk.MenuItem) builder.get_object ("page_move_right_menuitem"); +        page_delete_menuitem = (Gtk.MenuItem) builder.get_object ("page_delete_menuitem"); +        crop_rotate_menuitem = (Gtk.MenuItem) builder.get_object ("crop_rotate_menuitem"); +        save_menuitem = (Gtk.MenuItem) builder.get_object ("save_menuitem"); +        save_as_menuitem = (Gtk.MenuItem) builder.get_object ("save_as_menuitem"); +        save_toolbutton = (Gtk.ToolButton) builder.get_object ("save_toolbutton"); +        stop_menuitem = (Gtk.MenuItem) builder.get_object ("stop_scan_menuitem"); +        stop_toolbutton = (Gtk.ToolButton) builder.get_object ("stop_toolbutton"); + +        text_toolbar_menuitem = (Gtk.RadioMenuItem) builder.get_object ("text_toolbutton_menuitem"); +        text_menu_menuitem = (Gtk.RadioMenuItem) builder.get_object ("text_menuitem"); +        photo_toolbar_menuitem = (Gtk.RadioMenuItem) builder.get_object ("photo_toolbutton_menuitem"); +        photo_menu_menuitem = (Gtk.RadioMenuItem) builder.get_object ("photo_menuitem"); + +        authorize_dialog = (Gtk.Dialog) builder.get_object ("authorize_dialog"); +        authorize_label = (Gtk.Label) builder.get_object ("authorize_label"); +        username_entry = (Gtk.Entry) builder.get_object ("username_entry"); +        password_entry = (Gtk.Entry) builder.get_object ("password_entry"); + +        preferences_dialog = (Gtk.Dialog) builder.get_object ("preferences_dialog"); +        device_combo = (Gtk.ComboBox) builder.get_object ("device_combo"); +        device_model = (Gtk.ListStore) device_combo.get_model (); +        text_dpi_combo = (Gtk.ComboBox) builder.get_object ("text_dpi_combo"); +        text_dpi_model = (Gtk.ListStore) text_dpi_combo.get_model (); +        photo_dpi_combo = (Gtk.ComboBox) builder.get_object ("photo_dpi_combo"); +        photo_dpi_model = (Gtk.ListStore) photo_dpi_combo.get_model (); +        page_side_combo = (Gtk.ComboBox) builder.get_object ("page_side_combo"); +        page_side_model = (Gtk.ListStore) page_side_combo.get_model (); +        paper_size_combo = (Gtk.ComboBox) builder.get_object ("paper_size_combo"); +        paper_size_model = (Gtk.ListStore) paper_size_combo.get_model (); + +        /* Add InfoBar (not supported in Glade) */ +        info_bar = new Gtk.InfoBar (); +        info_bar.response.connect (info_bar_response_cb); +        main_vbox.pack_start (info_bar, false, true, 0); +        var hbox = new Gtk.HBox (false, 12); +        var content_area = (Gtk.Container) info_bar.get_content_area (); +        content_area.add (hbox); +        hbox.show (); + +        info_bar_image = new Gtk.Image.from_stock (Gtk.Stock.DIALOG_WARNING, Gtk.IconSize.DIALOG); +        hbox.pack_start (info_bar_image, false, true, 0); +        info_bar_image.show (); + +        info_bar_label = new Gtk.Label (null); +        info_bar_label.set_alignment (0.0f, 0.5f); +        hbox.pack_start (info_bar_label, true, true, 0); +        info_bar_label.show (); + +        info_bar_close_button = (Gtk.Button) info_bar.add_button (Gtk.Stock.CLOSE, Gtk.ResponseType.CLOSE); +        info_bar_change_scanner_button = (Gtk.Button) info_bar.add_button (/* Button in error infobar to open preferences dialog and change scanner */ +                                                                           _("Change _Scanner"), 1); + +        Gtk.TreeIter iter; +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 0, 1, 0, 2, +                              /* Combo box value for automatic paper size */ +                              _("Automatic"), -1); +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 1050, 1, 1480, 2, "A6", -1); +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 1480, 1, 2100, 2, "A5", -1); +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 2100, 1, 2970, 2, "A4", -1); +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 2159, 1, 2794, 2, "Letter", -1); +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 2159, 1, 3556, 2, "Legal", -1); +        paper_size_model.append (out iter); +        paper_size_model.set (iter, 0, 1016, 1, 1524, 2, "4×6", -1); + +        var dpi = settings.get_int ("text-dpi"); +        if (dpi <= 0) +            dpi = DEFAULT_TEXT_DPI; +        set_dpi_combo (text_dpi_combo, DEFAULT_TEXT_DPI, dpi); +        dpi = settings.get_int ("photo-dpi"); +        if (dpi <= 0) +            dpi = DEFAULT_PHOTO_DPI; +        set_dpi_combo (photo_dpi_combo, DEFAULT_PHOTO_DPI, dpi); + +        var renderer = new Gtk.CellRendererText (); +        device_combo.pack_start (renderer, true); +        device_combo.add_attribute (renderer, "text", 1); + +        renderer = new Gtk.CellRendererText (); +        page_side_combo.pack_start (renderer, true); +        page_side_combo.add_attribute (renderer, "text", 1); +        set_page_side ((ScanType) settings.get_enum ("page-side")); + +        renderer = new Gtk.CellRendererText (); +        paper_size_combo.pack_start (renderer, true); +        paper_size_combo.add_attribute (renderer, "text", 2); +        var paper_width = settings.get_int ("paper-width"); +        var paper_height = settings.get_int ("paper-height"); +        set_paper_size (paper_width, paper_height); + +        var device = settings.get_string ("selected-device"); +        if (device != null) +        { +            if (find_scan_device (device, out iter)) +                device_combo.set_active_iter (iter); +        } + +        var document_type = settings.get_string ("document-type"); +        if (document_type != null) +            set_document_hint (document_type); + +        book_view = new BookView (book); +        book_view.set_border_width (18); +        main_vbox.pack_end (book_view, true, true, 0); +        book_view.page_selected.connect (page_selected_cb); +        book_view.show_page.connect (show_page_cb); +        book_view.show_menu.connect (show_page_menu_cb); +        book_view.show (); + +        /* Find default page details */ +        default_page_scan_direction = (ScanDirection) settings.get_enum ("scan-direction"); +        default_page_width = settings.get_int ("page-width"); +        if (default_page_width <= 0) +            default_page_width = 595; +        default_page_height = settings.get_int ("page-height"); +        if (default_page_height <= 0) +            default_page_height = 842; +        default_page_dpi = settings.get_int ("page-dpi"); +        if (default_page_dpi <= 0) +            default_page_dpi = 72; + +        /* Restore window size */ +        window_width = settings.get_int ("window-width"); +        if (window_width <= 0) +            window_width = 600; +        window_height = settings.get_int ("window-height"); +        if (window_height <= 0) +            window_height = 400; +        debug ("Restoring window to %dx%d pixels", window_width, window_height); +        window.set_default_size (window_width, window_height); +        window_is_maximized = settings.get_boolean ("window-is-maximized"); +        if (window_is_maximized) +        { +            debug ("Restoring window to maximized"); +            window.maximize (); +        } + +        if (book.get_n_pages () == 0) +            add_default_page (); +        book.set_needs_saving (false); +        book.needs_saving_changed.connect (needs_saving_cb); +    } + +    public Book get_book () +    { +        return book; +    } + +    public void set_selected_page (Page page) +    { +        book_view.select_page (page); +    } + +    public Page get_selected_page () +    { +        return book_view.get_selected (); +    } + +    public void set_scanning (bool scanning) +    { +        this.scanning = scanning; +        page_delete_menuitem.set_sensitive (!scanning); +        stop_menuitem.set_sensitive (scanning); +        stop_toolbutton.set_sensitive (scanning); +    } + +    public void show_error (string error_title, string error_text, bool change_scanner_hint) +    { +        have_error = true; +        this.error_title = error_title; +        this.error_text = error_text; +        error_change_scanner_hint = change_scanner_hint; +        update_info_bar (); +    } + +    public void start () +    { +        window.show (); +    } +}  | 
