diff options
author | Alessio Treglia <alessio@debian.org> | 2011-08-27 10:54:22 +0200 |
---|---|---|
committer | Alessio Treglia <alessio@debian.org> | 2011-08-27 10:54:22 +0200 |
commit | 575d802c4f1a81ebce3b7b71be6dd3a51fddf7bd (patch) | |
tree | f67206af06039627d241d77bc83009505189b7eb /src | |
parent | 77a9b5bea4c6dc6977e51b002d92d268e57208f3 (diff) | |
parent | 87ebc2af1f0417b3bc38a233e28ff673eff4fa51 (diff) |
Merge commit 'upstream/3.1.5'
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 (); + } +} |