summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-11-06 19:30:49 -0300
committerPerberos <[email protected]>2011-11-06 19:30:49 -0300
commita8d28a6ce7e0c56dacba5d527d9134573a008902 (patch)
tree8852602004b5a13cc5d1ce3ecd7a314be81d1198 /src
downloadeom-a8d28a6ce7e0c56dacba5d527d9134573a008902.tar.bz2
eom-a8d28a6ce7e0c56dacba5d527d9134573a008902.tar.xz
inicial
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am239
-rw-r--r--src/Makefile.in1326
-rw-r--r--src/eom-application-service.xml23
-rw-r--r--src/eom-application.c566
-rw-r--r--src/eom-application.h118
-rw-r--r--src/eom-close-confirmation-dialog.c698
-rw-r--r--src/eom-close-confirmation-dialog.h79
-rw-r--r--src/eom-config-keys.h63
-rw-r--r--src/eom-debug.c160
-rw-r--r--src/eom-debug.h75
-rw-r--r--src/eom-dialog.c237
-rw-r--r--src/eom-dialog.h76
-rw-r--r--src/eom-enum-types.c.template39
-rw-r--r--src/eom-enum-types.h.template27
-rw-r--r--src/eom-enums.h37
-rw-r--r--src/eom-error-message-area.c192
-rw-r--r--src/eom-error-message-area.h37
-rw-r--r--src/eom-exif-details.c572
-rw-r--r--src/eom-exif-details.h72
-rw-r--r--src/eom-exif-util.c214
-rw-r--r--src/eom-exif-util.h41
-rw-r--r--src/eom-file-chooser.c497
-rw-r--r--src/eom-file-chooser.h60
-rw-r--r--src/eom-image-jpeg.c518
-rw-r--r--src/eom-image-jpeg.h22
-rw-r--r--src/eom-image-private.h96
-rw-r--r--src/eom-image-save-info.c150
-rw-r--r--src/eom-image-save-info.h54
-rw-r--r--src/eom-image.c2237
-rw-r--r--src/eom-image.h218
-rw-r--r--src/eom-job-queue.c238
-rw-r--r--src/eom-job-queue.h42
-rw-r--r--src/eom-jobs.c885
-rw-r--r--src/eom-jobs.h275
-rw-r--r--src/eom-list-store.c931
-rw-r--r--src/eom-list-store.h113
-rw-r--r--src/eom-marshal.list2
-rw-r--r--src/eom-metadata-reader-jpg.c673
-rw-r--r--src/eom-metadata-reader-jpg.h55
-rw-r--r--src/eom-metadata-reader-png.c648
-rw-r--r--src/eom-metadata-reader-png.h55
-rw-r--r--src/eom-metadata-reader.c150
-rw-r--r--src/eom-metadata-reader.h112
-rw-r--r--src/eom-module.c167
-rw-r--r--src/eom-module.h72
-rw-r--r--src/eom-pixbuf-util.c136
-rw-r--r--src/eom-pixbuf-util.h20
-rw-r--r--src/eom-plugin-engine.c943
-rw-r--r--src/eom-plugin-engine.h89
-rw-r--r--src/eom-plugin-manager.c917
-rw-r--r--src/eom-plugin-manager.h61
-rw-r--r--src/eom-plugin.c108
-rw-r--r--src/eom-plugin.h222
-rw-r--r--src/eom-preferences-dialog.c489
-rw-r--r--src/eom-preferences-dialog.h66
-rw-r--r--src/eom-print-image-setup.c1074
-rw-r--r--src/eom-print-image-setup.h71
-rw-r--r--src/eom-print-preview.c1226
-rw-r--r--src/eom-print-preview.h84
-rw-r--r--src/eom-print.c369
-rw-r--r--src/eom-print.h49
-rw-r--r--src/eom-properties-dialog.c834
-rw-r--r--src/eom-properties-dialog.h80
-rw-r--r--src/eom-python-module.c527
-rw-r--r--src/eom-python-module.h72
-rw-r--r--src/eom-python-plugin.c282
-rw-r--r--src/eom-python-plugin.h55
-rw-r--r--src/eom-save-as-dialog-helper.c311
-rw-r--r--src/eom-save-as-dialog-helper.h20
-rw-r--r--src/eom-scroll-view.c2633
-rw-r--r--src/eom-scroll-view.h73
-rw-r--r--src/eom-session.c52
-rw-r--r--src/eom-session.h46
-rw-r--r--src/eom-sidebar.c594
-rw-r--r--src/eom-sidebar.h82
-rw-r--r--src/eom-statusbar.c157
-rw-r--r--src/eom-statusbar.h71
-rw-r--r--src/eom-thumb-nav.c591
-rw-r--r--src/eom-thumb-nav.h79
-rw-r--r--src/eom-thumb-view.c918
-rw-r--r--src/eom-thumb-view.h87
-rw-r--r--src/eom-thumbnail.c509
-rw-r--r--src/eom-thumbnail.h48
-rw-r--r--src/eom-transform.c418
-rw-r--r--src/eom-transform.h75
-rw-r--r--src/eom-uri-converter.c988
-rw-r--r--src/eom-uri-converter.h107
-rw-r--r--src/eom-util.c348
-rw-r--r--src/eom-util.h72
-rw-r--r--src/eom-window.c5796
-rw-r--r--src/eom-window.h122
-rw-r--r--src/main.c270
-rw-r--r--src/uta.c1116
-rw-r--r--src/uta.h75
-rw-r--r--src/zoom.c118
-rw-r--r--src/zoom.h38
96 files changed, 36749 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..8d9e15f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,239 @@
+if ENABLE_JPEG
+jpeg_LIB = $(top_builddir)/jpegutils/libeom-jpegutils.la
+endif
+
+toolbar_LIB = $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la
+
+screensaver_LIB = $(top_builddir)/cut-n-paste/totem-screensaver/libtotemscrsaver.la
+
+noinst_LTLIBRARIES = libeom.la
+
+bin_PROGRAMS = eom
+
+headerdir = $(prefix)/include/[email protected][email protected]/eom
+header_DATA = $(INST_H_FILES)
+
+MARSHAL_OUTPUT = \
+ eom-marshal.h \
+ eom-marshal.c
+
+NOINST_H_FILES = \
+ eom-session.h \
+ eom-util.h \
+ eom-pixbuf-util.h \
+ eom-preferences-dialog.h \
+ eom-config-keys.h \
+ eom-image-jpeg.h \
+ eom-image-private.h \
+ eom-uri-converter.h \
+ eom-metadata-reader.h \
+ eom-metadata-reader-jpg.h \
+ eom-metadata-reader-png.h \
+ eom-save-as-dialog-helper.h \
+ eom-print-image-setup.h \
+ eom-print-preview.h \
+ eom-print.h \
+ eom-module.h \
+ eom-plugin-manager.h \
+ eom-plugin-engine.h \
+ uta.h \
+ eom-close-confirmation-dialog.h \
+ zoom.h
+
+if ENABLE_PYTHON
+NOINST_H_FILES += \
+ eom-python-module.h \
+ eom-python-plugin.h
+endif
+
+INST_H_FILES = \
+ eom-application.h \
+ eom-debug.h \
+ eom-window.h \
+ eom-sidebar.h \
+ eom-dialog.h \
+ eom-properties-dialog.h \
+ eom-error-message-area.h \
+ eom-file-chooser.h \
+ eom-statusbar.h \
+ eom-thumb-nav.h \
+ eom-transform.h \
+ eom-image.h \
+ eom-enums.h \
+ eom-image-save-info.h \
+ eom-scroll-view.h \
+ eom-thumb-view.h \
+ eom-list-store.h \
+ eom-thumbnail.h \
+ eom-job-queue.h \
+ eom-jobs.h \
+ eom-plugin.h
+
+libeom_la_SOURCES = \
+ eom-application.c \
+ eom-session.c \
+ eom-debug.c \
+ eom-util.c \
+ eom-pixbuf-util.c \
+ eom-window.c \
+ eom-sidebar.c \
+ eom-dialog.c \
+ eom-preferences-dialog.c \
+ eom-properties-dialog.c \
+ eom-error-message-area.c \
+ eom-file-chooser.c \
+ eom-statusbar.c \
+ eom-thumb-nav.c \
+ eom-transform.c \
+ eom-image.c \
+ eom-image-jpeg.c \
+ eom-image-save-info.c \
+ eom-scroll-view.c \
+ eom-thumb-view.c \
+ eom-list-store.c \
+ eom-thumbnail.c \
+ eom-job-queue.c \
+ eom-jobs.c \
+ eom-uri-converter.c \
+ eom-metadata-reader.c \
+ eom-metadata-reader-jpg.c \
+ eom-metadata-reader-png.c \
+ eom-save-as-dialog-helper.c \
+ eom-print-image-setup.c \
+ eom-print-preview.c \
+ eom-print.c \
+ eom-module.c \
+ eom-close-confirmation-dialog.c \
+ eom-plugin.c \
+ eom-plugin-manager.c \
+ eom-plugin-engine.c \
+ uta.c \
+ zoom.c \
+ $(BUILT_SOURCES) \
+ $(NOINST_H_FILES) \
+ $(INST_H_FILES)
+
+if HAVE_EXIF
+INST_H_FILES += \
+ eom-exif-util.h \
+ eom-exif-details.h
+libeom_la_SOURCES += \
+ eom-exif-util.c \
+ eom-exif-details.c
+endif
+
+if ENABLE_PYTHON
+libeom_la_SOURCES += \
+ eom-python-module.c \
+ eom-python-module.h \
+ eom-python-plugin.c \
+ eom-python-plugin.h
+endif
+
+if HAVE_EXEMPI
+# We need to make sure eom-exif-details.h
+# is only listed once in INST_H_FILES
+# or the build will break with automake-1.11
+if !HAVE_EXIF
+INST_H_FILES += \
+ eom-exif-details.h
+endif !HAVE_EXIF
+libeom_la_SOURCES += \
+ eom-exif-details.c
+endif HAVE_EXEMPI
+
+libeom_la_CFLAGS = \
+ -I$(top_srcdir)/jpegutils \
+ -I$(top_srcdir)/cut-n-paste/toolbar-editor \
+ -I$(top_srcdir)/cut-n-paste/totem-screensaver \
+ $(EOM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ -DG_LOG_DOMAIN=\"EOM\" \
+ -DEOM_PREFIX=\""${prefix}"\" \
+ -DEOM_DATA_DIR=\""$(pkgdatadir)"\" \
+ -DEOM_LOCALE_DIR=\""$(datadir)/locale"\" \
+ -DEOM_PIXMAPS_DIR=\""$(datadir)/pixmaps/eom"\" \
+ -DEOM_PLUGIN_DIR=\""$(libdir)/eom/plugins"\"
+
+libeom_la_LIBADD = \
+ $(EOM_LIBS)
+
+if HAVE_LCMS
+libeom_la_CFLAGS += \
+ $(X11_CFLAGS)
+
+libeom_la_LIBADD += \
+ $(X11_LIBS)
+endif
+
+if ENABLE_PYTHON
+libeom_la_CFLAGS += \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(PYGTK_CFLAGS) \
+ $(PYTHON_CFLAGS) \
+ $(AM_CFLAGS)
+
+libeom_la_LIBADD += \
+ $(top_builddir)/bindings/python/eom.la
+endif
+
+libeom_la_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
+
+eom_SOURCES = main.c
+
+eom_CFLAGS = \
+ -I$(top_srcdir)/cut-n-paste/toolbar-editor \
+ -I$(top_srcdir)/cut-n-paste/totem-screensaver \
+ $(EOM_CFLAGS) \
+ -DEOM_DATA_DIR=\""$(pkgdatadir)"\" \
+ -DEOM_LOCALE_DIR=\""$(datadir)/locale"\"
+
+eom_LDADD = \
+ libeom.la \
+ $(EOM_LIBS) \
+ $(LIBJPEG) \
+ $(toolbar_LIB) \
+ $(screensaver_LIB) \
+ $(jpeg_LIB)
+
+eom_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
+
+BUILT_SOURCES = \
+ eom-enum-types.c \
+ eom-enum-types.h \
+ $(MARSHAL_OUTPUT)
+
+eom-enum-types.h: eom-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS)
+ $(AM_V_GEN)(cd $(srcdir) && $(GLIB_MKENUMS) --template eom-enum-types.h.template $(INST_H_FILES)) > [email protected]
+
+eom-enum-types.c: eom-enum-types.c.template $(INST_H_FILES) $(GLIB_MKENUMS)
+ $(AM_V_GEN)(cd $(srcdir) && $(GLIB_MKENUMS) --template eom-enum-types.c.template $(INST_H_FILES)) > [email protected]
+
+eom-marshal.h: eom-marshal.list $(GLIB_GENMARSHAL)
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --header --internal --prefix=eom_marshal > [email protected]
+
+eom-marshal.c: eom-marshal.list $(GLIB_GENMARSHAL)
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --body --header --prefix=eom_marshal > [email protected]
+
+EXTRA_DIST = \
+ eom-enum-types.h.template \
+ eom-enum-types.c.template \
+ eom-marshal.list
+
+if HAVE_DBUS
+
+BUILT_SOURCES += eom-application-service.h
+
+EXTRA_DIST += eom-application-service.xml
+
+eom-application-service.h: eom-application-service.xml
+ $(AM_V_GEN)dbus-binding-tool --prefix=eom_application --mode=glib-server --output=eom-application-service.h $<
+
+endif
+
+CLEANFILES = $(BUILT_SOURCES)
+
+dist-hook:
+ cd $(distdir); rm -f $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..deacf79
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1326 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+pkgdatadir = $(datadir)/@[email protected]
+pkgincludedir = $(includedir)/@[email protected]
+pkglibdir = $(libdir)/@[email protected]
+pkglibexecdir = $(libexecdir)/@[email protected]
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @[email protected]
+host_triplet = @[email protected]
+bin_PROGRAMS = eom$(EXEEXT)
+
+
+
+
+
+# We need to make sure eom-exif-details.h
+# is only listed once in INST_H_FILES
+# or the build will break with automake-1.11
+
+
+
+
[email protected][email protected] $(NO_STRICT_ALIASING_CFLAGS) \
+
[email protected][email protected] $(top_builddir)/bindings/python/eom.la
+
[email protected][email protected]__append_11 = eom-application-service.h
[email protected][email protected]__append_12 = eom-application-service.xml
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+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 = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
[email protected][email protected]__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+libeom_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__append_10)
+am__libeom_la_SOURCES_DIST = eom-application.c eom-session.c \
+ eom-debug.c eom-util.c eom-pixbuf-util.c eom-window.c \
+ eom-sidebar.c eom-dialog.c eom-preferences-dialog.c \
+ eom-properties-dialog.c eom-error-message-area.c \
+ eom-file-chooser.c eom-statusbar.c eom-thumb-nav.c \
+ eom-transform.c eom-image.c eom-image-jpeg.c \
+ eom-image-save-info.c eom-scroll-view.c eom-thumb-view.c \
+ eom-list-store.c eom-thumbnail.c eom-job-queue.c eom-jobs.c \
+ eom-uri-converter.c eom-metadata-reader.c \
+ eom-metadata-reader-jpg.c eom-metadata-reader-png.c \
+ eom-save-as-dialog-helper.c eom-print-image-setup.c \
+ eom-print-preview.c eom-print.c eom-module.c \
+ eom-close-confirmation-dialog.c eom-plugin.c \
+ eom-plugin-manager.c eom-plugin-engine.c uta.c zoom.c \
+ eom-enum-types.c eom-enum-types.h eom-marshal.h eom-marshal.c \
+ eom-application-service.h eom-session.h eom-util.h \
+ eom-pixbuf-util.h eom-preferences-dialog.h eom-config-keys.h \
+ eom-image-jpeg.h eom-image-private.h eom-uri-converter.h \
+ eom-metadata-reader.h eom-metadata-reader-jpg.h \
+ eom-metadata-reader-png.h eom-save-as-dialog-helper.h \
+ eom-print-image-setup.h eom-print-preview.h eom-print.h \
+ eom-module.h eom-plugin-manager.h eom-plugin-engine.h uta.h \
+ eom-close-confirmation-dialog.h zoom.h eom-python-module.h \
+ eom-python-plugin.h eom-application.h eom-debug.h eom-window.h \
+ eom-sidebar.h eom-dialog.h eom-properties-dialog.h \
+ eom-error-message-area.h eom-file-chooser.h eom-statusbar.h \
+ eom-thumb-nav.h eom-transform.h eom-image.h eom-enums.h \
+ eom-image-save-info.h eom-scroll-view.h eom-thumb-view.h \
+ eom-list-store.h eom-thumbnail.h eom-job-queue.h eom-jobs.h \
+ eom-plugin.h eom-exif-util.h eom-exif-details.h \
+ eom-exif-util.c eom-exif-details.c eom-python-module.c \
+ eom-python-plugin.c
+am__objects_1 = libeom_la-eom-marshal.lo
+am__objects_2 =
+am__objects_3 = libeom_la-eom-enum-types.lo $(am__objects_1) \
+ $(am__objects_2)
+am__objects_4 = $(am__objects_2)
+am__objects_5 = $(am__objects_2) $(am__objects_2)
[email protected][email protected]__objects_6 = libeom_la-eom-exif-util.lo \
[email protected][email protected] libeom_la-eom-exif-details.lo
[email protected][email protected]__objects_7 = libeom_la-eom-python-module.lo \
[email protected][email protected] libeom_la-eom-python-plugin.lo
[email protected][email protected]__objects_8 = libeom_la-eom-exif-details.lo
+am_libeom_la_OBJECTS = libeom_la-eom-application.lo \
+ libeom_la-eom-session.lo libeom_la-eom-debug.lo \
+ libeom_la-eom-util.lo libeom_la-eom-pixbuf-util.lo \
+ libeom_la-eom-window.lo libeom_la-eom-sidebar.lo \
+ libeom_la-eom-dialog.lo libeom_la-eom-preferences-dialog.lo \
+ libeom_la-eom-properties-dialog.lo \
+ libeom_la-eom-error-message-area.lo \
+ libeom_la-eom-file-chooser.lo libeom_la-eom-statusbar.lo \
+ libeom_la-eom-thumb-nav.lo libeom_la-eom-transform.lo \
+ libeom_la-eom-image.lo libeom_la-eom-image-jpeg.lo \
+ libeom_la-eom-image-save-info.lo libeom_la-eom-scroll-view.lo \
+ libeom_la-eom-thumb-view.lo libeom_la-eom-list-store.lo \
+ libeom_la-eom-thumbnail.lo libeom_la-eom-job-queue.lo \
+ libeom_la-eom-jobs.lo libeom_la-eom-uri-converter.lo \
+ libeom_la-eom-metadata-reader.lo \
+ libeom_la-eom-metadata-reader-jpg.lo \
+ libeom_la-eom-metadata-reader-png.lo \
+ libeom_la-eom-save-as-dialog-helper.lo \
+ libeom_la-eom-print-image-setup.lo \
+ libeom_la-eom-print-preview.lo libeom_la-eom-print.lo \
+ libeom_la-eom-module.lo \
+ libeom_la-eom-close-confirmation-dialog.lo \
+ libeom_la-eom-plugin.lo libeom_la-eom-plugin-manager.lo \
+ libeom_la-eom-plugin-engine.lo libeom_la-uta.lo \
+ libeom_la-zoom.lo $(am__objects_3) $(am__objects_4) \
+ $(am__objects_5) $(am__objects_6) $(am__objects_7) \
+ $(am__objects_8)
+libeom_la_OBJECTS = $(am_libeom_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libeom_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libeom_la_CFLAGS) \
+ $(CFLAGS) $(libeom_la_LDFLAGS) $(LDFLAGS) -o [email protected]
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(headerdir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_eom_OBJECTS = eom-main.$(OBJEXT)
+eom_OBJECTS = $(am_eom_OBJECTS)
+eom_DEPENDENCIES = libeom.la $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(toolbar_LIB) $(screensaver_LIB) \
+ $(jpeg_LIB)
+eom_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(eom_CFLAGS) $(CFLAGS) \
+ $(eom_LDFLAGS) $(LDFLAGS) -o [email protected]
+DEFAULT_INCLUDES = [email protected][email protected] -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " [email protected];
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o [email protected]
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " [email protected];
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " [email protected];
+SOURCES = $(libeom_la_SOURCES) $(eom_SOURCES)
+DIST_SOURCES = $(am__libeom_la_SOURCES_DIST) $(eom_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+DATA = $(header_DATA)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @[email protected]
+ACLOCAL_AMFLAGS = @[email protected]
+ALL_LINGUAS = @[email protected]
+AM_DEFAULT_VERBOSITY = @[email protected]
+AUTOCONF = @[email protected]
+AUTOHEADER = @[email protected]
+AUTOMAKE = @[email protected]
+CATALOGS = @[email protected]
+CATOBJEXT = @[email protected]
+CCDEPMODE = @[email protected]
+CPPFLAGS = @[email protected]
+CYGPATH_W = @[email protected]
+DATADIRNAME = @[email protected]
+DBUS_BINDING_TOOL = @[email protected]
+DBUS_CFLAGS = @[email protected]
+DBUS_LIBS = @[email protected]
+DISABLE_DEPRECATED = @[email protected]
+DISTCHECK_CONFIGURE_FLAGS = @[email protected]
+DLLTOOL = @[email protected]
+DOC_USER_FORMATS = @[email protected]
+DSYMUTIL = @[email protected]
+DUMPBIN = @[email protected]
+EOM_API_VERSION = @[email protected]
+EOM_CFLAGS = @[email protected]
+EOM_DOC_EXIF_START = @[email protected]
+EOM_DOC_EXIF_STOP = @[email protected]
+EOM_LIBS = @[email protected]
+EOM_MAJOR_VERSION = @[email protected]
+EOM_MICRO_VERSION = @[email protected]
+EOM_MINOR_VERSION = @[email protected]
+EXEMPI_CFLAGS = @[email protected]
+EXEMPI_LIBS = @[email protected]
+EXIF_CFLAGS = @[email protected]
+EXIF_LIBS = @[email protected]
+GETTEXT_PACKAGE = @[email protected]
+GLIB_GENMARSHAL = @[email protected]
+GLIB_MKENUMS = @[email protected]
+GMOFILES = @[email protected]
+GMSGFMT = @[email protected]
+GTKDOC_CHECK = @[email protected]
+GTKDOC_DEPS_CFLAGS = @[email protected]
+GTKDOC_DEPS_LIBS = @[email protected]
+GTKDOC_MKPDF = @[email protected]
+GTKDOC_REBASE = @[email protected]
+HELP_DIR = @[email protected]
+HTML_DIR = @[email protected]
+INSTALL = @[email protected]
+INSTALL_DATA = @[email protected]
+INSTALL_PROGRAM = @[email protected]
+INSTALL_SCRIPT = @[email protected]
+INSTALL_STRIP_PROGRAM = @[email protected]
+INSTOBJEXT = @[email protected]
+INTLLIBS = @[email protected]
+INTLTOOL_EXTRACT = @[email protected]
+INTLTOOL_MERGE = @[email protected]
+INTLTOOL_PERL = @[email protected]
+INTLTOOL_UPDATE = @[email protected]
+LCMS_CFLAGS = @[email protected]
+LCMS_LIBS = @[email protected]
+LDFLAGS = @[email protected]
+LIBJPEG = @[email protected]
+LIBOBJS = @[email protected]
+LIBTOOL = @[email protected]
+LIBXML2_CFLAGS = @[email protected]
+LIBXML2_LIBS = @[email protected]
+LTLIBOBJS = @[email protected]
+MAKEINFO = @[email protected]
+MANIFEST_TOOL = @[email protected]
+MATECONFTOOL = @[email protected]
+MATECONF_SCHEMA_CONFIG_SOURCE = @[email protected]
+MATECONF_SCHEMA_FILE_DIR = @[email protected]
+MKDIR_P = @[email protected]
+MKINSTALLDIRS = @[email protected]
+MSGFMT_OPTS = @[email protected]
+MSGMERGE = @[email protected]
+NO_STRICT_ALIASING_CFLAGS = @[email protected]
+OBJDUMP = @[email protected]
+OMF_DIR = @[email protected]
+OTOOL64 = @[email protected]
+PACKAGE = @[email protected]
+PACKAGE_BUGREPORT = @[email protected]
+PACKAGE_NAME = @[email protected]
+PACKAGE_STRING = @[email protected]
+PACKAGE_TARNAME = @[email protected]
+PACKAGE_URL = @[email protected]
+PACKAGE_VERSION = @[email protected]
+PATH_SEPARATOR = @[email protected]
+PKG_CONFIG = @[email protected]
+PKG_CONFIG_LIBDIR = @[email protected]
+PKG_CONFIG_PATH = @[email protected]
+POFILES = @[email protected]
+PO_IN_DATADIR_FALSE = @[email protected]
+PO_IN_DATADIR_TRUE = @[email protected]
+PYGOBJECT_CODEGEN = @[email protected]
+PYGOBJECT_DEFSDIR = @[email protected]
+PYGOBJECT_H2DEF = @[email protected]
+PYGTK_CFLAGS = @[email protected]
+PYGTK_DEFSDIR = @[email protected]
+PYGTK_LIBS = @[email protected]
+PYTHON_CFLAGS = @[email protected]
+PYTHON_EXEC_PREFIX = @[email protected]
+PYTHON_EXTRA_LIBS = @[email protected]
+PYTHON_LIBS = @[email protected]
+PYTHON_LIB_LOC = @[email protected]
+PYTHON_PLATFORM = @[email protected]
+PYTHON_PREFIX = @[email protected]
+PYTHON_VERSION = @[email protected]
+RSVG_CFLAGS = @[email protected]
+RSVG_LIBS = @[email protected]
+SET_MAKE = @[email protected]
+USE_NLS = @[email protected]
+VERSION = @[email protected]
+WARN_CFLAGS = @[email protected]
+X11_CFLAGS = @[email protected]
+X11_LIBS = @[email protected]
+XGETTEXT = @[email protected]
+X_CFLAGS = @[email protected]
+X_EXTRA_LIBS = @[email protected]
+X_PRE_LIBS = @[email protected]
+abs_builddir = @[email protected]
+abs_srcdir = @[email protected]
+abs_top_builddir = @[email protected]
+abs_top_srcdir = @[email protected]
+ac_ct_AR = @[email protected]
+ac_ct_CC = @[email protected]
+ac_ct_DUMPBIN = @[email protected]
+am__include = @[email protected]
+am__leading_dot = @[email protected]
+am__quote = @[email protected]
+am__tar = @[email protected]
+am__untar = @[email protected]
+build_alias = @[email protected]
+build_cpu = @[email protected]
+build_os = @[email protected]
+build_vendor = @[email protected]
+builddir = @[email protected]
+datadir = @[email protected]
+datarootdir = @[email protected]
+exec_prefix = @[email protected]
+host_alias = @[email protected]
+host_cpu = @[email protected]
+host_os = @[email protected]
+host_vendor = @[email protected]
+htmldir = @[email protected]
+includedir = @[email protected]
+infodir = @[email protected]
+install_sh = @[email protected]
+libexecdir = @[email protected]
+localedir = @[email protected]
+localstatedir = @[email protected]
+mkdir_p = @[email protected]
+oldincludedir = @[email protected]
+pkgpyexecdir = @[email protected]
+pkgpythondir = @[email protected]
+program_transform_name = @[email protected]
+pyexecdir = @[email protected]
+pythondir = @[email protected]
+sbindir = @[email protected]
+sharedstatedir = @[email protected]
+sysconfdir = @[email protected]
+target_alias = @[email protected]
+top_build_prefix = @[email protected]
+top_builddir = @[email protected]
+top_srcdir = @[email protected]
[email protected][email protected]_LIB = $(top_builddir)/jpegutils/libeom-jpegutils.la
+toolbar_LIB = $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la
+screensaver_LIB = $(top_builddir)/cut-n-paste/totem-screensaver/libtotemscrsaver.la
+noinst_LTLIBRARIES = libeom.la
+headerdir = $(prefix)/include/[email protected][email protected]/eom
+header_DATA = $(INST_H_FILES)
+MARSHAL_OUTPUT = \
+ eom-marshal.h \
+ eom-marshal.c
+
+NOINST_H_FILES = eom-session.h eom-util.h eom-pixbuf-util.h \
+ eom-preferences-dialog.h eom-config-keys.h eom-image-jpeg.h \
+ eom-image-private.h eom-uri-converter.h eom-metadata-reader.h \
+ eom-metadata-reader-jpg.h eom-metadata-reader-png.h \
+ eom-save-as-dialog-helper.h eom-print-image-setup.h \
+ eom-print-preview.h eom-print.h eom-module.h \
+ eom-plugin-manager.h eom-plugin-engine.h uta.h \
+ eom-close-confirmation-dialog.h zoom.h $(am__append_1)
+INST_H_FILES = eom-application.h eom-debug.h eom-window.h \
+ eom-sidebar.h eom-dialog.h eom-properties-dialog.h \
+ eom-error-message-area.h eom-file-chooser.h eom-statusbar.h \
+ eom-thumb-nav.h eom-transform.h eom-image.h eom-enums.h \
+ eom-image-save-info.h eom-scroll-view.h eom-thumb-view.h \
+ eom-list-store.h eom-thumbnail.h eom-job-queue.h eom-jobs.h \
+ eom-plugin.h $(am__append_2) $(am__append_5)
+libeom_la_SOURCES = eom-application.c eom-session.c eom-debug.c \
+ eom-util.c eom-pixbuf-util.c eom-window.c eom-sidebar.c \
+ eom-dialog.c eom-preferences-dialog.c eom-properties-dialog.c \
+ eom-error-message-area.c eom-file-chooser.c eom-statusbar.c \
+ eom-thumb-nav.c eom-transform.c eom-image.c eom-image-jpeg.c \
+ eom-image-save-info.c eom-scroll-view.c eom-thumb-view.c \
+ eom-list-store.c eom-thumbnail.c eom-job-queue.c eom-jobs.c \
+ eom-uri-converter.c eom-metadata-reader.c \
+ eom-metadata-reader-jpg.c eom-metadata-reader-png.c \
+ eom-save-as-dialog-helper.c eom-print-image-setup.c \
+ eom-print-preview.c eom-print.c eom-module.c \
+ eom-close-confirmation-dialog.c eom-plugin.c \
+ eom-plugin-manager.c eom-plugin-engine.c uta.c zoom.c \
+ $(BUILT_SOURCES) $(NOINST_H_FILES) $(INST_H_FILES) \
+ $(am__append_3) $(am__append_4) $(am__append_6)
+libeom_la_CFLAGS = -I$(top_srcdir)/jpegutils \
+ -I$(top_srcdir)/cut-n-paste/toolbar-editor \
+ -I$(top_srcdir)/cut-n-paste/totem-screensaver $(EOM_CFLAGS) \
+ $(WARN_CFLAGS) -DG_LOG_DOMAIN=\"EOM\" \
+ -DEOM_PREFIX=\""${prefix}"\" \
+ -DEOM_DATA_DIR=\""$(pkgdatadir)"\" \
+ -DEOM_LOCALE_DIR=\""$(datadir)/locale"\" \
+ -DEOM_PIXMAPS_DIR=\""$(datadir)/pixmaps/eom"\" \
+ -DEOM_PLUGIN_DIR=\""$(libdir)/eom/plugins"\" $(am__append_7) \
+ $(am__append_9)
+libeom_la_LIBADD = $(EOM_LIBS) $(am__append_8) $(am__append_10)
+libeom_la_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
+eom_SOURCES = main.c
+eom_CFLAGS = \
+ -I$(top_srcdir)/cut-n-paste/toolbar-editor \
+ -I$(top_srcdir)/cut-n-paste/totem-screensaver \
+ $(EOM_CFLAGS) \
+ -DEOM_DATA_DIR=\""$(pkgdatadir)"\" \
+ -DEOM_LOCALE_DIR=\""$(datadir)/locale"\"
+
+eom_LDADD = \
+ libeom.la \
+ $(EOM_LIBS) \
+ $(LIBJPEG) \
+ $(toolbar_LIB) \
+ $(screensaver_LIB) \
+ $(jpeg_LIB)
+
+eom_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
+BUILT_SOURCES = eom-enum-types.c eom-enum-types.h $(MARSHAL_OUTPUT) \
+ $(am__append_11)
+EXTRA_DIST = eom-enum-types.h.template eom-enum-types.c.template \
+ eom-marshal.list $(am__append_12)
+CLEANFILES = $(BUILT_SOURCES)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @[email protected] $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f [email protected]; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected] $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected] $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @[email protected] $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @[email protected] $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libeom.la: $(libeom_la_OBJECTS) $(libeom_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libeom_la_LINK) $(libeom_la_OBJECTS) $(libeom_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+eom$(EXEEXT): $(eom_OBJECTS) $(eom_DEPENDENCIES)
+ @rm -f eom$(EXEEXT)
+ $(AM_V_CCLD)$(eom_LINK) $(eom_OBJECTS) $(eom_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+
+.c.o:
[email protected][email protected] $(AM_V_CC)$(COMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] $<
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+
+.c.obj:
[email protected][email protected] $(AM_V_CC)$(COMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] `$(CYGPATH_W) '$<'`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
[email protected][email protected] $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
[email protected][email protected] $(AM_V_CC)$(LTCOMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] $<
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+
+libeom_la-eom-application.lo: eom-application.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-application.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-application.Tpo -c -o libeom_la-eom-application.lo `test -f 'eom-application.c' || echo '$(srcdir)/'`eom-application.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-application.Tpo $(DEPDIR)/libeom_la-eom-application.Plo
[email protected][email protected]@[email protected] source='eom-application.c' object='libeom_la-eom-application.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-application.lo `test -f 'eom-application.c' || echo '$(srcdir)/'`eom-application.c
+
+libeom_la-eom-session.lo: eom-session.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-session.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-session.Tpo -c -o libeom_la-eom-session.lo `test -f 'eom-session.c' || echo '$(srcdir)/'`eom-session.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-session.Tpo $(DEPDIR)/libeom_la-eom-session.Plo
[email protected][email protected]@[email protected] source='eom-session.c' object='libeom_la-eom-session.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-session.lo `test -f 'eom-session.c' || echo '$(srcdir)/'`eom-session.c
+
+libeom_la-eom-debug.lo: eom-debug.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-debug.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-debug.Tpo -c -o libeom_la-eom-debug.lo `test -f 'eom-debug.c' || echo '$(srcdir)/'`eom-debug.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-debug.Tpo $(DEPDIR)/libeom_la-eom-debug.Plo
[email protected][email protected]@[email protected] source='eom-debug.c' object='libeom_la-eom-debug.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-debug.lo `test -f 'eom-debug.c' || echo '$(srcdir)/'`eom-debug.c
+
+libeom_la-eom-util.lo: eom-util.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-util.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-util.Tpo -c -o libeom_la-eom-util.lo `test -f 'eom-util.c' || echo '$(srcdir)/'`eom-util.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-util.Tpo $(DEPDIR)/libeom_la-eom-util.Plo
[email protected][email protected]@[email protected] source='eom-util.c' object='libeom_la-eom-util.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-util.lo `test -f 'eom-util.c' || echo '$(srcdir)/'`eom-util.c
+
+libeom_la-eom-pixbuf-util.lo: eom-pixbuf-util.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-pixbuf-util.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-pixbuf-util.Tpo -c -o libeom_la-eom-pixbuf-util.lo `test -f 'eom-pixbuf-util.c' || echo '$(srcdir)/'`eom-pixbuf-util.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-pixbuf-util.Tpo $(DEPDIR)/libeom_la-eom-pixbuf-util.Plo
[email protected][email protected]@[email protected] source='eom-pixbuf-util.c' object='libeom_la-eom-pixbuf-util.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-pixbuf-util.lo `test -f 'eom-pixbuf-util.c' || echo '$(srcdir)/'`eom-pixbuf-util.c
+
+libeom_la-eom-window.lo: eom-window.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-window.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-window.Tpo -c -o libeom_la-eom-window.lo `test -f 'eom-window.c' || echo '$(srcdir)/'`eom-window.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-window.Tpo $(DEPDIR)/libeom_la-eom-window.Plo
[email protected][email protected]@[email protected] source='eom-window.c' object='libeom_la-eom-window.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-window.lo `test -f 'eom-window.c' || echo '$(srcdir)/'`eom-window.c
+
+libeom_la-eom-sidebar.lo: eom-sidebar.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-sidebar.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-sidebar.Tpo -c -o libeom_la-eom-sidebar.lo `test -f 'eom-sidebar.c' || echo '$(srcdir)/'`eom-sidebar.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-sidebar.Tpo $(DEPDIR)/libeom_la-eom-sidebar.Plo
[email protected][email protected]@[email protected] source='eom-sidebar.c' object='libeom_la-eom-sidebar.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-sidebar.lo `test -f 'eom-sidebar.c' || echo '$(srcdir)/'`eom-sidebar.c
+
+libeom_la-eom-dialog.lo: eom-dialog.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-dialog.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-dialog.Tpo -c -o libeom_la-eom-dialog.lo `test -f 'eom-dialog.c' || echo '$(srcdir)/'`eom-dialog.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-dialog.Tpo $(DEPDIR)/libeom_la-eom-dialog.Plo
[email protected][email protected]@[email protected] source='eom-dialog.c' object='libeom_la-eom-dialog.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-dialog.lo `test -f 'eom-dialog.c' || echo '$(srcdir)/'`eom-dialog.c
+
+libeom_la-eom-preferences-dialog.lo: eom-preferences-dialog.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-preferences-dialog.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-preferences-dialog.Tpo -c -o libeom_la-eom-preferences-dialog.lo `test -f 'eom-preferences-dialog.c' || echo '$(srcdir)/'`eom-preferences-dialog.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-preferences-dialog.Tpo $(DEPDIR)/libeom_la-eom-preferences-dialog.Plo
[email protected][email protected]@[email protected] source='eom-preferences-dialog.c' object='libeom_la-eom-preferences-dialog.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-preferences-dialog.lo `test -f 'eom-preferences-dialog.c' || echo '$(srcdir)/'`eom-preferences-dialog.c
+
+libeom_la-eom-properties-dialog.lo: eom-properties-dialog.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-properties-dialog.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-properties-dialog.Tpo -c -o libeom_la-eom-properties-dialog.lo `test -f 'eom-properties-dialog.c' || echo '$(srcdir)/'`eom-properties-dialog.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-properties-dialog.Tpo $(DEPDIR)/libeom_la-eom-properties-dialog.Plo
[email protected][email protected]@[email protected] source='eom-properties-dialog.c' object='libeom_la-eom-properties-dialog.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-properties-dialog.lo `test -f 'eom-properties-dialog.c' || echo '$(srcdir)/'`eom-properties-dialog.c
+
+libeom_la-eom-error-message-area.lo: eom-error-message-area.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-error-message-area.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-error-message-area.Tpo -c -o libeom_la-eom-error-message-area.lo `test -f 'eom-error-message-area.c' || echo '$(srcdir)/'`eom-error-message-area.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-error-message-area.Tpo $(DEPDIR)/libeom_la-eom-error-message-area.Plo
[email protected][email protected]@[email protected] source='eom-error-message-area.c' object='libeom_la-eom-error-message-area.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-error-message-area.lo `test -f 'eom-error-message-area.c' || echo '$(srcdir)/'`eom-error-message-area.c
+
+libeom_la-eom-file-chooser.lo: eom-file-chooser.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-file-chooser.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-file-chooser.Tpo -c -o libeom_la-eom-file-chooser.lo `test -f 'eom-file-chooser.c' || echo '$(srcdir)/'`eom-file-chooser.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-file-chooser.Tpo $(DEPDIR)/libeom_la-eom-file-chooser.Plo
[email protected][email protected]@[email protected] source='eom-file-chooser.c' object='libeom_la-eom-file-chooser.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-file-chooser.lo `test -f 'eom-file-chooser.c' || echo '$(srcdir)/'`eom-file-chooser.c
+
+libeom_la-eom-statusbar.lo: eom-statusbar.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-statusbar.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-statusbar.Tpo -c -o libeom_la-eom-statusbar.lo `test -f 'eom-statusbar.c' || echo '$(srcdir)/'`eom-statusbar.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-statusbar.Tpo $(DEPDIR)/libeom_la-eom-statusbar.Plo
[email protected][email protected]@[email protected] source='eom-statusbar.c' object='libeom_la-eom-statusbar.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-statusbar.lo `test -f 'eom-statusbar.c' || echo '$(srcdir)/'`eom-statusbar.c
+
+libeom_la-eom-thumb-nav.lo: eom-thumb-nav.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-thumb-nav.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-thumb-nav.Tpo -c -o libeom_la-eom-thumb-nav.lo `test -f 'eom-thumb-nav.c' || echo '$(srcdir)/'`eom-thumb-nav.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-thumb-nav.Tpo $(DEPDIR)/libeom_la-eom-thumb-nav.Plo
[email protected][email protected]@[email protected] source='eom-thumb-nav.c' object='libeom_la-eom-thumb-nav.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-thumb-nav.lo `test -f 'eom-thumb-nav.c' || echo '$(srcdir)/'`eom-thumb-nav.c
+
+libeom_la-eom-transform.lo: eom-transform.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-transform.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-transform.Tpo -c -o libeom_la-eom-transform.lo `test -f 'eom-transform.c' || echo '$(srcdir)/'`eom-transform.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-transform.Tpo $(DEPDIR)/libeom_la-eom-transform.Plo
[email protected][email protected]@[email protected] source='eom-transform.c' object='libeom_la-eom-transform.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-transform.lo `test -f 'eom-transform.c' || echo '$(srcdir)/'`eom-transform.c
+
+libeom_la-eom-image.lo: eom-image.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-image.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-image.Tpo -c -o libeom_la-eom-image.lo `test -f 'eom-image.c' || echo '$(srcdir)/'`eom-image.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-image.Tpo $(DEPDIR)/libeom_la-eom-image.Plo
[email protected][email protected]@[email protected] source='eom-image.c' object='libeom_la-eom-image.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-image.lo `test -f 'eom-image.c' || echo '$(srcdir)/'`eom-image.c
+
+libeom_la-eom-image-jpeg.lo: eom-image-jpeg.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-image-jpeg.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-image-jpeg.Tpo -c -o libeom_la-eom-image-jpeg.lo `test -f 'eom-image-jpeg.c' || echo '$(srcdir)/'`eom-image-jpeg.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-image-jpeg.Tpo $(DEPDIR)/libeom_la-eom-image-jpeg.Plo
[email protected][email protected]@[email protected] source='eom-image-jpeg.c' object='libeom_la-eom-image-jpeg.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-image-jpeg.lo `test -f 'eom-image-jpeg.c' || echo '$(srcdir)/'`eom-image-jpeg.c
+
+libeom_la-eom-image-save-info.lo: eom-image-save-info.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-image-save-info.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-image-save-info.Tpo -c -o libeom_la-eom-image-save-info.lo `test -f 'eom-image-save-info.c' || echo '$(srcdir)/'`eom-image-save-info.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-image-save-info.Tpo $(DEPDIR)/libeom_la-eom-image-save-info.Plo
[email protected][email protected]@[email protected] source='eom-image-save-info.c' object='libeom_la-eom-image-save-info.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-image-save-info.lo `test -f 'eom-image-save-info.c' || echo '$(srcdir)/'`eom-image-save-info.c
+
+libeom_la-eom-scroll-view.lo: eom-scroll-view.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-scroll-view.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-scroll-view.Tpo -c -o libeom_la-eom-scroll-view.lo `test -f 'eom-scroll-view.c' || echo '$(srcdir)/'`eom-scroll-view.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-scroll-view.Tpo $(DEPDIR)/libeom_la-eom-scroll-view.Plo
[email protected][email protected]@[email protected] source='eom-scroll-view.c' object='libeom_la-eom-scroll-view.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-scroll-view.lo `test -f 'eom-scroll-view.c' || echo '$(srcdir)/'`eom-scroll-view.c
+
+libeom_la-eom-thumb-view.lo: eom-thumb-view.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-thumb-view.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-thumb-view.Tpo -c -o libeom_la-eom-thumb-view.lo `test -f 'eom-thumb-view.c' || echo '$(srcdir)/'`eom-thumb-view.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-thumb-view.Tpo $(DEPDIR)/libeom_la-eom-thumb-view.Plo
[email protected][email protected]@[email protected] source='eom-thumb-view.c' object='libeom_la-eom-thumb-view.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-thumb-view.lo `test -f 'eom-thumb-view.c' || echo '$(srcdir)/'`eom-thumb-view.c
+
+libeom_la-eom-list-store.lo: eom-list-store.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-list-store.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-list-store.Tpo -c -o libeom_la-eom-list-store.lo `test -f 'eom-list-store.c' || echo '$(srcdir)/'`eom-list-store.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-list-store.Tpo $(DEPDIR)/libeom_la-eom-list-store.Plo
[email protected][email protected]@[email protected] source='eom-list-store.c' object='libeom_la-eom-list-store.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-list-store.lo `test -f 'eom-list-store.c' || echo '$(srcdir)/'`eom-list-store.c
+
+libeom_la-eom-thumbnail.lo: eom-thumbnail.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-thumbnail.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-thumbnail.Tpo -c -o libeom_la-eom-thumbnail.lo `test -f 'eom-thumbnail.c' || echo '$(srcdir)/'`eom-thumbnail.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-thumbnail.Tpo $(DEPDIR)/libeom_la-eom-thumbnail.Plo
[email protected][email protected]@[email protected] source='eom-thumbnail.c' object='libeom_la-eom-thumbnail.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-thumbnail.lo `test -f 'eom-thumbnail.c' || echo '$(srcdir)/'`eom-thumbnail.c
+
+libeom_la-eom-job-queue.lo: eom-job-queue.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-job-queue.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-job-queue.Tpo -c -o libeom_la-eom-job-queue.lo `test -f 'eom-job-queue.c' || echo '$(srcdir)/'`eom-job-queue.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-job-queue.Tpo $(DEPDIR)/libeom_la-eom-job-queue.Plo
[email protected][email protected]@[email protected] source='eom-job-queue.c' object='libeom_la-eom-job-queue.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-job-queue.lo `test -f 'eom-job-queue.c' || echo '$(srcdir)/'`eom-job-queue.c
+
+libeom_la-eom-jobs.lo: eom-jobs.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-jobs.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-jobs.Tpo -c -o libeom_la-eom-jobs.lo `test -f 'eom-jobs.c' || echo '$(srcdir)/'`eom-jobs.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-jobs.Tpo $(DEPDIR)/libeom_la-eom-jobs.Plo
[email protected][email protected]@[email protected] source='eom-jobs.c' object='libeom_la-eom-jobs.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-jobs.lo `test -f 'eom-jobs.c' || echo '$(srcdir)/'`eom-jobs.c
+
+libeom_la-eom-uri-converter.lo: eom-uri-converter.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-uri-converter.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-uri-converter.Tpo -c -o libeom_la-eom-uri-converter.lo `test -f 'eom-uri-converter.c' || echo '$(srcdir)/'`eom-uri-converter.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-uri-converter.Tpo $(DEPDIR)/libeom_la-eom-uri-converter.Plo
[email protected][email protected]@[email protected] source='eom-uri-converter.c' object='libeom_la-eom-uri-converter.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-uri-converter.lo `test -f 'eom-uri-converter.c' || echo '$(srcdir)/'`eom-uri-converter.c
+
+libeom_la-eom-metadata-reader.lo: eom-metadata-reader.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-metadata-reader.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-metadata-reader.Tpo -c -o libeom_la-eom-metadata-reader.lo `test -f 'eom-metadata-reader.c' || echo '$(srcdir)/'`eom-metadata-reader.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-metadata-reader.Tpo $(DEPDIR)/libeom_la-eom-metadata-reader.Plo
[email protected][email protected]@[email protected] source='eom-metadata-reader.c' object='libeom_la-eom-metadata-reader.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-metadata-reader.lo `test -f 'eom-metadata-reader.c' || echo '$(srcdir)/'`eom-metadata-reader.c
+
+libeom_la-eom-metadata-reader-jpg.lo: eom-metadata-reader-jpg.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-metadata-reader-jpg.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-metadata-reader-jpg.Tpo -c -o libeom_la-eom-metadata-reader-jpg.lo `test -f 'eom-metadata-reader-jpg.c' || echo '$(srcdir)/'`eom-metadata-reader-jpg.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-metadata-reader-jpg.Tpo $(DEPDIR)/libeom_la-eom-metadata-reader-jpg.Plo
[email protected][email protected]@[email protected] source='eom-metadata-reader-jpg.c' object='libeom_la-eom-metadata-reader-jpg.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-metadata-reader-jpg.lo `test -f 'eom-metadata-reader-jpg.c' || echo '$(srcdir)/'`eom-metadata-reader-jpg.c
+
+libeom_la-eom-metadata-reader-png.lo: eom-metadata-reader-png.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-metadata-reader-png.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-metadata-reader-png.Tpo -c -o libeom_la-eom-metadata-reader-png.lo `test -f 'eom-metadata-reader-png.c' || echo '$(srcdir)/'`eom-metadata-reader-png.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-metadata-reader-png.Tpo $(DEPDIR)/libeom_la-eom-metadata-reader-png.Plo
[email protected][email protected]@[email protected] source='eom-metadata-reader-png.c' object='libeom_la-eom-metadata-reader-png.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-metadata-reader-png.lo `test -f 'eom-metadata-reader-png.c' || echo '$(srcdir)/'`eom-metadata-reader-png.c
+
+libeom_la-eom-save-as-dialog-helper.lo: eom-save-as-dialog-helper.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-save-as-dialog-helper.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-save-as-dialog-helper.Tpo -c -o libeom_la-eom-save-as-dialog-helper.lo `test -f 'eom-save-as-dialog-helper.c' || echo '$(srcdir)/'`eom-save-as-dialog-helper.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-save-as-dialog-helper.Tpo $(DEPDIR)/libeom_la-eom-save-as-dialog-helper.Plo
[email protected][email protected]@[email protected] source='eom-save-as-dialog-helper.c' object='libeom_la-eom-save-as-dialog-helper.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-save-as-dialog-helper.lo `test -f 'eom-save-as-dialog-helper.c' || echo '$(srcdir)/'`eom-save-as-dialog-helper.c
+
+libeom_la-eom-print-image-setup.lo: eom-print-image-setup.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-print-image-setup.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-print-image-setup.Tpo -c -o libeom_la-eom-print-image-setup.lo `test -f 'eom-print-image-setup.c' || echo '$(srcdir)/'`eom-print-image-setup.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-print-image-setup.Tpo $(DEPDIR)/libeom_la-eom-print-image-setup.Plo
[email protected][email protected]@[email protected] source='eom-print-image-setup.c' object='libeom_la-eom-print-image-setup.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-print-image-setup.lo `test -f 'eom-print-image-setup.c' || echo '$(srcdir)/'`eom-print-image-setup.c
+
+libeom_la-eom-print-preview.lo: eom-print-preview.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-print-preview.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-print-preview.Tpo -c -o libeom_la-eom-print-preview.lo `test -f 'eom-print-preview.c' || echo '$(srcdir)/'`eom-print-preview.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-print-preview.Tpo $(DEPDIR)/libeom_la-eom-print-preview.Plo
[email protected][email protected]@[email protected] source='eom-print-preview.c' object='libeom_la-eom-print-preview.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-print-preview.lo `test -f 'eom-print-preview.c' || echo '$(srcdir)/'`eom-print-preview.c
+
+libeom_la-eom-print.lo: eom-print.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-print.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-print.Tpo -c -o libeom_la-eom-print.lo `test -f 'eom-print.c' || echo '$(srcdir)/'`eom-print.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-print.Tpo $(DEPDIR)/libeom_la-eom-print.Plo
[email protected][email protected]@[email protected] source='eom-print.c' object='libeom_la-eom-print.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-print.lo `test -f 'eom-print.c' || echo '$(srcdir)/'`eom-print.c
+
+libeom_la-eom-module.lo: eom-module.c
[email protected]__fastdepCC_T[email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-module.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-module.Tpo -c -o libeom_la-eom-module.lo `test -f 'eom-module.c' || echo '$(srcdir)/'`eom-module.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-module.Tpo $(DEPDIR)/libeom_la-eom-module.Plo
[email protected][email protected]@[email protected] source='eom-module.c' object='libeom_la-eom-module.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-module.lo `test -f 'eom-module.c' || echo '$(srcdir)/'`eom-module.c
+
+libeom_la-eom-close-confirmation-dialog.lo: eom-close-confirmation-dialog.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-close-confirmation-dialog.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-close-confirmation-dialog.Tpo -c -o libeom_la-eom-close-confirmation-dialog.lo `test -f 'eom-close-confirmation-dialog.c' || echo '$(srcdir)/'`eom-close-confirmation-dialog.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-close-confirmation-dialog.Tpo $(DEPDIR)/libeom_la-eom-close-confirmation-dialog.Plo
[email protected][email protected]@[email protected] source='eom-close-confirmation-dialog.c' object='libeom_la-eom-close-confirmation-dialog.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-close-confirmation-dialog.lo `test -f 'eom-close-confirmation-dialog.c' || echo '$(srcdir)/'`eom-close-confirmation-dialog.c
+
+libeom_la-eom-plugin.lo: eom-plugin.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-plugin.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-plugin.Tpo -c -o libeom_la-eom-plugin.lo `test -f 'eom-plugin.c' || echo '$(srcdir)/'`eom-plugin.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-plugin.Tpo $(DEPDIR)/libeom_la-eom-plugin.Plo
[email protected][email protected]@[email protected] source='eom-plugin.c' object='libeom_la-eom-plugin.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-plugin.lo `test -f 'eom-plugin.c' || echo '$(srcdir)/'`eom-plugin.c
+
+libeom_la-eom-plugin-manager.lo: eom-plugin-manager.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-plugin-manager.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-plugin-manager.Tpo -c -o libeom_la-eom-plugin-manager.lo `test -f 'eom-plugin-manager.c' || echo '$(srcdir)/'`eom-plugin-manager.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-plugin-manager.Tpo $(DEPDIR)/libeom_la-eom-plugin-manager.Plo
[email protected][email protected]@[email protected] source='eom-plugin-manager.c' object='libeom_la-eom-plugin-manager.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-plugin-manager.lo `test -f 'eom-plugin-manager.c' || echo '$(srcdir)/'`eom-plugin-manager.c
+
+libeom_la-eom-plugin-engine.lo: eom-plugin-engine.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-plugin-engine.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-plugin-engine.Tpo -c -o libeom_la-eom-plugin-engine.lo `test -f 'eom-plugin-engine.c' || echo '$(srcdir)/'`eom-plugin-engine.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-plugin-engine.Tpo $(DEPDIR)/libeom_la-eom-plugin-engine.Plo
[email protected][email protected]@[email protected] source='eom-plugin-engine.c' object='libeom_la-eom-plugin-engine.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-plugin-engine.lo `test -f 'eom-plugin-engine.c' || echo '$(srcdir)/'`eom-plugin-engine.c
+
+libeom_la-uta.lo: uta.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-uta.lo -MD -MP -MF $(DEPDIR)/libeom_la-uta.Tpo -c -o libeom_la-uta.lo `test -f 'uta.c' || echo '$(srcdir)/'`uta.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-uta.Tpo $(DEPDIR)/libeom_la-uta.Plo
[email protected][email protected]@[email protected] source='uta.c' object='libeom_la-uta.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-uta.lo `test -f 'uta.c' || echo '$(srcdir)/'`uta.c
+
+libeom_la-zoom.lo: zoom.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-zoom.lo -MD -MP -MF $(DEPDIR)/libeom_la-zoom.Tpo -c -o libeom_la-zoom.lo `test -f 'zoom.c' || echo '$(srcdir)/'`zoom.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-zoom.Tpo $(DEPDIR)/libeom_la-zoom.Plo
[email protected][email protected]@[email protected] source='zoom.c' object='libeom_la-zoom.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-zoom.lo `test -f 'zoom.c' || echo '$(srcdir)/'`zoom.c
+
+libeom_la-eom-enum-types.lo: eom-enum-types.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-enum-types.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-enum-types.Tpo -c -o libeom_la-eom-enum-types.lo `test -f 'eom-enum-types.c' || echo '$(srcdir)/'`eom-enum-types.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-enum-types.Tpo $(DEPDIR)/libeom_la-eom-enum-types.Plo
[email protected][email protected]@[email protected] source='eom-enum-types.c' object='libeom_la-eom-enum-types.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-enum-types.lo `test -f 'eom-enum-types.c' || echo '$(srcdir)/'`eom-enum-types.c
+
+libeom_la-eom-marshal.lo: eom-marshal.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-marshal.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-marshal.Tpo -c -o libeom_la-eom-marshal.lo `test -f 'eom-marshal.c' || echo '$(srcdir)/'`eom-marshal.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-marshal.Tpo $(DEPDIR)/libeom_la-eom-marshal.Plo
[email protected][email protected]@[email protected] source='eom-marshal.c' object='libeom_la-eom-marshal.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-marshal.lo `test -f 'eom-marshal.c' || echo '$(srcdir)/'`eom-marshal.c
+
+libeom_la-eom-exif-util.lo: eom-exif-util.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-exif-util.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-exif-util.Tpo -c -o libeom_la-eom-exif-util.lo `test -f 'eom-exif-util.c' || echo '$(srcdir)/'`eom-exif-util.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-exif-util.Tpo $(DEPDIR)/libeom_la-eom-exif-util.Plo
[email protected][email protected]@[email protected] source='eom-exif-util.c' object='libeom_la-eom-exif-util.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-exif-util.lo `test -f 'eom-exif-util.c' || echo '$(srcdir)/'`eom-exif-util.c
+
+libeom_la-eom-exif-details.lo: eom-exif-details.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-exif-details.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-exif-details.Tpo -c -o libeom_la-eom-exif-details.lo `test -f 'eom-exif-details.c' || echo '$(srcdir)/'`eom-exif-details.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-exif-details.Tpo $(DEPDIR)/libeom_la-eom-exif-details.Plo
[email protected][email protected]@[email protected] source='eom-exif-details.c' object='libeom_la-eom-exif-details.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-exif-details.lo `test -f 'eom-exif-details.c' || echo '$(srcdir)/'`eom-exif-details.c
+
+libeom_la-eom-python-module.lo: eom-python-module.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-python-module.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-python-module.Tpo -c -o libeom_la-eom-python-module.lo `test -f 'eom-python-module.c' || echo '$(srcdir)/'`eom-python-module.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-python-module.Tpo $(DEPDIR)/libeom_la-eom-python-module.Plo
[email protected][email protected]@[email protected] source='eom-python-module.c' object='libeom_la-eom-python-module.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-python-module.lo `test -f 'eom-python-module.c' || echo '$(srcdir)/'`eom-python-module.c
+
+libeom_la-eom-python-plugin.lo: eom-python-plugin.c
[email protected][email protected] $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -MT libeom_la-eom-python-plugin.lo -MD -MP -MF $(DEPDIR)/libeom_la-eom-python-plugin.Tpo -c -o libeom_la-eom-python-plugin.lo `test -f 'eom-python-plugin.c' || echo '$(srcdir)/'`eom-python-plugin.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/libeom_la-eom-python-plugin.Tpo $(DEPDIR)/libeom_la-eom-python-plugin.Plo
[email protected][email protected] $(AM_V_CC) @AM_BACKSLASH@
[email protected][email protected]@[email protected] source='eom-python-plugin.c' object='libeom_la-eom-python-plugin.lo' libtool=yes @[email protected]
[email protected][email protected] $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libeom_la_CFLAGS) $(CFLAGS) -c -o libeom_la-eom-python-plugin.lo `test -f 'eom-python-plugin.c' || echo '$(srcdir)/'`eom-python-plugin.c
+
+eom-main.o: main.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(eom_CFLAGS) $(CFLAGS) -MT eom-main.o -MD -MP -MF $(DEPDIR)/eom-main.Tpo -c -o eom-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/eom-main.Tpo $(DEPDIR)/eom-main.Po
[email protected][email protected]@[email protected] source='main.c' object='eom-main.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(eom_CFLAGS) $(CFLAGS) -c -o eom-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
+
+eom-main.obj: main.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(eom_CFLAGS) $(CFLAGS) -MT eom-main.obj -MD -MP -MF $(DEPDIR)/eom-main.Tpo -c -o eom-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/eom-main.Tpo $(DEPDIR)/eom-main.Po
[email protected][email protected]@[email protected] source='main.c' object='eom-main.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(eom_CFLAGS) $(CFLAGS) -c -o eom-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-headerDATA: $(header_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(headerdir)" || $(MKDIR_P) "$(DESTDIR)$(headerdir)"
+ @list='$(header_DATA)'; test -n "$(headerdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(headerdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(headerdir)" || exit $$?; \
+ done
+
+uninstall-headerDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(header_DATA)'; test -n "$(headerdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(headerdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(headerdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "[email protected]" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(headerdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-headerDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-headerDATA
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES ctags \
+ dist-hook distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-headerDATA install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-headerDATA
+
+
+eom-enum-types.h: eom-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS)
+ $(AM_V_GEN)(cd $(srcdir) && $(GLIB_MKENUMS) --template eom-enum-types.h.template $(INST_H_FILES)) > [email protected]
+
+eom-enum-types.c: eom-enum-types.c.template $(INST_H_FILES) $(GLIB_MKENUMS)
+ $(AM_V_GEN)(cd $(srcdir) && $(GLIB_MKENUMS) --template eom-enum-types.c.template $(INST_H_FILES)) > [email protected]
+
+eom-marshal.h: eom-marshal.list $(GLIB_GENMARSHAL)
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --header --internal --prefix=eom_marshal > [email protected]
+
+eom-marshal.c: eom-marshal.list $(GLIB_GENMARSHAL)
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --body --header --prefix=eom_marshal > [email protected]
+
[email protected][email protected]: eom-application-service.xml
[email protected][email protected] $(AM_V_GEN)dbus-binding-tool --prefix=eom_application --mode=glib-server --output=eom-application-service.h $<
+
+dist-hook:
+ cd $(distdir); rm -f $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/eom-application-service.xml b/src/eom-application-service.xml
new file mode 100644
index 0000000..6089812
--- /dev/null
+++ b/src/eom-application-service.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/mate/eom/Eom">
+
+ <interface name="org.mate.eom.Application">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="eom_application"/>
+
+ <method name="OpenWindow">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="eom_application_open_window"/>
+ <arg type="u" name="timestamp" direction="in"/>
+ <arg type="y" name="flags" direction="in"/>
+ </method>
+
+ <method name="OpenUris">
+ <annotation name="org.freedesktop.DBus.Glib.CSymbol" value="eom_application_open_uris"/>
+ <arg type="as" name="uris" direction="in"/>
+ <arg type="u" name="timestamp" direction="in"/>
+ <arg type="y" name="flags" direction="in"/>
+ </method>
+
+ </interface>
+
+</node>
diff --git a/src/eom-application.c b/src/eom-application.c
new file mode 100644
index 0000000..2da184d
--- /dev/null
+++ b/src/eom-application.c
@@ -0,0 +1,566 @@
+/* Eye Of Mate - Application Facade
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on evince code (shell/ev-application.h) by:
+ * - Martin Kretzschmar <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-image.h"
+#include "eom-session.h"
+#include "eom-window.h"
+#include "eom-application.h"
+#include "eom-util.h"
+
+#ifdef HAVE_DBUS
+#include "totem-scrsaver.h"
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#ifdef HAVE_DBUS
+#include "eom-application-service.h"
+#include <dbus/dbus-glib-bindings.h>
+
+#define APPLICATION_SERVICE_NAME "org.mate.eom.ApplicationService"
+#endif
+
+static void eom_application_load_accelerators (void);
+static void eom_application_save_accelerators (void);
+
+#define EOM_APPLICATION_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_APPLICATION, EomApplicationPrivate))
+
+G_DEFINE_TYPE (EomApplication, eom_application, G_TYPE_OBJECT);
+
+#ifdef HAVE_DBUS
+
+/**
+ * eom_application_register_service:
+ * @application: An #EomApplication.
+ *
+ * Registers #EomApplication<!-- -->'s DBus service, to allow
+ * remote calls. If the DBus service is already registered,
+ * or there is any other connection error, returns %FALSE.
+ *
+ * Returns: %TRUE if the service was registered succesfully. %FALSE
+ * otherwise.
+ **/
+gboolean
+eom_application_register_service (EomApplication *application)
+{
+ static DBusGConnection *connection = NULL;
+ DBusGProxy *driver_proxy;
+ GError *err = NULL;
+ guint request_name_result;
+
+ if (connection) {
+ g_warning ("Service already registered.");
+ return FALSE;
+ }
+
+ connection = dbus_g_bus_get (DBUS_BUS_STARTER, &err);
+
+ if (connection == NULL) {
+ g_warning ("Service registration failed.");
+ g_error_free (err);
+
+ return FALSE;
+ }
+
+ driver_proxy = dbus_g_proxy_new_for_name (connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ if (!org_freedesktop_DBus_request_name (driver_proxy,
+ APPLICATION_SERVICE_NAME,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ &request_name_result, &err)) {
+ g_warning ("Service registration failed.");
+ g_clear_error (&err);
+ }
+
+ g_object_unref (driver_proxy);
+
+ if (request_name_result == DBUS_REQUEST_NAME_REPLY_EXISTS) {
+ return FALSE;
+ }
+
+ dbus_g_object_type_install_info (EOM_TYPE_APPLICATION,
+ &dbus_glib_eom_application_object_info);
+
+ dbus_g_connection_register_g_object (connection,
+ "/org/mate/eom/Eom",
+ G_OBJECT (application));
+
+ application->scr_saver = totem_scrsaver_new ();
+ g_object_set (application->scr_saver,
+ "reason", _("Running in fullscreen mode"),
+ NULL);
+
+ return TRUE;
+}
+#endif /* ENABLE_DBUS */
+
+static void
+eom_application_class_init (EomApplicationClass *eom_application_class)
+{
+}
+
+static void
+eom_application_init (EomApplication *eom_application)
+{
+ const gchar *dot_dir = eom_util_dot_dir ();
+
+ eom_session_init (eom_application);
+
+ eom_application->toolbars_model = egg_toolbars_model_new ();
+
+ egg_toolbars_model_load_names (eom_application->toolbars_model,
+ EOM_DATA_DIR "/eom-toolbar.xml");
+
+ if (G_LIKELY (dot_dir != NULL))
+ eom_application->toolbars_file = g_build_filename
+ (dot_dir, "eom_toolbar.xml", NULL);
+
+ if (!dot_dir || !egg_toolbars_model_load_toolbars (eom_application->toolbars_model,
+ eom_application->toolbars_file)) {
+
+ egg_toolbars_model_load_toolbars (eom_application->toolbars_model,
+ EOM_DATA_DIR "/eom-toolbar.xml");
+ }
+
+ egg_toolbars_model_set_flags (eom_application->toolbars_model, 0,
+ EGG_TB_MODEL_NOT_REMOVABLE);
+
+ eom_application_load_accelerators ();
+}
+
+/**
+ * eom_application_get_instance:
+ *
+ * Returns a singleton instance of #EomApplication currently running.
+ * If not running yet, it will create one.
+ *
+ * Returns: a running #EomApplication.
+ **/
+EomApplication *
+eom_application_get_instance (void)
+{
+ static EomApplication *instance;
+
+ if (!instance) {
+ instance = EOM_APPLICATION (g_object_new (EOM_TYPE_APPLICATION, NULL));
+ }
+
+ return instance;
+}
+
+static EomWindow *
+eom_application_get_empty_window (EomApplication *application)
+{
+ EomWindow *empty_window = NULL;
+ GList *windows;
+ GList *l;
+
+ g_return_val_if_fail (EOM_IS_APPLICATION (application), NULL);
+
+ windows = eom_application_get_windows (application);
+
+ for (l = windows; l != NULL; l = l->next) {
+ EomWindow *window = EOM_WINDOW (l->data);
+
+ if (eom_window_is_empty (window)) {
+ empty_window = window;
+ break;
+ }
+ }
+
+ g_list_free (windows);
+
+ return empty_window;
+}
+
+/**
+ * eom_application_open_window:
+ * @application: An #EomApplication.
+ * @timestamp: The timestamp of the user interaction which triggered this call
+ * (see gtk_window_present_with_time()).
+ * @flags: A set of #EomStartupFlags influencing a new windows' state.
+ * @error: Return location for a #GError, or NULL to ignore errors.
+ *
+ * Opens and presents an empty #EomWindow to the user. If there is
+ * an empty window already open, this will be used. Otherwise, a
+ * new one will be instantiated.
+ *
+ * Returns: %FALSE if @application is invalid, %TRUE otherwise
+ **/
+gboolean
+eom_application_open_window (EomApplication *application,
+ guint32 timestamp,
+ EomStartupFlags flags,
+ GError **error)
+{
+ GtkWidget *new_window = NULL;
+
+ new_window = GTK_WIDGET (eom_application_get_empty_window (application));
+
+ if (new_window == NULL) {
+ new_window = eom_window_new (flags);
+ }
+
+ g_return_val_if_fail (EOM_IS_APPLICATION (application), FALSE);
+
+ gtk_window_present_with_time (GTK_WINDOW (new_window),
+ timestamp);
+
+ return TRUE;
+}
+
+static EomWindow *
+eom_application_get_file_window (EomApplication *application, GFile *file)
+{
+ EomWindow *file_window = NULL;
+ GList *windows;
+ GList *l;
+
+ g_return_val_if_fail (file != NULL, NULL);
+ g_return_val_if_fail (EOM_IS_APPLICATION (application), NULL);
+
+ windows = gtk_window_list_toplevels ();
+
+ for (l = windows; l != NULL; l = l->next) {
+ if (EOM_IS_WINDOW (l->data)) {
+ EomWindow *window = EOM_WINDOW (l->data);
+
+ if (!eom_window_is_empty (window)) {
+ EomImage *image = eom_window_get_image (window);
+ GFile *window_file;
+
+ window_file = eom_image_get_file (image);
+ if (g_file_equal (window_file, file)) {
+ file_window = window;
+ break;
+ }
+ }
+ }
+ }
+
+ g_list_free (windows);
+
+ return file_window;
+}
+
+static void
+eom_application_show_window (EomWindow *window, gpointer user_data)
+{
+ gtk_window_present_with_time (GTK_WINDOW (window),
+ GPOINTER_TO_UINT (user_data));
+}
+
+/**
+ * eom_application_open_file_list:
+ * @application: An #EomApplication.
+ * @file_list: A list of #GFile<!-- -->s.
+ * @timestamp: The timestamp of the user interaction which triggered this call
+ * (see gtk_window_present_with_time()).
+ * @flags: A set of #EomStartupFlags influencing a new windows' state.
+ * @error: Return location for a #GError, or NULL to ignore errors.
+ *
+ * Opens a list of files in a #EomWindow. If an #EomWindow displaying the first
+ * image in the list is already open, this will be used. Otherwise, an empty
+ * #EomWindow is used, either already existing or newly created.
+ *
+ * Returns: Currently always %TRUE.
+ **/
+gboolean
+eom_application_open_file_list (EomApplication *application,
+ GSList *file_list,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error)
+{
+ EomWindow *new_window = NULL;
+
+ if (file_list != NULL)
+ new_window = eom_application_get_file_window (application,
+ (GFile *) file_list->data);
+
+ if (new_window != NULL) {
+ gtk_window_present_with_time (GTK_WINDOW (new_window),
+ timestamp);
+ return TRUE;
+ }
+
+ new_window = eom_application_get_empty_window (application);
+
+ if (new_window == NULL) {
+ new_window = EOM_WINDOW (eom_window_new (flags));
+ }
+
+ g_signal_connect (new_window,
+ "prepared",
+ G_CALLBACK (eom_application_show_window),
+ GUINT_TO_POINTER (timestamp));
+
+ eom_window_open_file_list (new_window, file_list);
+
+ return TRUE;
+}
+
+/**
+ * eom_application_open_uri_list:
+ * @application: An #EomApplication.
+ * @uri_list: A list of URIs.
+ * @timestamp: The timestamp of the user interaction which triggered this call
+ * (see gtk_window_present_with_time()).
+ * @flags: A set of #EomStartupFlags influencing a new windows' state.
+ * @error: Return location for a #GError, or NULL to ignore errors.
+ *
+ * Opens a list of images, from a list of URIs. See
+ * eom_application_open_file_list() for details.
+ *
+ * Returns: Currently always %TRUE.
+ **/
+gboolean
+eom_application_open_uri_list (EomApplication *application,
+ GSList *uri_list,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error)
+{
+ GSList *file_list = NULL;
+
+ g_return_val_if_fail (EOM_IS_APPLICATION (application), FALSE);
+
+ file_list = eom_util_string_list_to_file_list (uri_list);
+
+ return eom_application_open_file_list (application,
+ file_list,
+ timestamp,
+ flags,
+ error);
+}
+
+#ifdef HAVE_DBUS
+/**
+ * eom_application_open_uris:
+ * @application: an #EomApplication
+ * @uris: A #GList of URI strings.
+ * @timestamp: The timestamp of the user interaction which triggered this call
+ * (see gtk_window_present_with_time()).
+ * @flags: A set of #EomStartupFlags influencing a new windows' state.
+ * @error: Return location for a #GError, or NULL to ignore errors.
+ *
+ * Opens a list of images, from a list of URI strings. See
+ * eom_application_open_file_list() for details.
+ *
+ * Returns: Currently always %TRUE.
+ **/
+gboolean
+eom_application_open_uris (EomApplication *application,
+ gchar **uris,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error)
+{
+ GSList *file_list = NULL;
+
+ file_list = eom_util_strings_to_file_list (uris);
+
+ return eom_application_open_file_list (application, file_list, timestamp,
+ flags, error);
+}
+#endif
+
+/**
+ * eom_application_shutdown:
+ * @application: An #EomApplication.
+ *
+ * Takes care of shutting down the Eye of MATE, and quits.
+ **/
+void
+eom_application_shutdown (EomApplication *application)
+{
+ g_return_if_fail (EOM_IS_APPLICATION (application));
+
+ if (application->toolbars_model) {
+ g_object_unref (application->toolbars_model);
+ application->toolbars_model = NULL;
+
+ g_free (application->toolbars_file);
+ application->toolbars_file = NULL;
+ }
+
+ eom_application_save_accelerators ();
+
+ g_object_unref (application);
+
+ gtk_main_quit ();
+}
+
+/**
+ * eom_application_get_windows:
+ * @application: An #EomApplication.
+ *
+ * Gets the list of existing #EomApplication<!-- -->s. The windows
+ * in this list are not individually referenced, you need to keep
+ * your own references if you want to perform actions that may destroy
+ * them.
+ *
+ * Returns: A new list of #EomWindow<!-- -->s.
+ **/
+GList *
+eom_application_get_windows (EomApplication *application)
+{
+ GList *l, *toplevels;
+ GList *windows = NULL;
+
+ g_return_val_if_fail (EOM_IS_APPLICATION (application), NULL);
+
+ toplevels = gtk_window_list_toplevels ();
+
+ for (l = toplevels; l != NULL; l = l->next) {
+ if (EOM_IS_WINDOW (l->data)) {
+ windows = g_list_append (windows, l->data);
+ }
+ }
+
+ g_list_free (toplevels);
+
+ return windows;
+}
+
+/**
+ * eom_application_get_toolbars_model:
+ * @application: An #EomApplication.
+ *
+ * Retrieves the #EggToolbarsModel for the toolbar in #EomApplication.
+ *
+ * Returns: An #EggToolbarsModel.
+ **/
+EggToolbarsModel *
+eom_application_get_toolbars_model (EomApplication *application)
+{
+ g_return_val_if_fail (EOM_IS_APPLICATION (application), NULL);
+
+ return application->toolbars_model;
+}
+
+/**
+ * eom_application_save_toolbars_model:
+ * @application: An #EomApplication.
+ *
+ * Causes the saving of the model of the toolbar in #EomApplication to a file.
+ **/
+void
+eom_application_save_toolbars_model (EomApplication *application)
+{
+ if (G_LIKELY(application->toolbars_file != NULL))
+ egg_toolbars_model_save_toolbars (application->toolbars_model,
+ application->toolbars_file,
+ "1.0");
+}
+
+/**
+ * eom_application_reset_toolbars_model:
+ * @app: an #EomApplication
+ *
+ * Restores the toolbars model to the defaults.
+ **/
+void
+eom_application_reset_toolbars_model (EomApplication *app)
+{
+ g_return_if_fail (EOM_IS_APPLICATION (app));
+
+ g_object_unref (app->toolbars_model);
+
+ app->toolbars_model = egg_toolbars_model_new ();
+
+ egg_toolbars_model_load_names (app->toolbars_model,
+ EOM_DATA_DIR "/eom-toolbar.xml");
+ egg_toolbars_model_load_toolbars (app->toolbars_model,
+ EOM_DATA_DIR "/eom-toolbar.xml");
+ egg_toolbars_model_set_flags (app->toolbars_model, 0,
+ EGG_TB_MODEL_NOT_REMOVABLE);
+}
+
+#ifdef HAVE_DBUS
+/**
+ * eom_application_screensaver_enable:
+ * @application: an #EomApplication.
+ *
+ * Enables the screensaver. Usually necessary after a call to
+ * eom_application_screensaver_disable().
+ **/
+void
+eom_application_screensaver_enable (EomApplication *application)
+{
+ if (application->scr_saver)
+ totem_scrsaver_enable (application->scr_saver);
+}
+
+/**
+ * eom_application_screensaver_disable:
+ * @application: an #EomApplication.
+ *
+ * Disables the screensaver. Useful when the application is in fullscreen or
+ * similar mode.
+ **/
+void
+eom_application_screensaver_disable (EomApplication *application)
+{
+ if (application->scr_saver)
+ totem_scrsaver_disable (application->scr_saver);
+}
+#endif
+
+static void
+eom_application_load_accelerators (void)
+{
+ gchar *accelfile = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "accels",
+ "eom", NULL);
+
+ /* gtk_accel_map_load does nothing if the file does not exist */
+ gtk_accel_map_load (accelfile);
+ g_free (accelfile);
+}
+
+static void
+eom_application_save_accelerators (void)
+{
+ gchar *accelfile = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "accels",
+ "eom", NULL);
+
+ gtk_accel_map_save (accelfile);
+ g_free (accelfile);
+}
diff --git a/src/eom-application.h b/src/eom-application.h
new file mode 100644
index 0000000..8f4485a
--- /dev/null
+++ b/src/eom-application.h
@@ -0,0 +1,118 @@
+/* Eye Of Mate - Application Facade
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on evince code (shell/ev-application.h) by:
+ * - Martin Kretzschmar <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_APPLICATION_H__
+#define __EOM_APPLICATION_H__
+
+#include "eom-window.h"
+#include "egg-toolbars-model.h"
+
+#ifdef HAVE_DBUS
+#include "totem-scrsaver.h"
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EomApplication EomApplication;
+typedef struct _EomApplicationClass EomApplicationClass;
+typedef struct _EomApplicationPrivate EomApplicationPrivate;
+
+#define EOM_TYPE_APPLICATION (eom_application_get_type ())
+#define EOM_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_APPLICATION, EomApplication))
+#define EOM_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_APPLICATION, EomApplicationClass))
+#define EOM_IS_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_APPLICATION))
+#define EOM_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EOM_TYPE_APPLICATION))
+#define EOM_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EOM_TYPE_APPLICATION, EomApplicationClass))
+
+#define EOM_APP (eom_application_get_instance ())
+
+struct _EomApplication {
+ GObject base_instance;
+
+ EggToolbarsModel *toolbars_model;
+ gchar *toolbars_file;
+#ifdef HAVE_DBUS
+ TotemScrsaver *scr_saver;
+#endif
+};
+
+struct _EomApplicationClass {
+ GObjectClass parent_class;
+};
+
+GType eom_application_get_type (void) G_GNUC_CONST;
+
+EomApplication *eom_application_get_instance (void);
+
+#ifdef HAVE_DBUS
+gboolean eom_application_register_service (EomApplication *application);
+#endif
+
+void eom_application_shutdown (EomApplication *application);
+
+gboolean eom_application_open_window (EomApplication *application,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error);
+
+gboolean eom_application_open_uri_list (EomApplication *application,
+ GSList *uri_list,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error);
+
+gboolean eom_application_open_file_list (EomApplication *application,
+ GSList *file_list,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error);
+
+#ifdef HAVE_DBUS
+gboolean eom_application_open_uris (EomApplication *application,
+ gchar **uris,
+ guint timestamp,
+ EomStartupFlags flags,
+ GError **error);
+#endif
+
+GList *eom_application_get_windows (EomApplication *application);
+
+EggToolbarsModel *eom_application_get_toolbars_model (EomApplication *application);
+
+void eom_application_save_toolbars_model (EomApplication *application);
+
+void eom_application_reset_toolbars_model (EomApplication *app);
+
+#ifdef HAVE_DBUS
+void eom_application_screensaver_enable (EomApplication *application);
+
+void eom_application_screensaver_disable (EomApplication *application);
+#endif
+
+G_END_DECLS
+
+#endif /* __EOM_APPLICATION_H__ */
diff --git a/src/eom-close-confirmation-dialog.c b/src/eom-close-confirmation-dialog.c
new file mode 100644
index 0000000..0798c5e
--- /dev/null
+++ b/src/eom-close-confirmation-dialog.c
@@ -0,0 +1,698 @@
+/*
+ * eom-close-confirmation-dialog.c
+ * This file is part of eom
+ *
+ * Author: Marcus Carlson <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-close-confirmation.c) by gedit Team
+ *
+ * Copyright (C) 2004-2009 MATE Foundation
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "eom-close-confirmation-dialog.h"
+#include <eom-window.h>
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_UNSAVED_IMAGES
+};
+
+/* Mode */
+enum
+{
+ SINGLE_IMG_MODE,
+ MULTIPLE_IMGS_MODE
+};
+
+/* Columns */
+enum
+{
+ SAVE_COLUMN,
+ IMAGE_COLUMN,
+ NAME_COLUMN,
+ IMG_COLUMN, /* a handy pointer to the image */
+ N_COLUMNS
+};
+
+struct _EomCloseConfirmationDialogPrivate
+{
+ GList *unsaved_images;
+
+ GList *selected_images;
+
+ GtkTreeModel *list_store;
+ GtkCellRenderer *toggle_renderer;
+};
+
+
+#define EOM_CLOSE_CONFIRMATION_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ EOM_TYPE_CLOSE_CONFIRMATION_DIALOG, \
+ EomCloseConfirmationDialogPrivate))
+
+#define GET_MODE(priv) (((priv->unsaved_images != NULL) && \
+ (priv->unsaved_images->next == NULL)) ? \
+ SINGLE_IMG_MODE : MULTIPLE_IMGS_MODE)
+
+#define IMAGE_COLUMN_HEIGHT 40
+
+G_DEFINE_TYPE(EomCloseConfirmationDialog, eom_close_confirmation_dialog, GTK_TYPE_DIALOG)
+
+static void set_unsaved_image (EomCloseConfirmationDialog *dlg,
+ const GList *list);
+
+static GList *get_selected_imgs (GtkTreeModel *store);
+
+static GdkPixbuf *
+eom_close_confirmation_dialog_get_icon (const gchar *icon_name)
+{
+ GError *error = NULL;
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf;
+
+ icon_theme = gtk_icon_theme_get_default ();
+
+ pixbuf = gtk_icon_theme_load_icon (icon_theme,
+ icon_name,
+ IMAGE_COLUMN_HEIGHT,
+ 0,
+ &error);
+
+ if (!pixbuf) {
+ g_warning ("Couldn't load icon: %s", error->message);
+ g_error_free (error);
+ }
+
+ return pixbuf;
+}
+
+static GdkPixbuf*
+get_nothumb_pixbuf (void)
+{
+ static GOnce nothumb_once = G_ONCE_INIT;
+ g_once (&nothumb_once, (GThreadFunc) eom_close_confirmation_dialog_get_icon, "image-x-generic");
+ return GDK_PIXBUF (g_object_ref (nothumb_once.retval));
+}
+
+/* Since we connect in the costructor we are sure this handler will be called
+ * before the user ones
+ */
+static void
+response_cb (EomCloseConfirmationDialog *dlg,
+ gint response_id,
+ gpointer data)
+{
+ EomCloseConfirmationDialogPrivate *priv;
+
+ g_return_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg));
+
+ priv = dlg->priv;
+
+ if (priv->selected_images != NULL)
+ g_list_free (priv->selected_images);
+
+ if (response_id == GTK_RESPONSE_YES)
+ {
+ if (GET_MODE (priv) == SINGLE_IMG_MODE)
+ {
+ priv->selected_images =
+ g_list_copy (priv->unsaved_images);
+ }
+ else
+ {
+ g_return_if_fail (priv->list_store);
+
+ priv->selected_images =
+ get_selected_imgs (priv->list_store);
+ }
+ }
+ else
+ priv->selected_images = NULL;
+}
+
+static void
+add_buttons (EomCloseConfirmationDialog *dlg)
+{
+ gtk_dialog_add_button (GTK_DIALOG (dlg),
+ _("Close _without Saving"),
+ GTK_RESPONSE_NO);
+
+ gtk_dialog_add_button (GTK_DIALOG (dlg),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_add_button (GTK_DIALOG (dlg),
+ GTK_STOCK_SAVE,
+ GTK_RESPONSE_YES);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dlg),
+ GTK_RESPONSE_YES);
+}
+
+static void
+eom_close_confirmation_dialog_init (EomCloseConfirmationDialog *dlg)
+{
+ AtkObject *atk_obj;
+
+ dlg->priv = EOM_CLOSE_CONFIRMATION_DIALOG_GET_PRIVATE (dlg);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), 14);
+ gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), TRUE);
+
+ gtk_window_set_title (GTK_WINDOW (dlg), "");
+
+ gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (dlg));
+ atk_object_set_role (atk_obj, ATK_ROLE_ALERT);
+ atk_object_set_name (atk_obj, _("Question"));
+
+ g_signal_connect (dlg,
+ "response",
+ G_CALLBACK (response_cb),
+ NULL);
+}
+
+static void
+eom_close_confirmation_dialog_finalize (GObject *object)
+{
+ EomCloseConfirmationDialogPrivate *priv;
+
+ priv = EOM_CLOSE_CONFIRMATION_DIALOG (object)->priv;
+
+ if (priv->unsaved_images != NULL)
+ g_list_free (priv->unsaved_images);
+
+ if (priv->selected_images != NULL)
+ g_list_free (priv->selected_images);
+
+ /* Call the parent's destructor */
+ G_OBJECT_CLASS (eom_close_confirmation_dialog_parent_class)->finalize (object);
+}
+
+static void
+eom_close_confirmation_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EomCloseConfirmationDialog *dlg;
+
+ dlg = EOM_CLOSE_CONFIRMATION_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_UNSAVED_IMAGES:
+ set_unsaved_image (dlg, g_value_get_pointer (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+eom_close_confirmation_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EomCloseConfirmationDialogPrivate *priv;
+
+ priv = EOM_CLOSE_CONFIRMATION_DIALOG (object)->priv;
+
+ switch( prop_id )
+ {
+ case PROP_UNSAVED_IMAGES:
+ g_value_set_pointer (value, priv->unsaved_images);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+eom_close_confirmation_dialog_class_init (EomCloseConfirmationDialogClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = eom_close_confirmation_dialog_set_property;
+ gobject_class->get_property = eom_close_confirmation_dialog_get_property;
+ gobject_class->finalize = eom_close_confirmation_dialog_finalize;
+
+ g_type_class_add_private (klass, sizeof (EomCloseConfirmationDialogPrivate));
+
+ g_object_class_install_property (gobject_class,
+ PROP_UNSAVED_IMAGES,
+ g_param_spec_pointer ("unsaved_images",
+ "Unsaved Images",
+ "List of Unsaved Images",
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY)));
+}
+
+static GList *
+get_selected_imgs (GtkTreeModel *store)
+{
+ GList *list;
+ gboolean valid;
+ GtkTreeIter iter;
+
+ list = NULL;
+ valid = gtk_tree_model_get_iter_first (store, &iter);
+
+ while (valid)
+ {
+ gboolean to_save;
+ EomImage *img;
+
+ gtk_tree_model_get (store, &iter,
+ SAVE_COLUMN, &to_save,
+ IMG_COLUMN, &img,
+ -1);
+ if (to_save)
+ list = g_list_prepend (list, img);
+
+ valid = gtk_tree_model_iter_next (store, &iter);
+ }
+
+ list = g_list_reverse (list);
+
+ return list;
+}
+
+GList *
+eom_close_confirmation_dialog_get_selected_images (EomCloseConfirmationDialog *dlg)
+{
+ g_return_val_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
+
+ return g_list_copy (dlg->priv->selected_images);
+}
+
+GtkWidget *
+eom_close_confirmation_dialog_new (GtkWindow *parent,
+ GList *unsaved_images)
+{
+ GtkWidget *dlg;
+ GtkWindowGroup *wg;
+
+ g_return_val_if_fail (unsaved_images != NULL, NULL);
+
+ dlg = GTK_WIDGET (g_object_new (EOM_TYPE_CLOSE_CONFIRMATION_DIALOG,
+ "unsaved_images", unsaved_images,
+ NULL));
+ g_return_val_if_fail (dlg != NULL, NULL);
+
+ if (parent != NULL)
+ {
+ wg = gtk_window_get_group (parent);
+
+ /* gtk_window_get_group returns a default group when the given
+ * window doesn't have a group. Explicitly add the window to
+ * the group here to make sure it's actually in the returned
+ * group. It makes no difference if it is already. */
+ gtk_window_group_add_window (wg, parent);
+ gtk_window_group_add_window (wg, GTK_WINDOW (dlg));
+
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
+ }
+
+ return dlg;
+}
+
+GtkWidget *
+eom_close_confirmation_dialog_new_single (GtkWindow *parent,
+ EomImage *image)
+{
+ GtkWidget *dlg;
+ GList *unsaved_images;
+ g_return_val_if_fail (image != NULL, NULL);
+
+ unsaved_images = g_list_prepend (NULL, image);
+
+ dlg = eom_close_confirmation_dialog_new (parent,
+ unsaved_images);
+
+ g_list_free (unsaved_images);
+
+ return dlg;
+}
+
+static gchar *
+get_text_secondary_label (EomImage *image)
+{
+ gchar *secondary_msg;
+
+ secondary_msg = g_strdup (_("If you don't save, your changes will be lost."));
+
+ return secondary_msg;
+}
+
+static void
+build_single_img_dialog (EomCloseConfirmationDialog *dlg)
+{
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *primary_label;
+ GtkWidget *secondary_label;
+ GtkWidget *image;
+ EomImage *img;
+ const gchar *image_name;
+ gchar *str;
+ gchar *markup_str;
+
+ g_return_if_fail (dlg->priv->unsaved_images->data != NULL);
+ img = EOM_IMAGE (dlg->priv->unsaved_images->data);
+
+ /* Image */
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+
+ /* Primary label */
+ primary_label = gtk_label_new (NULL);
+ gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
+ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (primary_label), 0.0, 0.5);
+ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+ image_name = eom_image_get_caption (img);
+
+ str = g_markup_printf_escaped (_("Save changes to image \"%s\" before closing?"),
+ image_name);
+ markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
+ g_free (str);
+
+ gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
+ g_free (markup_str);
+
+ /* Secondary label */
+ str = get_text_secondary_label (img);
+
+ secondary_label = gtk_label_new (str);
+ g_free (str);
+ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (secondary_label), 0.0, 0.5);
+ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (vbox), secondary_label, FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+ hbox,
+ FALSE,
+ FALSE,
+ 0);
+
+ add_buttons (dlg);
+
+ gtk_widget_show_all (hbox);
+}
+
+static void
+populate_model (GtkTreeModel *store, GList *imgs)
+{
+ GtkTreeIter iter;
+
+ while (imgs != NULL)
+ {
+ EomImage *img;
+ const gchar *name;
+ GdkPixbuf *buf = NULL;
+ GdkPixbuf *buf_scaled = NULL;
+ int width;
+ double ratio;
+
+ img = EOM_IMAGE (imgs->data);
+
+ name = eom_image_get_caption (img);
+ buf = eom_image_get_thumbnail (img);
+
+ if (buf) {
+ ratio = IMAGE_COLUMN_HEIGHT / (double) gdk_pixbuf_get_height (buf);
+ width = (int) (gdk_pixbuf_get_width (buf) * ratio);
+ buf_scaled = gdk_pixbuf_scale_simple (buf, width, IMAGE_COLUMN_HEIGHT, GDK_INTERP_BILINEAR);
+ } else
+ buf_scaled = get_nothumb_pixbuf ();
+
+ gtk_list_store_append (GTK_LIST_STORE (store), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+ SAVE_COLUMN, TRUE,
+ IMAGE_COLUMN, buf_scaled,
+ NAME_COLUMN, name,
+ IMG_COLUMN, img,
+ -1);
+
+ imgs = g_list_next (imgs);
+ g_object_unref (buf_scaled);
+ }
+}
+
+static void
+save_toggled (GtkCellRendererToggle *renderer, gchar *path_str, GtkTreeModel *store)
+{
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+ GtkTreeIter iter;
+ gboolean active;
+
+ gtk_tree_model_get_iter (store, &iter, path);
+ gtk_tree_model_get (store, &iter, SAVE_COLUMN, &active, -1);
+
+ active ^= 1;
+
+ gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+ SAVE_COLUMN, active, -1);
+
+ gtk_tree_path_free (path);
+}
+
+static GtkWidget *
+create_treeview (EomCloseConfirmationDialogPrivate *priv)
+{
+ GtkListStore *store;
+ GtkWidget *treeview;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ treeview = gtk_tree_view_new ();
+ gtk_widget_set_size_request (treeview, 260, 120);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+ gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
+
+ /* Create and populate the model */
+ store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
+ populate_model (GTK_TREE_MODEL (store), priv->unsaved_images);
+
+ /* Set model to the treeview */
+ gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ priv->list_store = GTK_TREE_MODEL (store);
+
+ /* Add columns */
+ priv->toggle_renderer = renderer = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (renderer, "toggled",
+ G_CALLBACK (save_toggled), store);
+
+ column = gtk_tree_view_column_new_with_attributes ("Save?",
+ renderer,
+ "active",
+ SAVE_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+
+ column = gtk_tree_view_column_new_with_attributes ("Image",
+ renderer,
+ "pixbuf",
+ IMAGE_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Name",
+ renderer,
+ "text",
+ NAME_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+ return treeview;
+}
+
+static void
+build_multiple_imgs_dialog (EomCloseConfirmationDialog *dlg)
+{
+ EomCloseConfirmationDialogPrivate *priv;
+ GtkWidget *hbox;
+ GtkWidget *image;
+ GtkWidget *vbox;
+ GtkWidget *primary_label;
+ GtkWidget *vbox2;
+ GtkWidget *select_label;
+ GtkWidget *scrolledwindow;
+ GtkWidget *treeview;
+ GtkWidget *secondary_label;
+ gchar *str;
+ gchar *markup_str;
+
+ priv = dlg->priv;
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+ hbox, TRUE, TRUE, 0);
+
+ /* Image */
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+ /* Primary label */
+ primary_label = gtk_label_new (NULL);
+ gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
+ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (primary_label), 0.0, 0.5);
+ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+ str = g_strdup_printf (
+ ngettext ("There is %d image with unsaved changes. "
+ "Save changes before closing?",
+ "There are %d images with unsaved changes. "
+ "Save changes before closing?",
+ g_list_length (priv->unsaved_images)),
+ g_list_length (priv->unsaved_images));
+
+ markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
+ g_free (str);
+
+ gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
+ g_free (markup_str);
+ gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
+
+ vbox2 = gtk_vbox_new (FALSE, 8);
+ gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
+
+ select_label = gtk_label_new_with_mnemonic (_("S_elect the images you want to save:"));
+
+ gtk_box_pack_start (GTK_BOX (vbox2), select_label, FALSE, FALSE, 0);
+ gtk_label_set_line_wrap (GTK_LABEL (select_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (select_label), 0.0, 0.5);
+
+ scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
+ GTK_SHADOW_IN);
+
+ treeview = create_treeview (priv);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow), treeview);
+
+ /* Secondary label */
+ secondary_label = gtk_label_new (_("If you don't save, "
+ "all your changes will be lost."));
+
+ gtk_box_pack_start (GTK_BOX (vbox2), secondary_label, FALSE, FALSE, 0);
+ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5);
+ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (select_label), treeview);
+
+ add_buttons (dlg);
+
+ gtk_widget_show_all (hbox);
+}
+
+static void
+set_unsaved_image (EomCloseConfirmationDialog *dlg,
+ const GList *list)
+{
+ EomCloseConfirmationDialogPrivate *priv;
+
+ g_return_if_fail (list != NULL);
+
+ priv = dlg->priv;
+ g_return_if_fail (priv->unsaved_images == NULL);
+
+ priv->unsaved_images = g_list_copy ((GList *)list);
+
+ if (GET_MODE (priv) == SINGLE_IMG_MODE)
+ {
+ build_single_img_dialog (dlg);
+ }
+ else
+ {
+ build_multiple_imgs_dialog (dlg);
+ }
+}
+
+const GList *
+eom_close_confirmation_dialog_get_unsaved_images (EomCloseConfirmationDialog *dlg)
+{
+ g_return_val_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
+
+ return dlg->priv->unsaved_images;
+}
+
+void
+eom_close_confirmation_dialog_set_sensitive (EomCloseConfirmationDialog *dlg,
+ gboolean value)
+{
+ GtkWidget *action_area;
+
+ g_return_if_fail (EOM_IS_CLOSE_CONFIRMATION_DIALOG (dlg));
+
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (dlg));
+ gtk_widget_set_sensitive (action_area, value);
+
+ if (dlg->priv->toggle_renderer)
+ gtk_cell_renderer_toggle_set_activatable (GTK_CELL_RENDERER_TOGGLE (dlg->priv->toggle_renderer), value);
+}
diff --git a/src/eom-close-confirmation-dialog.h b/src/eom-close-confirmation-dialog.h
new file mode 100644
index 0000000..3c5f44e
--- /dev/null
+++ b/src/eom-close-confirmation-dialog.h
@@ -0,0 +1,79 @@
+/*
+ * eom-close-confirmation-dialog.h
+ * This file is part of eom
+ *
+ * Author: Marcus Carlson <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-close-confirmation.h) by gedit Team
+ *
+ * Copyright (C) 2004-2009 MATE Foundation
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_CLOSE_CONFIRMATION_DIALOG_H__
+#define __EOM_CLOSE_CONFIRMATION_DIALOG_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <eom-image.h>
+
+#define EOM_TYPE_CLOSE_CONFIRMATION_DIALOG (eom_close_confirmation_dialog_get_type ())
+#define EOM_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_CLOSE_CONFIRMATION_DIALOG, EomCloseConfirmationDialog))
+#define EOM_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EOM_TYPE_CLOSE_CONFIRMATION_DIALOG, EomCloseConfirmationDialogClass))
+#define EOM_IS_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_CLOSE_CONFIRMATION_DIALOG))
+#define EOM_IS_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_CLOSE_CONFIRMATION_DIALOG))
+#define EOM_CLOSE_CONFIRMATION_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),EOM_TYPE_CLOSE_CONFIRMATION_DIALOG, EomCloseConfirmationDialogClass))
+
+typedef struct _EomCloseConfirmationDialog EomCloseConfirmationDialog;
+typedef struct _EomCloseConfirmationDialogClass EomCloseConfirmationDialogClass;
+typedef struct _EomCloseConfirmationDialogPrivate EomCloseConfirmationDialogPrivate;
+
+struct _EomCloseConfirmationDialog
+{
+ GtkDialog parent;
+
+ /*< private > */
+ EomCloseConfirmationDialogPrivate *priv;
+};
+
+struct _EomCloseConfirmationDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType eom_close_confirmation_dialog_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkWidget *eom_close_confirmation_dialog_new (GtkWindow *parent,
+ GList *unsaved_documents);
+G_GNUC_INTERNAL
+GtkWidget *eom_close_confirmation_dialog_new_single (GtkWindow *parent,
+ EomImage *image);
+
+G_GNUC_INTERNAL
+const GList *eom_close_confirmation_dialog_get_unsaved_images (EomCloseConfirmationDialog *dlg);
+
+G_GNUC_INTERNAL
+GList *eom_close_confirmation_dialog_get_selected_images (EomCloseConfirmationDialog *dlg);
+
+G_GNUC_INTERNAL
+void eom_close_confirmation_dialog_set_sensitive (EomCloseConfirmationDialog *dlg, gboolean value);
+
+#endif /* __EOM_CLOSE_CONFIRMATION_DIALOG_H__ */
+
diff --git a/src/eom-config-keys.h b/src/eom-config-keys.h
new file mode 100644
index 0000000..7d7074c
--- /dev/null
+++ b/src/eom-config-keys.h
@@ -0,0 +1,63 @@
+/* Eye Of Mate - MateConf Keys Macros
+ *
+ * Copyright (C) 2000-2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on code by:
+ * - Federico Mena-Quintero <[email protected]>
+ * - Jens Finke <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_CONFIG_KEYS_H__
+#define __EOM_CONFIG_KEYS_H__
+
+#define EOM_CONF_DIR "/apps/eom"
+
+#define EOM_CONF_DESKTOP_WALLPAPER "/desktop/mate/background/picture_filename"
+#define EOM_CONF_DESKTOP_CAN_SAVE "/desktop/mate/lockdown/disable_save_to_disk"
+#define EOM_CONF_DESKTOP_CAN_PRINT "/desktop/mate/lockdown/disable_printing"
+#define EOM_CONF_DESKTOP_CAN_SETUP_PAGE "/desktop/mate/lockdown/disable_print_setup"
+
+#define EOM_CONF_VIEW_BACKGROUND_COLOR "/apps/eom/view/background-color"
+#define EOM_CONF_VIEW_INTERPOLATE "/apps/eom/view/interpolate"
+#define EOM_CONF_VIEW_EXTRAPOLATE "/apps/eom/view/extrapolate"
+#define EOM_CONF_VIEW_SCROLL_WHEEL_ZOOM "/apps/eom/view/scroll_wheel_zoom"
+#define EOM_CONF_VIEW_ZOOM_MULTIPLIER "/apps/eom/view/zoom_multiplier"
+#define EOM_CONF_VIEW_AUTOROTATE "/apps/eom/view/autorotate"
+#define EOM_CONF_VIEW_TRANSPARENCY "/apps/eom/view/transparency"
+#define EOM_CONF_VIEW_TRANS_COLOR "/apps/eom/view/trans_color"
+#define EOM_CONF_VIEW_USE_BG_COLOR "/apps/eom/view/use-background-color"
+
+#define EOM_CONF_FULLSCREEN_LOOP "/apps/eom/full_screen/loop"
+#define EOM_CONF_FULLSCREEN_UPSCALE "/apps/eom/full_screen/upscale"
+#define EOM_CONF_FULLSCREEN_SECONDS "/apps/eom/full_screen/seconds"
+
+#define EOM_CONF_UI_TOOLBAR "/apps/eom/ui/toolbar"
+#define EOM_CONF_UI_STATUSBAR "/apps/eom/ui/statusbar"
+#define EOM_CONF_UI_IMAGE_COLLECTION "/apps/eom/ui/image_collection"
+#define EOM_CONF_UI_IMAGE_COLLECTION_POSITION "/apps/eom/ui/image_collection_position"
+#define EOM_CONF_UI_IMAGE_COLLECTION_RESIZABLE "/apps/eom/ui/image_collection_resizable"
+#define EOM_CONF_UI_SIDEBAR "/apps/eom/ui/sidebar"
+#define EOM_CONF_UI_SCROLL_BUTTONS "/apps/eom/ui/scroll_buttons"
+#define EOM_CONF_UI_DISABLE_TRASH_CONFIRMATION "/apps/eom/ui/disable_trash_confirmation"
+#define EOM_CONF_UI_FILECHOOSER_XDG_FALLBACK "/apps/eom/ui/filechooser_xdg_fallback"
+#define EOM_CONF_UI_PROPSDIALOG_NETBOOK_MODE "/apps/eom/ui/propsdialog_netbook_mode"
+
+#define EOM_CONF_PLUGINS_ACTIVE_PLUGINS "/apps/eom/plugins/active_plugins"
+
+#endif /* __EOM_CONFIG_KEYS_H__ */
diff --git a/src/eom-debug.c b/src/eom-debug.c
new file mode 100644
index 0000000..6d373af
--- /dev/null
+++ b/src/eom-debug.c
@@ -0,0 +1,160 @@
+/* Eye Of Mate - Debugging
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-debug.h) by:
+ * - Alex Roberts <[email protected]>
+ * - Evan Lawrence <[email protected]>
+ * - Chema Celorio <[email protected]>
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "eom-debug.h"
+
+#define ENABLE_PROFILING
+
+#ifdef ENABLE_PROFILING
+static GTimer *timer = NULL;
+static gdouble last = 0.0;
+#endif
+
+static EomDebugSection debug = EOM_NO_DEBUG;
+
+void
+eom_debug_init (void)
+{
+ if (g_getenv ("EOM_DEBUG") != NULL)
+ {
+ /* Enable all debugging */
+ debug = ~EOM_NO_DEBUG;
+ goto out;
+ }
+
+ if (g_getenv ("EOM_DEBUG_WINDOW") != NULL)
+ debug = debug | EOM_DEBUG_WINDOW;
+
+ if (g_getenv ("EOM_DEBUG_VIEW") != NULL)
+ debug = debug | EOM_DEBUG_VIEW;
+
+ if (g_getenv ("EOM_DEBUG_JOBS") != NULL)
+ debug = debug | EOM_DEBUG_JOBS;
+
+ if (g_getenv ("EOM_DEBUG_THUMBNAIL") != NULL)
+ debug = debug | EOM_DEBUG_THUMBNAIL;
+
+ if (g_getenv ("EOM_DEBUG_IMAGE_DATA") != NULL)
+ debug = debug | EOM_DEBUG_IMAGE_DATA;
+
+ if (g_getenv ("EOM_DEBUG_IMAGE_LOAD") != NULL)
+ debug = debug | EOM_DEBUG_IMAGE_LOAD;
+
+ if (g_getenv ("EOM_DEBUG_IMAGE_SAVE") != NULL)
+ debug = debug | EOM_DEBUG_IMAGE_SAVE;
+
+ if (g_getenv ("EOM_DEBUG_LIST_STORE") != NULL)
+ debug = debug | EOM_DEBUG_LIST_STORE;
+
+ if (g_getenv ("EOM_DEBUG_PREFERENCES") != NULL)
+ debug = debug | EOM_DEBUG_PREFERENCES;
+
+ if (g_getenv ("EOM_DEBUG_PRINTING") != NULL)
+ debug = debug | EOM_DEBUG_PRINTING;
+
+ if (g_getenv ("EOM_DEBUG_LCMS") != NULL)
+ debug = debug | EOM_DEBUG_LCMS;
+
+ if (g_getenv ("EOM_DEBUG_PLUGINS") != NULL)
+ debug = debug | EOM_DEBUG_PLUGINS;
+
+out:
+
+#ifdef ENABLE_PROFILING
+ if (debug != EOM_NO_DEBUG)
+ timer = g_timer_new ();
+#endif
+ return;
+}
+
+void
+eom_debug_message (EomDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...)
+{
+ if (G_UNLIKELY (debug & section))
+ {
+#ifdef ENABLE_PROFILING
+ gdouble seconds;
+#endif
+
+ va_list args;
+ gchar *msg;
+
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ msg = g_strdup_vprintf (format, args);
+ va_end (args);
+
+#ifdef ENABLE_PROFILING
+ g_return_if_fail (timer != NULL);
+
+ seconds = g_timer_elapsed (timer, NULL);
+ g_print ("[%f (%f)] %s:%d (%s) %s\n",
+ seconds, seconds - last, file, line, function, msg);
+ last = seconds;
+#else
+ g_print ("%s:%d (%s) %s\n", file, line, function, msg);
+#endif
+
+ fflush (stdout);
+
+ g_free (msg);
+ }
+}
+
+void eom_debug (EomDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function)
+{
+ if (G_UNLIKELY (debug & section))
+ {
+#ifdef ENABLE_PROFILING
+ gdouble seconds;
+
+ g_return_if_fail (timer != NULL);
+
+ seconds = g_timer_elapsed (timer, NULL);
+ g_print ("[%f (%f)] %s:%d (%s)\n",
+ seconds, seconds - last, file, line, function);
+ last = seconds;
+#else
+ g_print ("%s:%d (%s)\n", file, line, function);
+#endif
+ fflush (stdout);
+ }
+}
diff --git a/src/eom-debug.h b/src/eom-debug.h
new file mode 100644
index 0000000..bde758c
--- /dev/null
+++ b/src/eom-debug.h
@@ -0,0 +1,75 @@
+/* Eye Of Mate - Debugging
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-debug.h) by:
+ * - Alex Roberts <[email protected]>
+ * - Evan Lawrence <[email protected]>
+ * - Chema Celorio <[email protected]>
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_DEBUG_H__
+#define __EOM_DEBUG_H__
+
+#include <glib.h>
+
+typedef enum {
+ EOM_NO_DEBUG = 0,
+ EOM_DEBUG_WINDOW = 1 << 0,
+ EOM_DEBUG_VIEW = 1 << 1,
+ EOM_DEBUG_JOBS = 1 << 2,
+ EOM_DEBUG_THUMBNAIL = 1 << 3,
+ EOM_DEBUG_IMAGE_DATA = 1 << 4,
+ EOM_DEBUG_IMAGE_LOAD = 1 << 5,
+ EOM_DEBUG_IMAGE_SAVE = 1 << 6,
+ EOM_DEBUG_LIST_STORE = 1 << 7,
+ EOM_DEBUG_PREFERENCES = 1 << 8,
+ EOM_DEBUG_PRINTING = 1 << 9,
+ EOM_DEBUG_LCMS = 1 << 10,
+ EOM_DEBUG_PLUGINS = 1 << 11
+} EomDebugSection;
+
+#define DEBUG_WINDOW EOM_DEBUG_WINDOW, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_VIEW EOM_DEBUG_VIEW, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_JOBS EOM_DEBUG_JOBS, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_THUMBNAIL EOM_DEBUG_THUMBNAIL, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_IMAGE_DATA EOM_DEBUG_IMAGE_DATA, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_IMAGE_LOAD EOM_DEBUG_IMAGE_LOAD, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_IMAGE_SAVE EOM_DEBUG_IMAGE_SAVE, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_LIST_STORE EOM_DEBUG_LIST_STORE, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_PREFERENCES EOM_DEBUG_PREFERENCES, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_PRINTING EOM_DEBUG_PRINTING, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_LCMS EOM_DEBUG_LCMS, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_PLUGINS EOM_DEBUG_PLUGINS, __FILE__, __LINE__, G_STRFUNC
+
+void eom_debug_init (void);
+
+void eom_debug (EomDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function);
+
+void eom_debug_message (EomDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...) G_GNUC_PRINTF(5, 6);
+
+#endif /* __EOM_DEBUG_H__ */
diff --git a/src/eom-dialog.c b/src/eom-dialog.c
new file mode 100644
index 0000000..fac74a9
--- /dev/null
+++ b/src/eom-dialog.c
@@ -0,0 +1,237 @@
+/* Eye Of Mate - Image Dialog
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-dialog.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#define EOM_DIALOG_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_DIALOG, EomDialogPrivate))
+
+G_DEFINE_TYPE (EomDialog, eom_dialog, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_PARENT_WINDOW,
+};
+
+struct _EomDialogPrivate {
+ GtkWidget *dlg;
+ GtkBuilder *xml;
+ GtkWindow *parent;
+};
+
+static void
+eom_dialog_construct_impl (EomDialog *dialog,
+ const gchar *glade_file,
+ const gchar *dlg_node)
+{
+ EomDialogPrivate *priv;
+ gchar *filename;
+
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (EOM_IS_DIALOG (dialog));
+
+ priv = dialog->priv;
+
+ filename = g_build_filename (EOM_DATA_DIR, glade_file, NULL);
+
+ priv->xml = gtk_builder_new ();
+ gtk_builder_set_translation_domain (priv->xml, GETTEXT_PACKAGE);
+ g_assert (gtk_builder_add_from_file (priv->xml, filename, NULL));
+
+ g_free (filename);
+
+ priv->dlg = GTK_WIDGET (gtk_builder_get_object (priv->xml, dlg_node));
+
+ if (priv->parent != NULL) {
+ gtk_window_set_transient_for (GTK_WINDOW (priv->dlg),
+ priv->parent);
+ }
+}
+
+static void
+eom_dialog_show_impl (EomDialog *dialog)
+{
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (EOM_IS_DIALOG (dialog));
+
+ gtk_window_present (GTK_WINDOW (dialog->priv->dlg));
+}
+
+static void
+eom_dialog_hide_impl (EomDialog *dialog)
+{
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (EOM_IS_DIALOG (dialog));
+
+ gtk_widget_hide (dialog->priv->dlg);
+}
+
+static void
+eom_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EomDialog *dialog = EOM_DIALOG (object);
+
+ switch (prop_id) {
+ case PROP_PARENT_WINDOW:
+ dialog->priv->parent = g_value_get_object (value);
+ break;
+ }
+}
+
+static void
+eom_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EomDialog *dialog = EOM_DIALOG (object);
+
+ switch (prop_id) {
+ case PROP_PARENT_WINDOW:
+ g_value_set_object (value, dialog->priv->parent);
+ break;
+ }
+}
+
+static void
+eom_dialog_dispose (GObject *object)
+{
+ EomDialog *dialog;
+ EomDialogPrivate *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (EOM_IS_DIALOG (object));
+
+ dialog = EOM_DIALOG (object);
+ priv = dialog->priv;
+
+ if (priv->dlg) {
+ gtk_widget_destroy (priv->dlg);
+ priv->dlg = NULL;
+ }
+
+ if (priv->xml) {
+ g_object_unref (priv->xml);
+ priv->xml = NULL;
+ }
+
+ G_OBJECT_CLASS (eom_dialog_parent_class)->dispose (object);
+}
+
+static void
+eom_dialog_class_init (EomDialogClass *class)
+{
+ GObjectClass *g_object_class = (GObjectClass *) class;
+
+ g_object_class->dispose = eom_dialog_dispose;
+ g_object_class->set_property = eom_dialog_set_property;
+ g_object_class->get_property = eom_dialog_get_property;
+
+ class->construct = eom_dialog_construct_impl;
+ class->show = eom_dialog_show_impl;
+ class->hide = eom_dialog_hide_impl;
+
+ g_object_class_install_property (g_object_class,
+ PROP_PARENT_WINDOW,
+ g_param_spec_object ("parent-window",
+ "Parent window",
+ "Parent window",
+ GTK_TYPE_WINDOW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_type_class_add_private (g_object_class, sizeof (EomDialogPrivate));
+}
+
+static void
+eom_dialog_init (EomDialog *dialog)
+{
+ dialog->priv = EOM_DIALOG_GET_PRIVATE (dialog);
+
+ dialog->priv->dlg = NULL;
+ dialog->priv->xml = NULL;
+ dialog->priv->parent = NULL;
+}
+
+void
+eom_dialog_construct (EomDialog *dialog,
+ const gchar *glade_file,
+ const gchar *dlg_node)
+{
+ EomDialogClass *klass = EOM_DIALOG_GET_CLASS (dialog);
+ klass->construct (dialog, glade_file, dlg_node);
+}
+
+void
+eom_dialog_show (EomDialog *dialog)
+{
+ EomDialogClass *klass = EOM_DIALOG_GET_CLASS (dialog);
+ klass->show (dialog);
+}
+
+void
+eom_dialog_hide (EomDialog *dialog)
+{
+ EomDialogClass *klass = EOM_DIALOG_GET_CLASS (dialog);
+ klass->hide (dialog);
+}
+
+void
+eom_dialog_get_controls (EomDialog *dialog,
+ const gchar *property_id,
+ ...)
+{
+ EomDialogPrivate *priv;
+ GtkWidget **wptr;
+ va_list varargs;
+
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (EOM_IS_DIALOG (dialog));
+
+ priv = dialog->priv;
+
+ va_start (varargs, property_id);
+
+ while (property_id != NULL)
+ {
+ wptr = va_arg (varargs, GtkWidget **);
+ *wptr = GTK_WIDGET (gtk_builder_get_object (priv->xml,
+ property_id));
+
+ property_id = va_arg (varargs, const gchar *);
+ }
+
+ va_end (varargs);
+}
diff --git a/src/eom-dialog.h b/src/eom-dialog.h
new file mode 100644
index 0000000..3022dee
--- /dev/null
+++ b/src/eom-dialog.h
@@ -0,0 +1,76 @@
+/* Eye Of Mate - EOM Dialog
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_DIALOG_H__
+#define __EOM_DIALOG_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EomDialog EomDialog;
+typedef struct _EomDialogClass EomDialogClass;
+typedef struct _EomDialogPrivate EomDialogPrivate;
+
+#define EOM_TYPE_DIALOG (eom_dialog_get_type ())
+#define EOM_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_DIALOG, EomDialog))
+#define EOM_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_DIALOG, EomDialogClass))
+#define EOM_IS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_DIALOG))
+#define EOM_IS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EOM_TYPE_DIALOG))
+#define EOM_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EOM_TYPE_DIALOG, EomDialogClass))
+
+struct _EomDialog {
+ GObject object;
+
+ EomDialogPrivate *priv;
+};
+
+struct _EomDialogClass {
+ GObjectClass parent_class;
+
+ void (* construct) (EomDialog *dialog,
+ const gchar *glade_file,
+ const gchar *dlg_node);
+
+ void (* show) (EomDialog *dialog);
+
+ void (* hide) (EomDialog *dialog);
+};
+
+GType eom_dialog_get_type (void) G_GNUC_CONST;
+
+void eom_dialog_construct (EomDialog *dialog,
+ const gchar *glade_file,
+ const gchar *dlg_node);
+
+void eom_dialog_show (EomDialog *dialog);
+
+void eom_dialog_hide (EomDialog *dialog);
+
+void eom_dialog_get_controls (EomDialog *dialog,
+ const gchar *property_id,
+ ...);
+
+G_END_DECLS
+
+#endif /* __EOM_DIALOG_H__ */
diff --git a/src/eom-enum-types.c.template b/src/eom-enum-types.c.template
new file mode 100644
index 0000000..a7212e0
--- /dev/null
+++ b/src/eom-enum-types.c.template
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include "eom-enum-types.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@[email protected]" */
+#include "@[email protected]"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const [email protected]@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ the_type = [email protected]@_register_static (
+ g_intern_static_string ("@[email protected]"),
+ values);
+ }
+ return the_type;
+}
+
+/*** END value-tail ***/
diff --git a/src/eom-enum-types.h.template b/src/eom-enum-types.h.template
new file mode 100644
index 0000000..e70c3b0
--- /dev/null
+++ b/src/eom-enum-types.h.template
@@ -0,0 +1,27 @@
+/*** BEGIN file-header ***/
+#ifndef __EOM_ENUM_TYPES_H__
+#define __EOM_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from "@[email protected]" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+#define [email protected]@ (@[email protected]_get_type())
+G_GNUC_INTERNAL GType @[email protected]_get_type (void) G_GNUC_CONST;
+
+/*** END enumeration-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __EOM_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
diff --git a/src/eom-enums.h b/src/eom-enums.h
new file mode 100644
index 0000000..b39e978
--- /dev/null
+++ b/src/eom-enums.h
@@ -0,0 +1,37 @@
+/* Eye of MATE - General enumerations.
+ *
+ * Copyright (C) 2007-2008 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_ENUMS__
+#define __EOM_ENUMS__
+
+typedef enum {
+ EOM_IMAGE_DATA_IMAGE = 1 << 0,
+ EOM_IMAGE_DATA_DIMENSION = 1 << 1,
+ EOM_IMAGE_DATA_EXIF = 1 << 2,
+ EOM_IMAGE_DATA_XMP = 1 << 3
+} EomImageData;
+
+#define EOM_IMAGE_DATA_ALL (EOM_IMAGE_DATA_IMAGE | \
+ EOM_IMAGE_DATA_DIMENSION | \
+ EOM_IMAGE_DATA_EXIF | \
+ EOM_IMAGE_DATA_XMP)
+
+#endif
diff --git a/src/eom-error-message-area.c b/src/eom-error-message-area.c
new file mode 100644
index 0000000..f0a2baf
--- /dev/null
+++ b/src/eom-error-message-area.c
@@ -0,0 +1,192 @@
+/* Eye Of Mate - Erro Message Area
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-message-area.h) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-error-message-area.h"
+#include "eom-image.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+static void
+set_message_area_text_and_icon (GtkInfoBar *message_area,
+ const gchar *icon_stock_id,
+ const gchar *primary_text,
+ const gchar *secondary_text)
+{
+ GtkWidget *hbox_content;
+ GtkWidget *image;
+ GtkWidget *vbox;
+ gchar *primary_markup;
+ gchar *secondary_markup;
+ GtkWidget *primary_label;
+ GtkWidget *secondary_label;
+
+ hbox_content = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox_content);
+
+ image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG);
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
+
+ primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
+ primary_label = gtk_label_new (primary_markup);
+ g_free (primary_markup);
+
+ gtk_widget_show (primary_label);
+
+ gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
+ gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (primary_label), FALSE);
+ gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5);
+
+ gtk_widget_set_can_focus (primary_label, TRUE);
+
+ gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
+
+ if (secondary_text != NULL) {
+ secondary_markup = g_strdup_printf ("<small>%s</small>",
+ secondary_text);
+ secondary_label = gtk_label_new (secondary_markup);
+ g_free (secondary_markup);
+
+ gtk_widget_show (secondary_label);
+
+ gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
+
+ gtk_widget_set_can_focus (secondary_label, TRUE);
+
+ gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5);
+ }
+
+ gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (message_area))), hbox_content, TRUE, TRUE, 0);
+}
+
+static GtkWidget *
+create_error_message_area (const gchar *primary_text,
+ const gchar *secondary_text,
+ gboolean recoverable)
+{
+ GtkWidget *message_area;
+
+ if (recoverable)
+ message_area = gtk_info_bar_new_with_buttons (_("_Retry"),
+ GTK_RESPONSE_OK,
+ NULL);
+ else
+ message_area = gtk_info_bar_new ();
+
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (message_area),
+ GTK_MESSAGE_ERROR);
+
+ set_message_area_text_and_icon (GTK_INFO_BAR (message_area),
+ GTK_STOCK_DIALOG_ERROR,
+ primary_text,
+ secondary_text);
+
+ return message_area;
+}
+
+GtkWidget *
+eom_image_load_error_message_area_new (const gchar *caption,
+ const GError *error)
+{
+ GtkWidget *message_area;
+ gchar *error_message = NULL;
+ gchar *message_details = NULL;
+ gchar *pango_escaped_caption = NULL;
+
+ g_return_val_if_fail (caption != NULL, NULL);
+ g_return_val_if_fail (error != NULL, NULL);
+
+ /* Escape the caption string with respect to pango markup.
+ This is necessary because otherwise characters like "&" will
+ be interpreted as the beginning of a pango entity inside
+ the message area GtkLabel. */
+ pango_escaped_caption = g_markup_escape_text (caption, -1);
+ error_message = g_strdup_printf (_("Could not load image '%s'."),
+ pango_escaped_caption);
+
+ message_details = g_strdup (error->message);
+
+ message_area = create_error_message_area (error_message,
+ message_details,
+ TRUE);
+
+ g_free (pango_escaped_caption);
+ g_free (error_message);
+ g_free (message_details);
+
+ return message_area;
+}
+
+GtkWidget *
+eom_no_images_error_message_area_new (GFile *file)
+{
+ GtkWidget *message_area;
+ gchar *error_message = NULL;
+
+ if (file != NULL) {
+ gchar *uri_str, *unescaped_str, *pango_escaped_str;
+
+ uri_str = g_file_get_uri (file);
+ /* Unescape URI with respect to rules defined in RFC 3986. */
+ unescaped_str = g_uri_unescape_string (uri_str, NULL);
+
+ /* Escape the URI string with respect to pango markup.
+ This is necessary because the URI string can contain
+ for example "&" which will otherwise be interpreted
+ as a pango markup entity when inserted into a GtkLabel. */
+ pango_escaped_str = g_markup_escape_text (unescaped_str, -1);
+ error_message = g_strdup_printf (_("No images found in '%s'."),
+ pango_escaped_str);
+
+ g_free (pango_escaped_str);
+ g_free (uri_str);
+ g_free (unescaped_str);
+ } else {
+ error_message = g_strdup (_("The given locations contain no images."));
+ }
+
+ message_area = create_error_message_area (error_message,
+ NULL,
+ FALSE);
+
+ g_free (error_message);
+
+ return message_area;
+}
diff --git a/src/eom-error-message-area.h b/src/eom-error-message-area.h
new file mode 100644
index 0000000..8b285ba
--- /dev/null
+++ b/src/eom-error-message-area.h
@@ -0,0 +1,37 @@
+/* Eye Of Mate - Erro Message Area
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-message-area.h) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_ERROR_MESSAGE_AREA__
+#define __EOM_ERROR_MESSAGE_AREA__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+GtkWidget *eom_image_load_error_message_area_new (const gchar *caption,
+ const GError *error);
+
+GtkWidget *eom_no_images_error_message_area_new (GFile *file);
+
+#endif /* __EOM_ERROR_MESSAGE_AREA__ */
diff --git a/src/eom-exif-details.c b/src/eom-exif-details.c
new file mode 100644
index 0000000..2385e6a
--- /dev/null
+++ b/src/eom-exif-details.c
@@ -0,0 +1,572 @@
+/* Eye Of Mate - EOM Image Exif Details
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-exif-details.h"
+#include "eom-util.h"
+
+#if HAVE_EXIF
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+#endif
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#include <exempi/xmpconsts.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <string.h>
+
+#define EOM_EXIF_DETAILS_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_EXIF_DETAILS, EomExifDetailsPrivate))
+
+G_DEFINE_TYPE (EomExifDetails, eom_exif_details, GTK_TYPE_TREE_VIEW)
+
+typedef enum {
+ EXIF_CATEGORY_CAMERA,
+ EXIF_CATEGORY_IMAGE_DATA,
+ EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS,
+ EXIF_CATEGORY_MAKER_NOTE,
+ EXIF_CATEGORY_OTHER,
+#ifdef HAVE_EXEMPI
+ XMP_CATEGORY_EXIF,
+ XMP_CATEGORY_IPTC,
+ XMP_CATEGORY_RIGHTS,
+ XMP_CATEGORY_OTHER
+#endif
+} ExifCategory;
+
+typedef struct {
+ char *label;
+ char *path;
+} ExifCategoryInfo;
+
+static ExifCategoryInfo exif_categories[] = {
+ { N_("Camera"), "0" },
+ { N_("Image Data"), "1" },
+ { N_("Image Taking Conditions"), "2" },
+ { N_("Maker Note"), "3" },
+ { N_("Other"), "4" },
+#ifdef HAVE_EXEMPI
+ { N_("XMP Exif"), "5" },
+ { N_("XMP IPTC"), "6" },
+ { N_("XMP Rights Management"), "7" },
+ { N_("XMP Other"), "8" },
+#endif
+ { NULL, NULL }
+};
+
+typedef struct {
+ int id;
+ ExifCategory category;
+} ExifTagCategory;
+
+#ifdef HAVE_EXIF
+static ExifTagCategory exif_tag_category_map[] = {
+ { EXIF_TAG_INTEROPERABILITY_INDEX, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_INTEROPERABILITY_VERSION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_IMAGE_WIDTH, EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_IMAGE_LENGTH , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_BITS_PER_SAMPLE ,EXIF_CATEGORY_CAMERA },
+ { EXIF_TAG_COMPRESSION , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_PHOTOMETRIC_INTERPRETATION , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FILL_ORDER , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_DOCUMENT_NAME , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_IMAGE_DESCRIPTION , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_MAKE , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_MODEL , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_STRIP_OFFSETS , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_ORIENTATION , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_SAMPLES_PER_PIXEL , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_ROWS_PER_STRIP , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_STRIP_BYTE_COUNTS , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_X_RESOLUTION , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_Y_RESOLUTION , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_PLANAR_CONFIGURATION , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_RESOLUTION_UNIT , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_TRANSFER_FUNCTION , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SOFTWARE , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_DATE_TIME , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_ARTIST , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_WHITE_POINT , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_PRIMARY_CHROMATICITIES, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_TRANSFER_RANGE , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_JPEG_PROC , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, },
+ { EXIF_TAG_YCBCR_COEFFICIENTS , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_YCBCR_SUB_SAMPLING , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_YCBCR_POSITIONING , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_REFERENCE_BLACK_WHITE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_RELATED_IMAGE_FILE_FORMAT,EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_RELATED_IMAGE_WIDTH , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_RELATED_IMAGE_LENGTH , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_CFA_REPEAT_PATTERN_DIM, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_CFA_PATTERN , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_BATTERY_LEVEL , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_COPYRIGHT , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_EXPOSURE_TIME , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FNUMBER , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_IPTC_NAA , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXIF_IFD_POINTER , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_INTER_COLOR_PROFILE , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXPOSURE_PROGRAM , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SPECTRAL_SENSITIVITY , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_GPS_INFO_IFD_POINTER , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_ISO_SPEED_RATINGS , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_OECF , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXIF_VERSION , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_DATE_TIME_ORIGINAL , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_DATE_TIME_DIGITIZED , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_COMPONENTS_CONFIGURATION , EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SHUTTER_SPEED_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_APERTURE_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_BRIGHTNESS_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_EXPOSURE_BIAS_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_MAX_APERTURE_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SUBJECT_DISTANCE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_METERING_MODE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_LIGHT_SOURCE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FLASH , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FOCAL_LENGTH , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SUBJECT_AREA , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_MAKER_NOTE , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_USER_COMMENT , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_SUBSEC_TIME , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FLASH_PIX_VERSION , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_COLOR_SPACE , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_PIXEL_X_DIMENSION , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_PIXEL_Y_DIMENSION , EXIF_CATEGORY_IMAGE_DATA},
+ { EXIF_TAG_RELATED_SOUND_FILE , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_INTEROPERABILITY_IFD_POINTER, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FLASH_ENERGY ,EXIF_CATEGORY_OTHER },
+ { EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SUBJECT_LOCATION, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXPOSURE_INDEX, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SENSING_METHOD, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FILE_SOURCE , EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_SCENE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_NEW_CFA_PATTERN, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_CUSTOM_RENDERED, EXIF_CATEGORY_OTHER},
+ { EXIF_TAG_EXPOSURE_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_WHITE_BALANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SCENE_CAPTURE_TYPE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_GAIN_CONTROL , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_CONTRAST , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SATURATION , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_SHARPNESS , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_DEVICE_SETTING_DESCRIPTION, EXIF_CATEGORY_CAMERA},
+ { EXIF_TAG_SUBJECT_DISTANCE_RANGE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS},
+ { EXIF_TAG_IMAGE_UNIQUE_ID , EXIF_CATEGORY_IMAGE_DATA},
+ { -1, -1 }
+};
+#endif
+
+#define MODEL_COLUMN_ATTRIBUTE 0
+#define MODEL_COLUMN_VALUE 1
+
+struct _EomExifDetailsPrivate {
+ GtkTreeModel *model;
+
+ GHashTable *id_path_hash;
+ GHashTable *id_path_hash_mnote;
+};
+
+static char* set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value);
+
+static void eom_exif_details_reset (EomExifDetails *exif_details);
+
+static void
+eom_exif_details_dispose (GObject *object)
+{
+ EomExifDetailsPrivate *priv;
+
+ priv = EOM_EXIF_DETAILS (object)->priv;
+
+ if (priv->model) {
+ g_object_unref (priv->model);
+ priv->model = NULL;
+ }
+
+ if (priv->id_path_hash) {
+ g_hash_table_destroy (priv->id_path_hash);
+ priv->id_path_hash = NULL;
+ }
+
+ if (priv->id_path_hash_mnote) {
+ g_hash_table_destroy (priv->id_path_hash_mnote);
+ priv->id_path_hash_mnote = NULL;
+ }
+ G_OBJECT_CLASS (eom_exif_details_parent_class)->dispose (object);
+}
+
+static void
+eom_exif_details_init (EomExifDetails *exif_details)
+{
+ EomExifDetailsPrivate *priv;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+
+ exif_details->priv = EOM_EXIF_DETAILS_GET_PRIVATE (exif_details);
+
+ priv = exif_details->priv;
+
+ priv->model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
+ priv->id_path_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ priv->id_path_hash_mnote = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+
+ /* Tag name column */
+ cell = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Tag"), cell,
+ "text", MODEL_COLUMN_ATTRIBUTE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (exif_details), column);
+
+ /* Value column */
+ cell = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Value"), cell,
+ "text", MODEL_COLUMN_VALUE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (exif_details), column);
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (exif_details), TRUE);
+
+ eom_exif_details_reset (exif_details);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (exif_details),
+ GTK_TREE_MODEL (priv->model));
+}
+
+static void
+eom_exif_details_class_init (EomExifDetailsClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eom_exif_details_dispose;
+
+ g_type_class_add_private (object_class, sizeof (EomExifDetailsPrivate));
+}
+
+#ifdef HAVE_EXIF
+static ExifCategory
+get_exif_category (ExifEntry *entry)
+{
+ ExifCategory cat = EXIF_CATEGORY_OTHER;
+ int i;
+
+ for (i = 0; exif_tag_category_map [i].id != -1; i++) {
+ if (exif_tag_category_map[i].id == (int) entry->tag) {
+ cat = exif_tag_category_map[i].category;
+ break;
+ }
+ }
+
+ return cat;
+}
+#endif
+
+static char*
+set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value)
+{
+ GtkTreeIter iter;
+ gchar *utf_attribute = NULL;
+ gchar *utf_value = NULL;
+ gboolean iter_valid = FALSE;
+
+ if (!attribute) return NULL;
+
+ if (path != NULL) {
+ iter_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path);
+ }
+
+ if (!iter_valid) {
+ GtkTreePath *tree_path;
+ GtkTreeIter parent_iter;
+ gboolean parent_valid = FALSE;
+
+ if (parent != NULL) {
+ parent_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store),
+ &parent_iter,
+ parent);
+ }
+
+ gtk_tree_store_append (store, &iter, parent_valid ? &parent_iter : NULL);
+
+ if (path == NULL) {
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+
+ if (tree_path != NULL) {
+ path = gtk_tree_path_to_string (tree_path);
+ gtk_tree_path_free (tree_path);
+ }
+ }
+ }
+
+ utf_attribute = eom_util_make_valid_utf8 (attribute);
+
+ gtk_tree_store_set (store, &iter, MODEL_COLUMN_ATTRIBUTE, utf_attribute, -1);
+ g_free (utf_attribute);
+
+ if (value != NULL) {
+ utf_value = eom_util_make_valid_utf8 (value);
+ gtk_tree_store_set (store, &iter, MODEL_COLUMN_VALUE, utf_value, -1);
+ g_free (utf_value);
+ }
+
+ return path;
+}
+
+#ifdef HAVE_EXIF
+static void
+exif_entry_cb (ExifEntry *entry, gpointer data)
+{
+ GtkTreeStore *store;
+ EomExifDetails *view;
+ EomExifDetailsPrivate *priv;
+ ExifCategory cat;
+ char *path;
+ char b[1024];
+
+ view = EOM_EXIF_DETAILS (data);
+ priv = view->priv;
+
+ store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+
+ path = g_hash_table_lookup (priv->id_path_hash, GINT_TO_POINTER (entry->tag));
+
+ if (path != NULL) {
+ set_row_data (store,
+ path,
+ NULL,
+ exif_tag_get_name (entry->tag),
+ exif_entry_get_value (entry, b, sizeof(b)));
+ } else {
+
+ ExifMnoteData *mnote = (entry->tag == EXIF_TAG_MAKER_NOTE ?
+ exif_data_get_mnote_data (entry->parent->parent) : NULL);
+
+ if (mnote) {
+ // Supported MakerNote Found
+ unsigned int i, c = exif_mnote_data_count (mnote);
+
+ for (i = 0; i < c; i++) {
+ path = g_hash_table_lookup (priv->id_path_hash_mnote, GINT_TO_POINTER (i));
+ if (path != NULL) {
+ set_row_data (store, path, NULL,
+ exif_mnote_data_get_title (mnote, i),
+ exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
+ } else {
+ path = set_row_data (store,
+ NULL,
+ exif_categories[EXIF_CATEGORY_MAKER_NOTE].path,
+ exif_mnote_data_get_title (mnote, i),
+ exif_mnote_data_get_value (mnote, i, b, sizeof(b)));
+ g_hash_table_insert (priv->id_path_hash_mnote, GINT_TO_POINTER (i), path);
+ }
+ }
+ } else {
+ cat = get_exif_category (entry);
+
+ path = set_row_data (store,
+ NULL,
+ exif_categories[cat].path,
+ exif_tag_get_name (entry->tag),
+ exif_entry_get_value (entry, b,
+ sizeof(b)));
+
+ g_hash_table_insert (priv->id_path_hash,
+ GINT_TO_POINTER (entry->tag),
+ path);
+ }
+ }
+}
+#endif
+
+#ifdef HAVE_EXIF
+static void
+exif_content_cb (ExifContent *content, gpointer data)
+{
+ exif_content_foreach_entry (content, exif_entry_cb, data);
+}
+#endif
+
+GtkWidget *
+eom_exif_details_new (void)
+{
+ GObject *object;
+
+ object = g_object_new (EOM_TYPE_EXIF_DETAILS, NULL);
+
+ return GTK_WIDGET (object);
+}
+
+static void
+eom_exif_details_reset (EomExifDetails *exif_details)
+{
+ int i;
+ EomExifDetailsPrivate *priv = exif_details->priv;
+
+ gtk_tree_store_clear (GTK_TREE_STORE (priv->model));
+
+ g_hash_table_remove_all (priv->id_path_hash);
+ g_hash_table_remove_all (priv->id_path_hash_mnote);
+
+ for (i = 0; exif_categories [i].label != NULL; i++) {
+ char *translated_string;
+
+ translated_string = gettext (exif_categories[i].label);
+
+ set_row_data (GTK_TREE_STORE (priv->model),
+ exif_categories[i].path,
+ NULL,
+ translated_string,
+ NULL);
+ }
+}
+
+#ifdef HAVE_EXIF
+void
+eom_exif_details_update (EomExifDetails *exif_details, ExifData *data)
+{
+ EomExifDetailsPrivate *priv;
+
+ g_return_if_fail (EOM_IS_EXIF_DETAILS (exif_details));
+
+ priv = exif_details->priv;
+
+ eom_exif_details_reset (exif_details);
+ if (data) {
+ exif_data_foreach_content (data, exif_content_cb, exif_details);
+ }
+}
+#endif /* HAVE_EXIF */
+
+#ifdef HAVE_EXEMPI
+typedef struct {
+ const char *id;
+ ExifCategory category;
+} XmpNsCategory;
+
+static XmpNsCategory xmp_ns_category_map[] = {
+ { NS_EXIF, XMP_CATEGORY_EXIF},
+ { NS_TIFF, XMP_CATEGORY_EXIF},
+ { NS_XAP, XMP_CATEGORY_EXIF},
+ { NS_XAP_RIGHTS, XMP_CATEGORY_RIGHTS},
+ { NS_EXIF_AUX, XMP_CATEGORY_EXIF},
+ { NS_DC, XMP_CATEGORY_IPTC},
+ { NS_IPTC4XMP, XMP_CATEGORY_IPTC},
+ { NS_CC, XMP_CATEGORY_RIGHTS},
+ { NULL, -1}
+};
+
+static ExifCategory
+get_xmp_category (XmpStringPtr schema)
+{
+ ExifCategory cat = XMP_CATEGORY_OTHER;
+ const char *s = xmp_string_cstr(schema);
+ int i;
+
+ for (i = 0; xmp_ns_category_map[i].id != NULL; i++) {
+ if (strcmp (xmp_ns_category_map[i].id, s) == 0) {
+ cat = xmp_ns_category_map[i].category;
+ break;
+ }
+ }
+
+ return cat;
+}
+
+static void
+xmp_entry_insert (EomExifDetails *view, XmpStringPtr xmp_schema,
+ XmpStringPtr xmp_path, XmpStringPtr xmp_prop)
+{
+ GtkTreeStore *store;
+ EomExifDetailsPrivate *priv;
+ ExifCategory cat;
+ char *path;
+ gchar *key;
+
+ priv = view->priv;
+
+ key = g_strconcat (xmp_string_cstr (xmp_schema), ":",
+ xmp_string_cstr (xmp_path), NULL);
+
+ store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+
+ path = g_hash_table_lookup (priv->id_path_hash, key);
+
+ if (path != NULL) {
+ set_row_data (store, path, NULL,
+ xmp_string_cstr (xmp_path),
+ xmp_string_cstr (xmp_prop));
+
+ g_free(key);
+ }
+ else {
+ cat = get_xmp_category (xmp_schema);
+
+ path = set_row_data (store, NULL, exif_categories[cat].path,
+ xmp_string_cstr(xmp_path),
+ xmp_string_cstr(xmp_prop));
+
+ g_hash_table_insert (priv->id_path_hash, key, path);
+ }
+}
+
+void
+eom_exif_details_xmp_update (EomExifDetails *view, XmpPtr data)
+{
+ EomExifDetailsPrivate *priv;
+
+ g_return_if_fail (EOM_IS_EXIF_DETAILS (view));
+
+ priv = view->priv;
+
+ if (data) {
+ XmpIteratorPtr iter = xmp_iterator_new(data, NULL, NULL, XMP_ITER_JUSTLEAFNODES);
+ XmpStringPtr the_schema = xmp_string_new ();
+ XmpStringPtr the_path = xmp_string_new ();
+ XmpStringPtr the_prop = xmp_string_new ();
+
+ while (xmp_iterator_next (iter, the_schema, the_path, the_prop, NULL)) {
+ xmp_entry_insert (view, the_schema, the_path, the_prop);
+ }
+
+ xmp_string_free (the_prop);
+ xmp_string_free (the_path);
+ xmp_string_free (the_schema);
+ xmp_iterator_free (iter);
+ }
+}
+#endif
diff --git a/src/eom-exif-details.h b/src/eom-exif-details.h
new file mode 100644
index 0000000..5964133
--- /dev/null
+++ b/src/eom-exif-details.h
@@ -0,0 +1,72 @@
+/* Eye Of Mate - EOM Image Exif Details
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_EXIF_DETAILS__
+#define __EOM_EXIF_DETAILS__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#if HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#endif
+
+G_BEGIN_DECLS
+
+typedef struct _EomExifDetails EomExifDetails;
+typedef struct _EomExifDetailsClass EomExifDetailsClass;
+typedef struct _EomExifDetailsPrivate EomExifDetailsPrivate;
+
+#define EOM_TYPE_EXIF_DETAILS (eom_exif_details_get_type ())
+#define EOM_EXIF_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_EXIF_DETAILS, EomExifDetails))
+#define EOM_EXIF_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_EXIF_DETAILS, EomExifDetailsClass))
+#define EOM_IS_EXIF_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_EXIF_DETAILS))
+#define EOM_IS_EXIF_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_EXIF_DETAILS))
+#define EOM_EXIF_DETAILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_EXIF_DETAILS, EomExifDetailsClass))
+
+struct _EomExifDetails {
+ GtkTreeView parent;
+
+ EomExifDetailsPrivate *priv;
+};
+
+struct _EomExifDetailsClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType eom_exif_details_get_type (void) G_GNUC_CONST;
+
+GtkWidget *eom_exif_details_new (void);
+
+#if HAVE_EXIF
+void eom_exif_details_update (EomExifDetails *view,
+ ExifData *data);
+#endif
+#if HAVE_EXEMPI
+void eom_exif_details_xmp_update (EomExifDetails *view,
+ XmpPtr xmp_data);
+#endif
+
+G_END_DECLS
+
+#endif /* __EOM_EXIF_DETAILS__ */
diff --git a/src/eom-exif-util.c b/src/eom-exif-util.c
new file mode 100644
index 0000000..93d54e0
--- /dev/null
+++ b/src/eom-exif-util.c
@@ -0,0 +1,214 @@
+/* Eye Of Mate - EXIF Utilities
+ *
+ * Copyright (C) 2006-2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ * Author: Claudio Saavedra <[email protected]>
+ * Author: Felix Riemann <[email protected]>
+ *
+ * Based on code by:
+ * - Jens Finke <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STRPTIME
+#define _XOPEN_SOURCE
+#endif
+#include <time.h>
+
+#include "eom-exif-util.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#define DATE_BUF_SIZE 200
+
+/* gboolean <-> gpointer conversion macros taken from gedit */
+#ifndef GBOOLEAN_TO_POINTER
+#define GBOOLEAN_TO_POINTER(i) (GINT_TO_POINTER ((i) ? 2 : 1))
+#endif
+#ifndef GPOINTER_TO_BOOLEAN
+#define GPOINTER_TO_BOOLEAN(i) ((gboolean) ((GPOINTER_TO_INT (i) == 2) ? TRUE : FALSE))
+#endif
+
+static gpointer
+_check_strptime_updates_wday (gpointer data)
+{
+ struct tm tm;
+
+ memset (&tm, '\0', sizeof (tm));
+ strptime ("2008:12:24 20:30:45", "%Y:%m:%d %T", &tm);
+ /* Check if tm.tm_wday is set to Wednesday (3) now */
+ return GBOOLEAN_TO_POINTER (tm.tm_wday == 3);
+}
+
+/**
+ * _calculate_wday_yday:
+ * @tm: A struct tm that should be updated.
+ *
+ * Ensure tm_wday and tm_yday are set correctly in a struct tm.
+ * The other date (dmy) values must have been set already.
+ **/
+static void
+_calculate_wday_yday (struct tm *tm)
+{
+ GDate *exif_date;
+ struct tm tmp_tm;
+
+ exif_date = g_date_new_dmy (tm->tm_mday,
+ tm->tm_mon+1,
+ tm->tm_year+1900);
+
+ g_return_if_fail (exif_date != NULL && g_date_valid (exif_date));
+
+ // Use this to get GLib <-> libc corrected values
+ g_date_to_struct_tm (exif_date, &tmp_tm);
+ g_date_free (exif_date);
+
+ tm->tm_wday = tmp_tm.tm_wday;
+ tm->tm_yday = tmp_tm.tm_yday;
+}
+
+#ifdef HAVE_STRPTIME
+static gchar *
+eom_exif_util_format_date_with_strptime (const gchar *date)
+{
+ static GOnce strptime_updates_wday = G_ONCE_INIT;
+ gchar *new_date = NULL;
+ gchar tmp_date[DATE_BUF_SIZE];
+ gchar *p;
+ gsize dlen;
+ struct tm tm;
+
+ memset (&tm, '\0', sizeof (tm));
+ p = strptime (date, "%Y:%m:%d %T", &tm);
+
+ if (p == date + strlen (date)) {
+ g_once (&strptime_updates_wday,
+ _check_strptime_updates_wday,
+ NULL);
+
+ // Ensure tm.tm_wday and tm.tm_yday are set
+ if (!GPOINTER_TO_BOOLEAN (strptime_updates_wday.retval))
+ _calculate_wday_yday (&tm);
+
+ /* A strftime-formatted string, to display the date the image was taken. */
+ dlen = strftime (tmp_date, DATE_BUF_SIZE * sizeof(gchar), _("%a, %d %B %Y %X"), &tm);
+ new_date = g_strndup (tmp_date, dlen);
+ }
+
+ return new_date;
+}
+#else
+static gchar *
+eom_exif_util_format_date_by_hand (const gchar *date)
+{
+ int year, month, day, hour, minutes, seconds;
+ int result;
+ gchar *new_date = NULL;
+
+ result = sscanf (date, "%d:%d:%d %d:%d:%d",
+ &year, &month, &day, &hour, &minutes, &seconds);
+
+ if (result < 3 || !g_date_valid_dmy (day, month, year)) {
+ return NULL;
+ } else {
+ gchar tmp_date[DATE_BUF_SIZE];
+ gsize dlen;
+ time_t secs;
+ struct tm tm;
+
+ memset (&tm, '\0', sizeof (tm));
+ tm.tm_mday = day;
+ tm.tm_mon = month-1;
+ tm.tm_year = year-1900;
+ // Calculate tm.tm_wday
+ _calculate_wday_yday (&tm);
+
+ if (result < 5) {
+ /* A strftime-formatted string, to display the date the image was taken, for the case we don't have the time. */
+ dlen = strftime (tmp_date, DATE_BUF_SIZE * sizeof(gchar), _("%a, %d %B %Y"), &tm);
+ } else {
+ tm.tm_sec = result < 6 ? 0 : seconds;
+ tm.tm_min = minutes;
+ tm.tm_hour = hour;
+ /* A strftime-formatted string, to display the date the image was taken. */
+ dlen = strftime (tmp_date, DATE_BUF_SIZE * sizeof(gchar), _("%a, %d %B %Y %X"), &tm);
+ }
+
+ if (dlen == 0)
+ return NULL;
+ else
+ new_date = g_strndup (tmp_date, dlen);
+ }
+ return new_date;
+}
+#endif /* HAVE_STRPTIME */
+
+/**
+ * eom_exif_util_format_date:
+ * @date: a date string following Exif specifications
+ *
+ * Takes a date string formatted after Exif specifications and generates a
+ * more readable, possibly localized, string out of it.
+ *
+ * Returns: a newly allocated date string formatted according to the
+ * current locale.
+ */
+gchar *
+eom_exif_util_format_date (const gchar *date)
+{
+ gchar *new_date;
+#ifdef HAVE_STRPTIME
+ new_date = eom_exif_util_format_date_with_strptime (date);
+#else
+ new_date = eom_exif_util_format_date_by_hand (date);
+#endif /* HAVE_STRPTIME */
+ return new_date;
+}
+
+/**
+ * eom_exif_util_get_value:
+ * @exif_data: pointer to an <structname>ExifData</structname> struct
+ * @tag_id: the requested tag's id. See <filename>exif-tag.h</filename>
+ * from the libexif package for possible values (e.g. %EXIF_TAG_EXPOSURE_MODE).
+ * @buffer: a pre-allocated output buffer
+ * @buf_size: size of @buffer
+ *
+ * Convenience function to extract a string representation of an Exif tag
+ * directly from an <structname>ExifData</structname> struct. The string is
+ * written into @buffer as far as @buf_size permits.
+ *
+ * Returns: a pointer to @buffer.
+ */
+const gchar *
+eom_exif_util_get_value (ExifData *exif_data, gint tag_id, gchar *buffer, guint buf_size)
+{
+ ExifEntry *exif_entry;
+ const gchar *exif_value;
+
+ exif_entry = exif_data_get_entry (exif_data, tag_id);
+
+ buffer[0] = 0;
+
+ exif_value = exif_entry_get_value (exif_entry, buffer, buf_size);
+
+ return exif_value;
+}
diff --git a/src/eom-exif-util.h b/src/eom-exif-util.h
new file mode 100644
index 0000000..9463524
--- /dev/null
+++ b/src/eom-exif-util.h
@@ -0,0 +1,41 @@
+/* Eye Of Mate - EXIF Utilities
+ *
+ * Copyright (C) 2006-2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ * Author: Claudio Saavedra <[email protected]>
+ * Author: Felix Riemann <[email protected]>
+ *
+ * Based on code by:
+ * - Jens Finke <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_EXIF_UTIL_H__
+#define __EOM_EXIF_UTIL_H__
+
+#include <glib.h>
+#include <libexif/exif-data.h>
+
+G_BEGIN_DECLS
+
+gchar* eom_exif_util_format_date (const gchar *date);
+
+const gchar *eom_exif_util_get_value (ExifData *exif_data, gint tag_id, gchar *buffer, guint buf_size);
+
+G_END_DECLS
+
+#endif /* __EOM_EXIF_UTIL_H__ */
diff --git a/src/eom-file-chooser.c b/src/eom-file-chooser.c
new file mode 100644
index 0000000..83a6fe2
--- /dev/null
+++ b/src/eom-file-chooser.c
@@ -0,0 +1,497 @@
+/*
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-file-chooser.h"
+#include "eom-config-keys.h"
+#include "eom-pixbuf-util.h"
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+/* We must define MATE_DESKTOP_USE_UNSTABLE_API to be able
+ to use MateDesktopThumbnail */
+#ifndef MATE_DESKTOP_USE_UNSTABLE_API
+#define MATE_DESKTOP_USE_UNSTABLE_API
+#endif
+#include <libmateui/mate-desktop-thumbnail.h>
+
+static char *last_dir[] = { NULL, NULL, NULL, NULL };
+
+#define FILE_FORMAT_KEY "file-format"
+
+#define EOM_FILE_CHOOSER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ EOM_TYPE_FILE_CHOOSER, \
+ EomFileChooserPrivate))
+
+struct _EomFileChooserPrivate
+{
+ MateDesktopThumbnailFactory *thumb_factory;
+
+ GtkWidget *image;
+ GtkWidget *size_label;
+ GtkWidget *dim_label;
+ GtkWidget *creator_label;
+};
+
+G_DEFINE_TYPE(EomFileChooser, eom_file_chooser, GTK_TYPE_FILE_CHOOSER_DIALOG)
+
+static void
+eom_file_chooser_finalize (GObject *object)
+{
+ EomFileChooserPrivate *priv;
+
+ priv = EOM_FILE_CHOOSER (object)->priv;
+
+ if (priv->thumb_factory != NULL)
+ g_object_unref (priv->thumb_factory);
+
+ (* G_OBJECT_CLASS (eom_file_chooser_parent_class)->finalize) (object);
+}
+
+static void
+eom_file_chooser_class_init (EomFileChooserClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ object_class->finalize = eom_file_chooser_finalize;
+
+ g_type_class_add_private (object_class, sizeof (EomFileChooserPrivate));
+}
+
+static void
+eom_file_chooser_init (EomFileChooser *chooser)
+{
+ chooser->priv = EOM_FILE_CHOOSER_GET_PRIVATE (chooser);
+}
+
+static void
+response_cb (GtkDialog *dlg, gint id, gpointer data)
+{
+ char *dir;
+ GtkFileChooserAction action;
+
+ if (id == GTK_RESPONSE_OK) {
+ dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg));
+ action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dlg));
+
+ if (last_dir [action] != NULL)
+ g_free (last_dir [action]);
+
+ last_dir [action] = dir;
+ }
+}
+
+static void
+save_response_cb (GtkDialog *dlg, gint id, gpointer data)
+{
+ GFile *file;
+ GdkPixbufFormat *format;
+
+ if (id != GTK_RESPONSE_OK)
+ return;
+
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dlg));
+ format = eom_pixbuf_get_format (file);
+ g_object_unref (file);
+
+ if (!format || !gdk_pixbuf_format_is_writable (format)) {
+ GtkWidget *msg_dialog;
+
+ msg_dialog = gtk_message_dialog_new (
+ GTK_WINDOW (dlg),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("File format is unknown or unsupported"));
+
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (msg_dialog),
+ "%s\n%s",
+ _("Eye of MATE could not determine a supported writable file format based on the filename."),
+ _("Please try a different file extension like .png or .jpg."));
+
+ gtk_dialog_run (GTK_DIALOG (msg_dialog));
+ gtk_widget_destroy (msg_dialog);
+
+ g_signal_stop_emission_by_name (dlg, "response");
+ } else {
+ response_cb (dlg, id, data);
+ }
+}
+
+static void
+eom_file_chooser_add_filter (EomFileChooser *chooser)
+{
+ GSList *it;
+ GSList *formats;
+ GtkFileFilter *all_file_filter;
+ GtkFileFilter *all_img_filter;
+ GtkFileFilter *filter;
+ GSList *filters = NULL;
+ gchar **mime_types, **pattern, *tmp;
+ int i;
+ GtkFileChooserAction action;
+
+ action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (chooser));
+
+ if (action != GTK_FILE_CHOOSER_ACTION_SAVE && action != GTK_FILE_CHOOSER_ACTION_OPEN) {
+ return;
+ }
+
+ /* All Files Filter */
+ all_file_filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (all_file_filter, _("All Files"));
+ gtk_file_filter_add_pattern (all_file_filter, "*");
+
+ /* All Image Filter */
+ all_img_filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (all_img_filter, _("All Images"));
+
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
+ formats = eom_pixbuf_get_savable_formats ();
+ }
+ else {
+ formats = gdk_pixbuf_get_formats ();
+ }
+
+ /* Image filters */
+ for (it = formats; it != NULL; it = it->next) {
+ char *filter_name;
+ char *description, *extension;
+ GdkPixbufFormat *format;
+ filter = gtk_file_filter_new ();
+
+ format = (GdkPixbufFormat*) it->data;
+ description = gdk_pixbuf_format_get_description (format);
+ extension = gdk_pixbuf_format_get_name (format);
+
+ /* Filter name: First description then file extension, eg. "The PNG-Format (*.png)".*/
+ filter_name = g_strdup_printf (_("%s (*.%s)"), description, extension);
+ g_free (description);
+ g_free (extension);
+
+ gtk_file_filter_set_name (filter, filter_name);
+ g_free (filter_name);
+
+ mime_types = gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) it->data);
+ for (i = 0; mime_types[i] != NULL; i++) {
+ gtk_file_filter_add_mime_type (filter, mime_types[i]);
+ gtk_file_filter_add_mime_type (all_img_filter, mime_types[i]);
+ }
+ g_strfreev (mime_types);
+
+ pattern = gdk_pixbuf_format_get_extensions ((GdkPixbufFormat *) it->data);
+ for (i = 0; pattern[i] != NULL; i++) {
+ tmp = g_strconcat ("*.", pattern[i], NULL);
+ gtk_file_filter_add_pattern (filter, tmp);
+ gtk_file_filter_add_pattern (all_img_filter, tmp);
+ g_free (tmp);
+ }
+ g_strfreev (pattern);
+
+ /* attach GdkPixbufFormat to filter, see also
+ * eom_file_chooser_get_format. */
+ g_object_set_data (G_OBJECT (filter),
+ FILE_FORMAT_KEY,
+ format);
+
+ filters = g_slist_prepend (filters, filter);
+ }
+ g_slist_free (formats);
+
+ /* Add filter to filechooser */
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), all_file_filter);
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), all_img_filter);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), all_img_filter);
+
+ for (it = filters; it != NULL; it = it->next) {
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), GTK_FILE_FILTER (it->data));
+ }
+ g_slist_free (filters);
+}
+
+static void
+set_preview_label (GtkWidget *label, const char *str)
+{
+ if (str == NULL) {
+ gtk_widget_hide (GTK_WIDGET (label));
+ }
+ else {
+ gtk_label_set_text (GTK_LABEL (label), str);
+ gtk_widget_show (GTK_WIDGET (label));
+ }
+}
+
+/* Sets the pixbuf as preview thumbnail and tries to read and display
+ * further information according to the thumbnail spec.
+ */
+static void
+set_preview_pixbuf (EomFileChooser *chooser, GdkPixbuf *pixbuf, goffset size)
+{
+ EomFileChooserPrivate *priv;
+ int bytes;
+ int pixels;
+ const char *bytes_str;
+ const char *width;
+ const char *height;
+ const char *creator = NULL;
+ char *size_str = NULL;
+ char *dim_str = NULL;
+
+ g_return_if_fail (EOM_IS_FILE_CHOOSER (chooser));
+
+ priv = chooser->priv;
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
+
+ if (pixbuf != NULL) {
+ /* try to read file size */
+ bytes_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Size");
+ if (bytes_str != NULL) {
+ bytes = atoi (bytes_str);
+ size_str = g_format_size_for_display (bytes);
+ }
+ else {
+ size_str = g_format_size_for_display (size);
+ }
+
+ /* try to read image dimensions */
+ width = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
+ height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
+
+ if ((width != NULL) && (height != NULL)) {
+ pixels = atoi (height);
+ /* Pixel size of image: width x height in pixel */
+ dim_str = g_strdup_printf ("%s x %s %s", width, height, ngettext ("pixel", "pixels", pixels));
+ }
+
+#if 0
+ /* Not sure, if this is really useful, therefore its commented out for now. */
+
+ /* try to read creator of the thumbnail */
+ creator = gdk_pixbuf_get_option (pixbuf, "tEXt::Software");
+
+ /* stupid workaround to display nicer string if the
+ * thumbnail is created through the mate libraries.
+ */
+ if (g_ascii_strcasecmp (creator, "Mate::ThumbnailFactory") == 0) {
+ creator = "MATE Libs";
+ }
+#endif
+ }
+
+ set_preview_label (priv->size_label, size_str);
+ set_preview_label (priv->dim_label, dim_str);
+ set_preview_label (priv->creator_label, creator);
+
+ if (size_str != NULL) {
+ g_free (size_str);
+ }
+
+ if (dim_str != NULL) {
+ g_free (dim_str);
+ }
+}
+
+static void
+update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
+{
+ EomFileChooserPrivate *priv;
+ char *uri;
+ char *thumb_path = NULL;
+ GFile *file;
+ GFileInfo *file_info;
+ GdkPixbuf *pixbuf = NULL;
+ gboolean have_preview = FALSE;
+
+ priv = EOM_FILE_CHOOSER (file_chooser)->priv;
+
+ uri = gtk_file_chooser_get_preview_uri (file_chooser);
+ if (uri == NULL) {
+ gtk_file_chooser_set_preview_widget_active (file_chooser, FALSE);
+ return;
+ }
+
+ file = g_file_new_for_uri (uri);
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED ","
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ 0, NULL, NULL);
+ g_object_unref (file);
+
+ if ((file_info != NULL) && (priv->thumb_factory != NULL)) {
+ guint64 mtime;
+
+ mtime = g_file_info_get_attribute_uint64 (file_info,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ thumb_path = mate_desktop_thumbnail_factory_lookup (priv->thumb_factory, uri, mtime);
+ if (thumb_path == NULL) {
+ /* read files smaller than 100kb directly */
+ if (g_file_info_get_size (file_info) <= 100000) {
+ /* FIXME: we should then output also the image dimensions */
+ thumb_path = gtk_file_chooser_get_preview_filename (file_chooser);
+ }
+ }
+
+ if (thumb_path != NULL && g_file_test (thumb_path, G_FILE_TEST_EXISTS)) {
+ /* try to load and display preview thumbnail */
+ pixbuf = gdk_pixbuf_new_from_file (thumb_path, NULL);
+
+ have_preview = (pixbuf != NULL);
+
+ set_preview_pixbuf (EOM_FILE_CHOOSER (file_chooser), pixbuf,
+ g_file_info_get_size (file_info));
+
+ if (pixbuf != NULL) {
+ g_object_unref (pixbuf);
+ }
+ }
+ }
+
+ if (thumb_path != NULL) {
+ g_free (thumb_path);
+ }
+
+ g_free (uri);
+ g_object_unref (file_info);
+
+ gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
+}
+
+static void
+eom_file_chooser_add_preview (GtkWidget *widget)
+{
+ EomFileChooserPrivate *priv;
+ GtkWidget *vbox;
+
+ priv = EOM_FILE_CHOOSER (widget)->priv;
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+
+ priv->image = gtk_image_new ();
+ /* 128x128 is maximum size of thumbnails */
+ gtk_widget_set_size_request (priv->image, 128,128);
+
+ priv->dim_label = gtk_label_new (NULL);
+ priv->size_label = gtk_label_new (NULL);
+ priv->creator_label = gtk_label_new (NULL);
+
+ gtk_box_pack_start (GTK_BOX (vbox), priv->image, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), priv->dim_label, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), priv->size_label, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), priv->creator_label, FALSE, TRUE, 0);
+
+ gtk_widget_show_all (vbox);
+
+ gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (widget), vbox);
+ gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (widget), FALSE);
+
+ priv->thumb_factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+
+ g_signal_connect (widget, "update-preview",
+ G_CALLBACK (update_preview_cb), NULL);
+}
+
+GtkWidget *
+eom_file_chooser_new (GtkFileChooserAction action)
+{
+ GtkWidget *chooser;
+ gchar *title = NULL;
+
+ chooser = g_object_new (EOM_TYPE_FILE_CHOOSER,
+ "action", action,
+ "select-multiple", (action == GTK_FILE_CHOOSER_ACTION_OPEN),
+ "local-only", FALSE,
+ NULL);
+
+ switch (action) {
+ case GTK_FILE_CHOOSER_ACTION_OPEN:
+ gtk_dialog_add_buttons (GTK_DIALOG (chooser),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+ title = _("Open Image");
+ break;
+
+ case GTK_FILE_CHOOSER_ACTION_SAVE:
+ gtk_dialog_add_buttons (GTK_DIALOG (chooser),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+ title = _("Save Image");
+ break;
+
+ case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+ gtk_dialog_add_buttons (GTK_DIALOG (chooser),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+ title = _("Open Folder");
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) {
+ eom_file_chooser_add_filter (EOM_FILE_CHOOSER (chooser));
+ eom_file_chooser_add_preview (chooser);
+ }
+
+ if (last_dir[action] != NULL) {
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), last_dir [action]);
+ }
+
+ g_signal_connect (chooser, "response",
+ G_CALLBACK ((action == GTK_FILE_CHOOSER_ACTION_SAVE) ?
+ save_response_cb : response_cb),
+ NULL);
+
+ gtk_window_set_title (GTK_WINDOW (chooser), title);
+ gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
+
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (chooser), TRUE);
+
+ return chooser;
+}
+
+GdkPixbufFormat *
+eom_file_chooser_get_format (EomFileChooser *chooser)
+{
+ GtkFileFilter *filter;
+ GdkPixbufFormat* format;
+
+ g_return_val_if_fail (EOM_IS_FILE_CHOOSER (chooser), NULL);
+
+ filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (chooser));
+ if (filter == NULL)
+ return NULL;
+
+ format = g_object_get_data (G_OBJECT (filter), FILE_FORMAT_KEY);
+
+ return format;
+}
diff --git a/src/eom-file-chooser.h b/src/eom-file-chooser.h
new file mode 100644
index 0000000..dc31fcb
--- /dev/null
+++ b/src/eom-file-chooser.h
@@ -0,0 +1,60 @@
+/*
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _EOM_FILE_CHOOSER_H_
+#define _EOM_FILE_CHOOSER_H_
+
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define EOM_TYPE_FILE_CHOOSER (eom_file_chooser_get_type ())
+#define EOM_FILE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EOM_TYPE_FILE_CHOOSER, EomFileChooser))
+#define EOM_FILE_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EOM_TYPE_FILE_CHOOSER, EomFileChooserClass))
+
+#define EOM_IS_FILE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOM_TYPE_FILE_CHOOSER))
+#define EOM_IS_FILE_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EOM_TYPE_FILE_CHOOSER))
+#define EOM_FILE_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EOM_TYPE_FILE_CHOOSER, EomFileChooserClass))
+
+typedef struct _EomFileChooser EomFileChooser;
+typedef struct _EomFileChooserClass EomFileChooserClass;
+typedef struct _EomFileChooserPrivate EomFileChooserPrivate;
+
+struct _EomFileChooser
+{
+ GtkFileChooserDialog parent;
+
+ EomFileChooserPrivate *priv;
+};
+
+struct _EomFileChooserClass
+{
+ GtkFileChooserDialogClass parent_class;
+};
+
+
+GType eom_file_chooser_get_type (void) G_GNUC_CONST;
+
+GtkWidget *eom_file_chooser_new (GtkFileChooserAction action);
+
+GdkPixbufFormat *eom_file_chooser_get_format (EomFileChooser *chooser);
+
+
+G_END_DECLS
+
+#endif /* _EOM_FILE_CHOOSER_H_ */
diff --git a/src/eom-image-jpeg.c b/src/eom-image-jpeg.c
new file mode 100644
index 0000000..ef7a2cc
--- /dev/null
+++ b/src/eom-image-jpeg.c
@@ -0,0 +1,518 @@
+/* This code is based on the jpeg saving code from gdk-pixbuf. Full copyright
+ * notice is given in the following:
+ */
+/* GdkPixbuf library - JPEG image loader
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Progressive loading code Copyright (C) 1999 Red Hat, Inc.
+ *
+ * Authors: Michael Zucchi <[email protected]>
+ * Federico Mena-Quintero <[email protected]>
+ * Michael Fulbright <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-image-jpeg.h"
+#include "eom-image-private.h"
+
+#if HAVE_JPEG
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include "transupp.h"
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib/gi18n.h>
+#if HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+
+#ifdef G_OS_WIN32
+#define sigjmp_buf jmp_buf
+#define sigsetjmp(env, savesigs) setjmp (env)
+#define siglongjmp longjmp
+#endif
+
+typedef enum {
+ EOM_SAVE_NONE,
+ EOM_SAVE_JPEG_AS_JPEG,
+ EOM_SAVE_ANY_AS_JPEG
+} EomJpegSaveMethod;
+
+/* error handler data */
+struct error_handler_data {
+ struct jpeg_error_mgr pub;
+ sigjmp_buf setjmp_buffer;
+ GError **error;
+ char *filename;
+};
+
+
+static void
+fatal_error_handler (j_common_ptr cinfo)
+{
+ struct error_handler_data *errmgr;
+ char buffer[JMSG_LENGTH_MAX];
+
+ errmgr = (struct error_handler_data *) cinfo->err;
+
+ /* Create the message */
+ (* cinfo->err->format_message) (cinfo, buffer);
+
+ /* broken check for *error == NULL for robustness against
+ * crappy JPEG library
+ */
+ if (errmgr->error && *errmgr->error == NULL) {
+ g_set_error (errmgr->error,
+ 0,
+ 0,
+ "Error interpreting JPEG image file: %s\n\n%s",
+ g_path_get_basename (errmgr->filename),
+ buffer);
+ }
+
+ siglongjmp (errmgr->setjmp_buffer, 1);
+
+ g_assert_not_reached ();
+}
+
+
+static void
+output_message_handler (j_common_ptr cinfo)
+{
+ /* This method keeps libjpeg from dumping crap to stderr */
+ /* do nothing */
+}
+
+static void
+init_transform_info (EomImage *image, jpeg_transform_info *info)
+{
+ EomImagePrivate *priv;
+ EomTransform *composition = NULL;
+ EomTransformType transformation;
+ JXFORM_CODE trans_code = JXFORM_NONE;
+
+ g_return_if_fail (EOM_IS_IMAGE (image));
+
+ priv = image->priv;
+
+ if (priv->trans != NULL && priv->trans_autorotate != NULL) {
+ composition = eom_transform_compose (priv->trans,
+ priv->trans_autorotate);
+ } else if (priv->trans != NULL) {
+ composition = g_object_ref (priv->trans);
+ } else if (priv->trans_autorotate != NULL) {
+ composition = g_object_ref (priv->trans_autorotate);
+ }
+
+ if (composition != NULL) {
+ transformation = eom_transform_get_transform_type (composition);
+
+ switch (transformation) {
+ case EOM_TRANSFORM_ROT_90:
+ trans_code = JXFORM_ROT_90;
+ break;
+ case EOM_TRANSFORM_ROT_270:
+ trans_code = JXFORM_ROT_270;
+ break;
+ case EOM_TRANSFORM_ROT_180:
+ trans_code = JXFORM_ROT_180;
+ break;
+ case EOM_TRANSFORM_FLIP_HORIZONTAL:
+ trans_code = JXFORM_FLIP_H;
+ break;
+ case EOM_TRANSFORM_FLIP_VERTICAL:
+ trans_code = JXFORM_FLIP_V;
+ break;
+ default:
+ trans_code = JXFORM_NONE;
+ break;
+ }
+ }
+
+ info->transform = trans_code;
+ info->trim = FALSE;
+#if JPEG_LIB_VERSION >= 80
+ info->crop = FALSE;
+#endif
+ info->force_grayscale = FALSE;
+
+ g_object_unref (composition);
+}
+
+static gboolean
+_save_jpeg_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source,
+ EomImageSaveInfo *target, GError **error)
+{
+ struct jpeg_decompress_struct srcinfo;
+ struct jpeg_compress_struct dstinfo;
+ struct error_handler_data jsrcerr, jdsterr;
+ jpeg_transform_info transformoption;
+ jvirt_barray_ptr *src_coef_arrays;
+ jvirt_barray_ptr *dst_coef_arrays;
+ FILE *output_file;
+ FILE *input_file;
+ EomImagePrivate *priv;
+ gchar *infile_uri;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE);
+ g_return_val_if_fail (EOM_IMAGE (image)->priv->file != NULL, FALSE);
+
+ priv = image->priv;
+
+ init_transform_info (image, &transformoption);
+
+ /* Initialize the JPEG decompression object with default error
+ * handling. */
+ jsrcerr.filename = g_file_get_path (priv->file);
+ srcinfo.err = jpeg_std_error (&(jsrcerr.pub));
+ jsrcerr.pub.error_exit = fatal_error_handler;
+ jsrcerr.pub.output_message = output_message_handler;
+ jsrcerr.error = error;
+
+ jpeg_create_decompress (&srcinfo);
+
+ /* Initialize the JPEG compression object with default error
+ * handling. */
+ jdsterr.filename = (char *) file;
+ dstinfo.err = jpeg_std_error (&(jdsterr.pub));
+ jdsterr.pub.error_exit = fatal_error_handler;
+ jdsterr.pub.output_message = output_message_handler;
+ jdsterr.error = error;
+
+ jpeg_create_compress (&dstinfo);
+
+ dstinfo.err->trace_level = 0;
+ dstinfo.arith_code = FALSE;
+ dstinfo.optimize_coding = FALSE;
+
+ jsrcerr.pub.trace_level = jdsterr.pub.trace_level;
+ srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
+
+ /* Open the output file. */
+ /* FIXME: Make this a GIO aware input manager */
+ infile_uri = g_file_get_path (priv->file);
+ input_file = fopen (infile_uri, "rb");
+ if (input_file == NULL) {
+ g_warning ("Input file not openable: %s\n", infile_uri);
+ g_free (jsrcerr.filename);
+ g_free (infile_uri);
+ return FALSE;
+ }
+ g_free (infile_uri);
+
+ output_file = fopen (file, "wb");
+ if (output_file == NULL) {
+ g_warning ("Output file not openable: %s\n", file);
+ fclose (input_file);
+ g_free (jsrcerr.filename);
+ return FALSE;
+ }
+
+ if (sigsetjmp (jsrcerr.setjmp_buffer, 1)) {
+ fclose (output_file);
+ fclose (input_file);
+ jpeg_destroy_compress (&dstinfo);
+ jpeg_destroy_decompress (&srcinfo);
+ g_free (jsrcerr.filename);
+ return FALSE;
+ }
+
+ if (sigsetjmp (jdsterr.setjmp_buffer, 1)) {
+ fclose (output_file);
+ fclose (input_file);
+ jpeg_destroy_compress (&dstinfo);
+ jpeg_destroy_decompress (&srcinfo);
+ g_free (jsrcerr.filename);
+ return FALSE;
+ }
+
+ /* Specify data source for decompression */
+ jpeg_stdio_src (&srcinfo, input_file);
+
+ /* Enable saving of extra markers that we want to copy */
+ jcopy_markers_setup (&srcinfo, JCOPYOPT_DEFAULT);
+
+ /* Read file header */
+ (void) jpeg_read_header (&srcinfo, TRUE);
+
+ /* Any space needed by a transform option must be requested before
+ * jpeg_read_coefficients so that memory allocation will be done right.
+ */
+ jtransform_request_workspace (&srcinfo, &transformoption);
+
+ /* Read source file as DCT coefficients */
+ src_coef_arrays = jpeg_read_coefficients (&srcinfo);
+
+ /* Initialize destination compression parameters from source values */
+ jpeg_copy_critical_parameters (&srcinfo, &dstinfo);
+
+ /* Adjust destination parameters if required by transform options;
+ * also find out which set of coefficient arrays will hold the output.
+ */
+ dst_coef_arrays = jtransform_adjust_parameters (&srcinfo,
+ &dstinfo,
+ src_coef_arrays,
+ &transformoption);
+
+ /* Specify data destination for compression */
+ jpeg_stdio_dest (&dstinfo, output_file);
+
+ /* Start compressor (note no image data is actually written here) */
+ jpeg_write_coefficients (&dstinfo, dst_coef_arrays);
+
+ /* handle EXIF/IPTC data explicitly */
+#if HAVE_EXIF
+ /* exif_chunk and exif are mutally exclusvie, this is what we assure here */
+ g_assert (priv->exif_chunk == NULL);
+ if (priv->exif != NULL)
+ {
+ unsigned char *exif_buf;
+ unsigned int exif_buf_len;
+
+ exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len);
+ jpeg_write_marker (&dstinfo, JPEG_APP0+1, exif_buf, exif_buf_len);
+ g_free (exif_buf);
+ }
+#else
+ if (priv->exif_chunk != NULL) {
+ jpeg_write_marker (&dstinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len);
+ }
+#endif
+ /* FIXME: Consider IPTC data too */
+
+ /* Copy to the output file any extra markers that we want to
+ * preserve */
+ jcopy_markers_execute (&srcinfo, &dstinfo, JCOPYOPT_DEFAULT);
+
+ /* Execute image transformation, if any */
+ jtransform_execute_transformation (&srcinfo,
+ &dstinfo,
+ src_coef_arrays,
+ &transformoption);
+
+ /* Finish compression and release memory */
+ jpeg_finish_compress (&dstinfo);
+ jpeg_destroy_compress (&dstinfo);
+ (void) jpeg_finish_decompress (&srcinfo);
+ jpeg_destroy_decompress (&srcinfo);
+ g_free (jsrcerr.filename);
+
+ /* Close files */
+ fclose (input_file);
+ fclose (output_file);
+
+ return TRUE;
+}
+
+static gboolean
+_save_any_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source,
+ EomImageSaveInfo *target, GError **error)
+{
+ EomImagePrivate *priv;
+ GdkPixbuf *pixbuf;
+ struct jpeg_compress_struct cinfo;
+ guchar *buf = NULL;
+ guchar *ptr;
+ guchar *pixels = NULL;
+ JSAMPROW *jbuf;
+ int y = 0;
+ volatile int quality = 75; /* default; must be between 0 and 100 */
+ int i, j;
+ int w, h = 0;
+ int rowstride = 0;
+ FILE *outfile;
+ struct error_handler_data jerr;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE);
+ g_return_val_if_fail (EOM_IMAGE (image)->priv->image != NULL, FALSE);
+
+ priv = image->priv;
+ pixbuf = priv->image;
+
+ outfile = fopen (file, "wb");
+ if (outfile == NULL) {
+ g_set_error (error, /* FIXME: Better error message */
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Couldn't create temporary file for saving: %s"),
+ file);
+ return FALSE;
+ }
+
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+
+ /* no image data? abort */
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ g_return_val_if_fail (pixels != NULL, FALSE);
+
+ /* allocate a small buffer to convert image data */
+ buf = g_try_malloc (w * 3 * sizeof (guchar));
+ if (!buf) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Couldn't allocate memory for loading JPEG file"));
+ fclose (outfile);
+ return FALSE;
+ }
+
+ /* set up error handling */
+ jerr.filename = (char *) file;
+ cinfo.err = jpeg_std_error (&(jerr.pub));
+ jerr.pub.error_exit = fatal_error_handler;
+ jerr.pub.output_message = output_message_handler;
+ jerr.error = error;
+
+ /* setup compress params */
+ jpeg_create_compress (&cinfo);
+ jpeg_stdio_dest (&cinfo, outfile);
+ cinfo.image_width = w;
+ cinfo.image_height = h;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ /* error exit routine */
+ if (sigsetjmp (jerr.setjmp_buffer, 1)) {
+ g_free (buf);
+ fclose (outfile);
+ jpeg_destroy_compress (&cinfo);
+ return FALSE;
+ }
+
+ /* set desired jpeg quality if available */
+ if (target != NULL && target->jpeg_quality >= 0.0) {
+ quality = (int) MIN (target->jpeg_quality, 1.0) * 100;
+ }
+
+ /* set up jepg compression parameters */
+ jpeg_set_defaults (&cinfo);
+ jpeg_set_quality (&cinfo, quality, TRUE);
+ jpeg_start_compress (&cinfo, TRUE);
+
+ /* write EXIF/IPTC data explicitly */
+#if HAVE_EXIF
+ /* exif_chunk and exif are mutally exclusvie, this is what we assure here */
+ g_assert (priv->exif_chunk == NULL);
+ if (priv->exif != NULL)
+ {
+ unsigned char *exif_buf;
+ unsigned int exif_buf_len;
+
+ exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len);
+ jpeg_write_marker (&cinfo, 0xe1, exif_buf, exif_buf_len);
+ g_free (exif_buf);
+ }
+#else
+ if (priv->exif_chunk != NULL) {
+ jpeg_write_marker (&cinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len);
+ }
+#endif
+ /* FIXME: Consider IPTC data too */
+
+ /* get the start pointer */
+ ptr = pixels;
+ /* go one scanline at a time... and save */
+ i = 0;
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* convert scanline from ARGB to RGB packed */
+ for (j = 0; j < w; j++)
+ memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*(rowstride/w)]), 3);
+
+ /* write scanline */
+ jbuf = (JSAMPROW *)(&buf);
+ jpeg_write_scanlines (&cinfo, jbuf, 1);
+ i++;
+ y++;
+
+ }
+
+ /* finish off */
+ jpeg_finish_compress (&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ g_free (buf);
+
+ fclose (outfile);
+
+ return TRUE;
+}
+
+gboolean
+eom_image_jpeg_save_file (EomImage *image, const char *file,
+ EomImageSaveInfo *source, EomImageSaveInfo *target,
+ GError **error)
+{
+ EomJpegSaveMethod method = EOM_SAVE_NONE;
+ gboolean source_is_jpeg = FALSE;
+ gboolean target_is_jpeg = FALSE;
+ gboolean result;
+
+ g_return_val_if_fail (source != NULL, FALSE);
+
+ source_is_jpeg = !g_ascii_strcasecmp (source->format, EOM_FILE_FORMAT_JPEG);
+
+ /* determine which method should be used for saving */
+ if (target == NULL) {
+ if (source_is_jpeg) {
+ method = EOM_SAVE_JPEG_AS_JPEG;
+ }
+ }
+ else {
+ target_is_jpeg = !g_ascii_strcasecmp (target->format, EOM_FILE_FORMAT_JPEG);
+
+ if (source_is_jpeg && target_is_jpeg) {
+ if (target->jpeg_quality < 0.0) {
+ method = EOM_SAVE_JPEG_AS_JPEG;
+ }
+ else {
+ /* reencoding is required, cause quality is set */
+ method = EOM_SAVE_ANY_AS_JPEG;
+ }
+ }
+ else if (!source_is_jpeg && target_is_jpeg) {
+ method = EOM_SAVE_ANY_AS_JPEG;
+ }
+ }
+
+ switch (method) {
+ case EOM_SAVE_JPEG_AS_JPEG:
+ result = _save_jpeg_as_jpeg (image, file, source, target, error);
+ break;
+ case EOM_SAVE_ANY_AS_JPEG:
+ result = _save_any_as_jpeg (image, file, source, target, error);
+ break;
+ default:
+ result = FALSE;
+ }
+
+ return result;
+}
+#endif
diff --git a/src/eom-image-jpeg.h b/src/eom-image-jpeg.h
new file mode 100644
index 0000000..4e43d0d
--- /dev/null
+++ b/src/eom-image-jpeg.h
@@ -0,0 +1,22 @@
+#ifndef _EOM_IMAGE_JPEG_H_
+#define _EOM_IMAGE_JPEG_H_
+
+#if HAVE_JPEG
+
+#include <glib.h>
+#include "eom-image.h"
+#include "eom-image-save-info.h"
+
+/* Saves a source jpeg file in an arbitrary format (as specified by
+ * target). The target pointer may be NULL, in which case the output
+ * file is saved as jpeg too. This method tries to be as smart as
+ * possible. It will save the image as lossless as possible (if the
+ * target is a jpeg image too).
+ */
+G_GNUC_INTERNAL
+gboolean eom_image_jpeg_save_file (EomImage *image, const char *file,
+ EomImageSaveInfo *source, EomImageSaveInfo *target,
+ GError **error);
+#endif
+
+#endif /* _EOM_IMAGE_JPEG_H_ */
diff --git a/src/eom-image-private.h b/src/eom-image-private.h
new file mode 100644
index 0000000..794d4ad
--- /dev/null
+++ b/src/eom-image-private.h
@@ -0,0 +1,96 @@
+/* Eye Of Mate - Image Private Data
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_IMAGE_PRIVATE_H__
+#define __EOM_IMAGE_PRIVATE_H__
+
+#include "eom-image.h"
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#endif
+
+G_BEGIN_DECLS
+
+struct _EomImagePrivate {
+ GFile *file;
+
+ EomImageStatus status;
+ EomImageStatus prev_status;
+ gboolean is_monitored;
+ EomImageMetadataStatus metadata_status;
+
+ GdkPixbuf *image;
+ GdkPixbufAnimation *anim;
+ GdkPixbufAnimationIter *anim_iter;
+ gboolean is_playing;
+ GdkPixbuf *thumbnail;
+#ifdef HAVE_RSVG
+ RsvgHandle *svg;
+#endif
+
+ gint width;
+ gint height;
+
+ goffset bytes;
+ gchar *file_type;
+ gboolean threadsafe_format;
+
+ /* Holds EXIF raw data */
+ guint exif_chunk_len;
+ guchar *exif_chunk;
+
+ /* Holds IPTC raw data */
+ guchar *iptc_chunk;
+ guint iptc_chunk_len;
+
+ gboolean modified;
+
+#ifdef HAVE_EXIF
+ gboolean autorotate;
+ gint orientation;
+ ExifData *exif;
+#endif
+#ifdef HAVE_EXEMPI
+ XmpPtr xmp;
+#endif
+
+#ifdef HAVE_LCMS
+ cmsHPROFILE profile;
+#endif
+
+ gchar *caption;
+
+ gchar *collate_key;
+
+ GMutex *status_mutex;
+
+ gboolean cancel_loading;
+ guint data_ref_count;
+
+ GSList *undo_stack;
+
+ EomTransform *trans;
+ EomTransform *trans_autorotate;
+};
+
+G_END_DECLS
+
+#endif /* __EOM_IMAGE_PRIVATE_H__ */
diff --git a/src/eom-image-save-info.c b/src/eom-image-save-info.c
new file mode 100644
index 0000000..d368a61
--- /dev/null
+++ b/src/eom-image-save-info.c
@@ -0,0 +1,150 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include "eom-image-save-info.h"
+#include "eom-image-private.h"
+#include "eom-pixbuf-util.h"
+#include "eom-image.h"
+
+G_DEFINE_TYPE (EomImageSaveInfo, eom_image_save_info, G_TYPE_OBJECT)
+
+static void
+eom_image_save_info_dispose (GObject *object)
+{
+ EomImageSaveInfo *info = EOM_IMAGE_SAVE_INFO (object);
+
+ if (info->file != NULL) {
+ g_object_unref (info->file);
+ info->file = NULL;
+ }
+
+ if (info->format != NULL) {
+ g_free (info->format);
+ info->format = NULL;
+ }
+
+ G_OBJECT_CLASS (eom_image_save_info_parent_class)->dispose (object);
+}
+
+static void
+eom_image_save_info_init (EomImageSaveInfo *obj)
+{
+
+}
+
+static void
+eom_image_save_info_class_init (EomImageSaveInfoClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eom_image_save_info_dispose;
+}
+
+/* is_local_uri:
+ *
+ * Checks if the URI points to a local file system. This tests simply
+ * if the URI scheme is 'file'. This function is used to ensure that
+ * we can write to the path-part of the URI with non-VFS aware
+ * filesystem calls.
+ */
+static gboolean
+is_local_file (GFile *file)
+{
+ char *scheme;
+ gboolean ret;
+
+ g_return_val_if_fail (file != NULL, FALSE);
+
+ scheme = g_file_get_uri_scheme (file);
+
+ ret = (g_ascii_strcasecmp (scheme, "file") == 0);
+ g_free (scheme);
+ return ret;
+}
+
+static char*
+get_save_file_type_by_file (GFile *file)
+{
+ GdkPixbufFormat *format;
+ char *type = NULL;
+
+ format = eom_pixbuf_get_format (file);
+ if (format != NULL) {
+ type = gdk_pixbuf_format_get_name (format);
+ }
+
+ return type;
+}
+
+EomImageSaveInfo*
+eom_image_save_info_from_image (gpointer data)
+{
+ EomImageSaveInfo *info = NULL;
+ EomImage *image;
+
+ image = EOM_IMAGE (data);
+
+ g_return_val_if_fail (EOM_IS_IMAGE (image), NULL);
+
+ info = g_object_new (EOM_TYPE_IMAGE_SAVE_INFO, NULL);
+
+ info->file = eom_image_get_file (image);
+ info->format = g_strdup (image->priv->file_type);
+ info->exists = g_file_query_exists (info->file, NULL);
+ info->local = is_local_file (info->file);
+ info->has_metadata = eom_image_has_data (image, EOM_IMAGE_DATA_EXIF);
+ info->modified = eom_image_is_modified (image);
+ info->overwrite = FALSE;
+
+ info->jpeg_quality = -1.0;
+
+ return info;
+}
+
+EomImageSaveInfo*
+eom_image_save_info_from_uri (const char *txt_uri, GdkPixbufFormat *format)
+{
+ GFile *file;
+ EomImageSaveInfo *info;
+
+ g_return_val_if_fail (txt_uri != NULL, NULL);
+
+ file = g_file_new_for_uri (txt_uri);
+
+ info = eom_image_save_info_from_file (file, format);
+
+ g_object_unref (file);
+
+ return info;
+}
+
+EomImageSaveInfo*
+eom_image_save_info_from_file (GFile *file, GdkPixbufFormat *format)
+{
+ EomImageSaveInfo *info;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ info = g_object_new (EOM_TYPE_IMAGE_SAVE_INFO, NULL);
+
+ info->file = g_object_ref (file);
+ if (format == NULL) {
+ info->format = get_save_file_type_by_file (info->file);
+ }
+ else {
+ info->format = gdk_pixbuf_format_get_name (format);
+ }
+ info->exists = g_file_query_exists (file, NULL);
+ info->local = is_local_file (file);
+ info->has_metadata = FALSE;
+ info->modified = FALSE;
+ info->overwrite = FALSE;
+
+ info->jpeg_quality = -1.0;
+
+ g_assert (info->format != NULL);
+
+ return info;
+}
diff --git a/src/eom-image-save-info.h b/src/eom-image-save-info.h
new file mode 100644
index 0000000..8a3c36f
--- /dev/null
+++ b/src/eom-image-save-info.h
@@ -0,0 +1,54 @@
+#ifndef _EOM_IMAGE_SAVE_INFO_H_
+#define _EOM_IMAGE_SAVE_INFO_H_
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+struct EomImage;
+
+#define EOM_TYPE_IMAGE_SAVE_INFO (eom_image_save_info_get_type ())
+#define EOM_IMAGE_SAVE_INFO(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EOM_TYPE_IMAGE_SAVE_INFO, EomImageSaveInfo))
+#define EOM_IMAGE_SAVE_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EOM_TYPE_IMAGE_SAVE_INFO, EomImageSaveInfoClass))
+#define EOM_IS_IMAGE_SAVE_INFO(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOM_TYPE_IMAGE_SAVE_INFO))
+#define EOM_IS_IMAGE_SAVE_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EOM_TYPE_IMAGE_SAVE_INFO))
+#define EOM_IMAGE_SAVE_INFO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EOM_TYPE_IMAGE_SAVE_INFO, EomImageSaveInfoClass))
+
+typedef struct _EomImageSaveInfo EomImageSaveInfo;
+typedef struct _EomImageSaveInfoClass EomImageSaveInfoClass;
+
+struct _EomImageSaveInfo {
+ GObject parent;
+
+ GFile *file;
+ char *format;
+ gboolean exists;
+ gboolean local;
+ gboolean has_metadata;
+ gboolean modified;
+ gboolean overwrite;
+
+ float jpeg_quality; /* valid range: [0.0 ... 1.0] */
+};
+
+struct _EomImageSaveInfoClass {
+ GObjectClass parent_klass;
+};
+
+#define EOM_FILE_FORMAT_JPEG "jpeg"
+
+GType eom_image_save_info_get_type (void) G_GNUC_CONST;
+
+EomImageSaveInfo *eom_image_save_info_from_image (gpointer data);
+
+EomImageSaveInfo *eom_image_save_info_from_uri (const char *uri,
+ GdkPixbufFormat *format);
+
+EomImageSaveInfo *eom_image_save_info_from_file (GFile *file,
+ GdkPixbufFormat *format);
+
+G_END_DECLS
+
+#endif /* _EOM_IMAGE_SAVE_INFO_H_ */
diff --git a/src/eom-image.c b/src/eom-image.c
new file mode 100644
index 0000000..e57e7cb
--- /dev/null
+++ b/src/eom-image.c
@@ -0,0 +1,2237 @@
+/* Eye Of Mate - Image
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define GDK_PIXBUF_ENABLE_BACKEND
+
+#include "eom-image.h"
+#include "eom-image-private.h"
+#include "eom-debug.h"
+
+#ifdef HAVE_JPEG
+#include "eom-image-jpeg.h"
+#endif
+
+#include "eom-marshal.h"
+#include "eom-pixbuf-util.h"
+#include "eom-metadata-reader.h"
+#include "eom-image-save-info.h"
+#include "eom-transform.h"
+#include "eom-util.h"
+#include "eom-jobs.h"
+#include "eom-thumbnail.h"
+
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifdef HAVE_EXIF
+#include <libexif/exif-data.h>
+#include <libexif/exif-utils.h>
+#include <libexif/exif-loader.h>
+#endif
+
+#ifdef HAVE_LCMS
+#include <lcms.h>
+#ifndef EXIF_TAG_GAMMA
+#define EXIF_TAG_GAMMA 0xa500
+#endif
+#endif
+
+#define EOM_IMAGE_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_IMAGE, EomImagePrivate))
+
+G_DEFINE_TYPE (EomImage, eom_image, G_TYPE_OBJECT)
+
+enum {
+ SIGNAL_CHANGED,
+ SIGNAL_SIZE_PREPARED,
+ SIGNAL_THUMBNAIL_CHANGED,
+ SIGNAL_SAVE_PROGRESS,
+ SIGNAL_NEXT_FRAME,
+ SIGNAL_FILE_CHANGED,
+ SIGNAL_LAST
+};
+
+static gint signals[SIGNAL_LAST];
+
+static GList *supported_mime_types = NULL;
+
+#define EOM_IMAGE_READ_BUFFER_SIZE 65535
+
+static void
+eom_image_free_mem_private (EomImage *image)
+{
+ EomImagePrivate *priv;
+
+ priv = image->priv;
+
+ if (priv->status == EOM_IMAGE_STATUS_LOADING) {
+ eom_image_cancel_load (image);
+ } else {
+ if (priv->anim_iter != NULL) {
+ g_object_unref (priv->anim_iter);
+ priv->anim_iter = NULL;
+ }
+
+ if (priv->anim != NULL) {
+ g_object_unref (priv->anim);
+ priv->anim = NULL;
+ }
+
+ priv->is_playing = FALSE;
+
+ if (priv->image != NULL) {
+ g_object_unref (priv->image);
+ priv->image = NULL;
+ }
+
+#ifdef HAVE_RSVG
+ if (priv->svg != NULL) {
+ g_object_unref (priv->svg);
+ priv->svg = NULL;
+ }
+#endif
+
+#ifdef HAVE_EXIF
+ if (priv->exif != NULL) {
+ exif_data_unref (priv->exif);
+ priv->exif = NULL;
+ }
+#endif
+
+ if (priv->exif_chunk != NULL) {
+ g_free (priv->exif_chunk);
+ priv->exif_chunk = NULL;
+ }
+
+ priv->exif_chunk_len = 0;
+
+#ifdef HAVE_EXEMPI
+ if (priv->xmp != NULL) {
+ xmp_free (priv->xmp);
+ priv->xmp = NULL;
+ }
+#endif
+
+#ifdef HAVE_LCMS
+ if (priv->profile != NULL) {
+ cmsCloseProfile (priv->profile);
+ priv->profile = NULL;
+ }
+#endif
+
+ priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+ }
+}
+
+static void
+eom_image_dispose (GObject *object)
+{
+ EomImagePrivate *priv;
+
+ priv = EOM_IMAGE (object)->priv;
+
+ eom_image_free_mem_private (EOM_IMAGE (object));
+
+ if (priv->file) {
+ g_object_unref (priv->file);
+ priv->file = NULL;
+ }
+
+ if (priv->caption) {
+ g_free (priv->caption);
+ priv->caption = NULL;
+ }
+
+ if (priv->collate_key) {
+ g_free (priv->collate_key);
+ priv->collate_key = NULL;
+ }
+
+ if (priv->file_type) {
+ g_free (priv->file_type);
+ priv->file_type = NULL;
+ }
+
+ if (priv->status_mutex) {
+ g_mutex_free (priv->status_mutex);
+ priv->status_mutex = NULL;
+ }
+
+ if (priv->trans) {
+ g_object_unref (priv->trans);
+ priv->trans = NULL;
+ }
+
+ if (priv->trans_autorotate) {
+ g_object_unref (priv->trans_autorotate);
+ priv->trans_autorotate = NULL;
+ }
+
+ if (priv->undo_stack) {
+ g_slist_foreach (priv->undo_stack, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->undo_stack);
+ priv->undo_stack = NULL;
+ }
+
+ G_OBJECT_CLASS (eom_image_parent_class)->dispose (object);
+}
+
+static void
+eom_image_class_init (EomImageClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eom_image_dispose;
+
+ signals[SIGNAL_SIZE_PREPARED] =
+ g_signal_new ("size-prepared",
+ EOM_TYPE_IMAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomImageClass, size_prepared),
+ NULL, NULL,
+ eom_marshal_VOID__INT_INT,
+ G_TYPE_NONE, 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
+
+ signals[SIGNAL_CHANGED] =
+ g_signal_new ("changed",
+ EOM_TYPE_IMAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomImageClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[SIGNAL_THUMBNAIL_CHANGED] =
+ g_signal_new ("thumbnail-changed",
+ EOM_TYPE_IMAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomImageClass, thumbnail_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[SIGNAL_SAVE_PROGRESS] =
+ g_signal_new ("save-progress",
+ EOM_TYPE_IMAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomImageClass, save_progress),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__FLOAT,
+ G_TYPE_NONE, 1,
+ G_TYPE_FLOAT);
+ /**
+ * EomImage::next-frame:
+ * @img: the object which received the signal.
+ * @delay: number of milliseconds the current frame will be displayed.
+ *
+ * The ::next-frame signal will be emitted each time an animated image
+ * advances to the next frame.
+ */
+ signals[SIGNAL_NEXT_FRAME] =
+ g_signal_new ("next-frame",
+ EOM_TYPE_IMAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomImageClass, next_frame),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1,
+ G_TYPE_INT);
+
+ signals[SIGNAL_FILE_CHANGED] = g_signal_new ("file-changed",
+ EOM_TYPE_IMAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomImageClass, file_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (object_class, sizeof (EomImagePrivate));
+}
+
+static void
+eom_image_init (EomImage *img)
+{
+ img->priv = EOM_IMAGE_GET_PRIVATE (img);
+
+ img->priv->file = NULL;
+ img->priv->image = NULL;
+ img->priv->anim = NULL;
+ img->priv->anim_iter = NULL;
+ img->priv->is_playing = FALSE;
+ img->priv->thumbnail = NULL;
+ img->priv->width = -1;
+ img->priv->height = -1;
+ img->priv->modified = FALSE;
+ img->priv->status_mutex = g_mutex_new ();
+ img->priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+ img->priv->metadata_status = EOM_IMAGE_METADATA_NOT_READ;
+ img->priv->is_monitored = FALSE;
+ img->priv->undo_stack = NULL;
+ img->priv->trans = NULL;
+ img->priv->trans_autorotate = NULL;
+ img->priv->data_ref_count = 0;
+#ifdef HAVE_EXIF
+ img->priv->orientation = 0;
+ img->priv->autorotate = FALSE;
+ img->priv->exif = NULL;
+#endif
+#ifdef HAVE_EXEMPI
+ img->priv->xmp = NULL;
+#endif
+#ifdef HAVE_LCMS
+ img->priv->profile = NULL;
+#endif
+#ifdef HAVE_RSVG
+ img->priv->svg = NULL;
+#endif
+}
+
+EomImage *
+eom_image_new (const char *txt_uri)
+{
+ EomImage *img;
+
+ img = EOM_IMAGE (g_object_new (EOM_TYPE_IMAGE, NULL));
+
+ img->priv->file = g_file_new_for_uri (txt_uri);
+
+ return img;
+}
+
+EomImage *
+eom_image_new_file (GFile *file)
+{
+ EomImage *img;
+
+ img = EOM_IMAGE (g_object_new (EOM_TYPE_IMAGE, NULL));
+
+ img->priv->file = g_object_ref (file);
+
+ return img;
+}
+
+GQuark
+eom_image_error_quark (void)
+{
+ static GQuark q = 0;
+
+ if (q == 0) {
+ q = g_quark_from_static_string ("eom-image-error-quark");
+ }
+
+ return q;
+}
+
+static void
+eom_image_update_exif_data (EomImage *image)
+{
+#ifdef HAVE_EXIF
+ EomImagePrivate *priv;
+ ExifEntry *entry;
+ ExifByteOrder bo;
+
+ eom_debug (DEBUG_IMAGE_DATA);
+
+ g_return_if_fail (EOM_IS_IMAGE (image));
+
+ priv = image->priv;
+
+ if (priv->exif == NULL) return;
+
+ bo = exif_data_get_byte_order (priv->exif);
+
+ /* Update image width */
+ entry = exif_data_get_entry (priv->exif, EXIF_TAG_PIXEL_X_DIMENSION);
+ if (entry != NULL && (priv->width >= 0)) {
+ if (entry->format == EXIF_FORMAT_LONG)
+ exif_set_long (entry->data, bo, priv->width);
+ else if (entry->format == EXIF_FORMAT_SHORT)
+ exif_set_short (entry->data, bo, priv->width);
+ else
+ g_warning ("Exif entry has unsupported size");
+ }
+
+ /* Update image height */
+ entry = exif_data_get_entry (priv->exif, EXIF_TAG_PIXEL_Y_DIMENSION);
+ if (entry != NULL && (priv->height >= 0)) {
+ if (entry->format == EXIF_FORMAT_LONG)
+ exif_set_long (entry->data, bo, priv->height);
+ else if (entry->format == EXIF_FORMAT_SHORT)
+ exif_set_short (entry->data, bo, priv->height);
+ else
+ g_warning ("Exif entry has unsupported size");
+ }
+
+ /* Update image orientation */
+ entry = exif_data_get_entry (priv->exif, EXIF_TAG_ORIENTATION);
+ if (entry != NULL) {
+ if (entry->format == EXIF_FORMAT_LONG)
+ exif_set_long (entry->data, bo, 1);
+ else if (entry->format == EXIF_FORMAT_SHORT)
+ exif_set_short (entry->data, bo, 1);
+ else
+ g_warning ("Exif entry has unsupported size");
+
+ priv->orientation = 1;
+ }
+#endif
+}
+
+static void
+eom_image_real_transform (EomImage *img,
+ EomTransform *trans,
+ gboolean is_undo,
+ EomJob *job)
+{
+ EomImagePrivate *priv;
+ GdkPixbuf *transformed;
+ gboolean modified = FALSE;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+ g_return_if_fail (EOM_IS_TRANSFORM (trans));
+
+ priv = img->priv;
+
+ if (priv->image != NULL) {
+ transformed = eom_transform_apply (trans, priv->image, job);
+
+ g_object_unref (priv->image);
+ priv->image = transformed;
+
+ priv->width = gdk_pixbuf_get_width (transformed);
+ priv->height = gdk_pixbuf_get_height (transformed);
+
+ modified = TRUE;
+ }
+
+ if (priv->thumbnail != NULL) {
+ transformed = eom_transform_apply (trans, priv->thumbnail, NULL);
+
+ g_object_unref (priv->thumbnail);
+ priv->thumbnail = transformed;
+
+ modified = TRUE;
+ }
+
+ if (modified) {
+ priv->modified = TRUE;
+ eom_image_update_exif_data (img);
+ }
+
+ if (priv->trans == NULL) {
+ g_object_ref (trans);
+ priv->trans = trans;
+ } else {
+ EomTransform *composition;
+
+ composition = eom_transform_compose (priv->trans, trans);
+
+ g_object_unref (priv->trans);
+
+ priv->trans = composition;
+ }
+
+ if (!is_undo) {
+ g_object_ref (trans);
+ priv->undo_stack = g_slist_prepend (priv->undo_stack, trans);
+ }
+}
+
+static gboolean
+do_emit_size_prepared_signal (EomImage *img)
+{
+ g_signal_emit (img, signals[SIGNAL_SIZE_PREPARED], 0,
+ img->priv->width, img->priv->height);
+ return FALSE;
+}
+
+static void
+eom_image_emit_size_prepared (EomImage *img)
+{
+ gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) do_emit_size_prepared_signal,
+ g_object_ref (img), g_object_unref);
+}
+
+static gboolean
+check_loader_threadsafety (GdkPixbufLoader *loader, gboolean *result)
+{
+ GdkPixbufFormat *format;
+ gboolean ret_val = FALSE;
+
+ format = gdk_pixbuf_loader_get_format (loader);
+ if (format) {
+ ret_val = TRUE;
+ if (result)
+ /* FIXME: We should not be accessing this struct internals
+ * directly. Keep track of bug #469209 to fix that. */
+ *result = format->flags & GDK_PIXBUF_FORMAT_THREADSAFE;
+ }
+
+ return ret_val;
+}
+
+static void
+eom_image_pre_size_prepared (GdkPixbufLoader *loader,
+ gint width,
+ gint height,
+ gpointer data)
+{
+ EomImage *img;
+
+ eom_debug (DEBUG_IMAGE_LOAD);
+
+ g_return_if_fail (EOM_IS_IMAGE (data));
+
+ img = EOM_IMAGE (data);
+ check_loader_threadsafety (loader, &img->priv->threadsafe_format);
+}
+
+static void
+eom_image_size_prepared (GdkPixbufLoader *loader,
+ gint width,
+ gint height,
+ gpointer data)
+{
+ EomImage *img;
+
+ eom_debug (DEBUG_IMAGE_LOAD);
+
+ g_return_if_fail (EOM_IS_IMAGE (data));
+
+ img = EOM_IMAGE (data);
+
+ g_mutex_lock (img->priv->status_mutex);
+
+ img->priv->width = width;
+ img->priv->height = height;
+
+ g_mutex_unlock (img->priv->status_mutex);
+
+#ifdef HAVE_EXIF
+ if (img->priv->threadsafe_format && (!img->priv->autorotate || img->priv->exif))
+#else
+ if (img->priv->threadsafe_format)
+#endif
+ eom_image_emit_size_prepared (img);
+}
+
+static EomMetadataReader*
+check_for_metadata_img_format (EomImage *img, guchar *buffer, guint bytes_read)
+{
+ EomMetadataReader *md_reader = NULL;
+
+ eom_debug_message (DEBUG_IMAGE_DATA, "Check image format for jpeg: %x%x - length: %i",
+ buffer[0], buffer[1], bytes_read);
+
+ if (bytes_read >= 2) {
+ /* SOI (start of image) marker for JPEGs is 0xFFD8 */
+ if ((buffer[0] == 0xFF) && (buffer[1] == 0xD8)) {
+ md_reader = eom_metadata_reader_new (EOM_METADATA_JPEG);
+ }
+ if (bytes_read >= 8 &&
+ memcmp (buffer, "\x89PNG\x0D\x0A\x1a\x0A", 8) == 0) {
+ md_reader = eom_metadata_reader_new (EOM_METADATA_PNG);
+ }
+ }
+
+ return md_reader;
+}
+
+static gboolean
+eom_image_needs_transformation (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ return (img->priv->trans != NULL || img->priv->trans_autorotate != NULL);
+}
+
+static gboolean
+eom_image_apply_transformations (EomImage *img, GError **error)
+{
+ GdkPixbuf *transformed = NULL;
+ EomTransform *composition = NULL;
+ EomImagePrivate *priv;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ priv = img->priv;
+
+ if (priv->trans == NULL && priv->trans_autorotate == NULL) {
+ return TRUE;
+ }
+
+ if (priv->image == NULL) {
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_NOT_LOADED,
+ _("Transformation on unloaded image."));
+
+ return FALSE;
+ }
+
+ if (priv->trans != NULL && priv->trans_autorotate != NULL) {
+ composition = eom_transform_compose (priv->trans,
+ priv->trans_autorotate);
+ } else if (priv->trans != NULL) {
+ composition = g_object_ref (priv->trans);
+ } else if (priv->trans_autorotate != NULL) {
+ composition = g_object_ref (priv->trans_autorotate);
+ }
+
+ if (composition != NULL) {
+ transformed = eom_transform_apply (composition, priv->image, NULL);
+ }
+
+ g_object_unref (priv->image);
+ priv->image = transformed;
+
+ if (transformed != NULL) {
+ priv->width = gdk_pixbuf_get_width (priv->image);
+ priv->height = gdk_pixbuf_get_height (priv->image);
+ } else {
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_GENERIC,
+ _("Transformation failed."));
+ }
+
+ g_object_unref (composition);
+
+ return (transformed != NULL);
+}
+
+static void
+eom_image_get_file_info (EomImage *img,
+ goffset *bytes,
+ gchar **mime_type,
+ GError **error)
+{
+ GFileInfo *file_info;
+
+ file_info = g_file_query_info (img->priv->file,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, error);
+
+ if (file_info == NULL) {
+ if (bytes)
+ *bytes = 0;
+
+ if (mime_type)
+ *mime_type = NULL;
+
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_VFS,
+ "Error in getting image file info");
+ } else {
+ if (bytes)
+ *bytes = g_file_info_get_size (file_info);
+
+ if (mime_type)
+ *mime_type = g_strdup (g_file_info_get_content_type (file_info));
+ g_object_unref (file_info);
+ }
+}
+
+#ifdef HAVE_LCMS
+void
+eom_image_apply_display_profile (EomImage *img, cmsHPROFILE screen)
+{
+ EomImagePrivate *priv;
+ cmsHTRANSFORM transform;
+ gint row, width, rows, stride;
+ guchar *p;
+
+ g_return_if_fail (img != NULL);
+
+ priv = img->priv;
+
+ if (screen == NULL || priv->profile == NULL) return;
+
+ /* TODO: support other colorspaces than RGB */
+ if (cmsGetColorSpace (priv->profile) != icSigRgbData ||
+ cmsGetColorSpace (screen) != icSigRgbData) {
+ eom_debug_message (DEBUG_LCMS, "One or both ICC profiles not in RGB colorspace; not correcting");
+ return;
+ }
+
+ /* TODO: find the right way to colorcorrect RGBA images */
+ if (gdk_pixbuf_get_has_alpha (priv->image)) {
+ eom_debug_message (DEBUG_LCMS, "Colorcorrecting RGBA images is unsupported.");
+ return;
+ }
+
+ transform = cmsCreateTransform (priv->profile,
+ TYPE_RGB_8,
+ screen,
+ TYPE_RGB_8,
+ INTENT_PERCEPTUAL,
+ 0);
+
+ if (G_LIKELY (transform != NULL)) {
+ rows = gdk_pixbuf_get_height (priv->image);
+ width = gdk_pixbuf_get_width (priv->image);
+ stride = gdk_pixbuf_get_rowstride (priv->image);
+ p = gdk_pixbuf_get_pixels (priv->image);
+
+ for (row = 0; row < rows; ++row) {
+ cmsDoTransform (transform, p, p, width);
+ p += stride;
+ }
+ cmsDeleteTransform (transform);
+ }
+}
+
+static void
+eom_image_set_icc_data (EomImage *img, EomMetadataReader *md_reader)
+{
+ EomImagePrivate *priv = img->priv;
+
+ priv->profile = eom_metadata_reader_get_icc_profile (md_reader);
+
+
+}
+#endif
+
+#ifdef HAVE_EXIF
+static void
+eom_image_set_orientation (EomImage *img)
+{
+ EomImagePrivate *priv;
+ ExifData* exif;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ exif = (ExifData*) eom_image_get_exif_info (img);
+
+ if (exif != NULL) {
+ ExifByteOrder o = exif_data_get_byte_order (exif);
+
+ ExifEntry *entry = exif_data_get_entry (exif,
+ EXIF_TAG_ORIENTATION);
+
+ if (entry && entry->data != NULL) {
+ priv->orientation = exif_get_short (entry->data, o);
+ }
+ }
+
+ /* exif_data_unref handles NULL values like g_free */
+ exif_data_unref (exif);
+
+ if (priv->orientation > 4 &&
+ priv->orientation < 9) {
+ gint tmp;
+
+ tmp = priv->width;
+ priv->width = priv->height;
+ priv->height = tmp;
+ }
+}
+
+static void
+eom_image_real_autorotate (EomImage *img)
+{
+ static const EomTransformType lookup[8] = {EOM_TRANSFORM_NONE,
+ EOM_TRANSFORM_FLIP_HORIZONTAL,
+ EOM_TRANSFORM_ROT_180,
+ EOM_TRANSFORM_FLIP_VERTICAL,
+ EOM_TRANSFORM_TRANSPOSE,
+ EOM_TRANSFORM_ROT_90,
+ EOM_TRANSFORM_TRANSVERSE,
+ EOM_TRANSFORM_ROT_270};
+ EomImagePrivate *priv;
+ EomTransformType type;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ type = (priv->orientation >= 1 && priv->orientation <= 8 ?
+ lookup[priv->orientation - 1] : EOM_TRANSFORM_NONE);
+
+ if (type != EOM_TRANSFORM_NONE) {
+ img->priv->trans_autorotate = eom_transform_new (type);
+ }
+
+ /* Disable auto orientation for next loads */
+ priv->autorotate = FALSE;
+}
+
+void
+eom_image_autorotate (EomImage *img)
+{
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ /* Schedule auto orientation */
+ img->priv->autorotate = TRUE;
+}
+#endif
+
+#ifdef HAVE_EXEMPI
+static void
+eom_image_set_xmp_data (EomImage *img, EomMetadataReader *md_reader)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ if (priv->xmp) {
+ xmp_free (priv->xmp);
+ }
+ priv->xmp = eom_metadata_reader_get_xmp_data (md_reader);
+}
+#endif
+
+static void
+eom_image_set_exif_data (EomImage *img, EomMetadataReader *md_reader)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+#ifdef HAVE_EXIF
+ g_mutex_lock (priv->status_mutex);
+ if (priv->exif) {
+ exif_data_unref (priv->exif);
+ }
+ priv->exif = eom_metadata_reader_get_exif_data (md_reader);
+ g_mutex_unlock (priv->status_mutex);
+
+ priv->exif_chunk = NULL;
+ priv->exif_chunk_len = 0;
+
+ /* EXIF data is already available, set the image orientation */
+ if (priv->autorotate) {
+ eom_image_set_orientation (img);
+
+ /* Emit size prepared signal if we have the size */
+ if (priv->width > 0 &&
+ priv->height > 0) {
+ eom_image_emit_size_prepared (img);
+ }
+ }
+#else
+ if (priv->exif_chunk) {
+ g_free (priv->exif_chunk);
+ }
+ eom_metadata_reader_get_exif_chunk (md_reader,
+ &priv->exif_chunk,
+ &priv->exif_chunk_len);
+#endif
+}
+
+/*
+ * Attempts to get the image dimensions from the thumbnail.
+ * Returns FALSE if this information is not found.
+ **/
+static gboolean
+eom_image_get_dimension_from_thumbnail (EomImage *image,
+ gint *width,
+ gint *height)
+{
+ if (image->priv->thumbnail == NULL)
+ return FALSE;
+
+ *width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (image->priv->thumbnail),
+ EOM_THUMBNAIL_ORIGINAL_WIDTH));
+ *height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (image->priv->thumbnail),
+ EOM_THUMBNAIL_ORIGINAL_HEIGHT));
+
+ return (*width || *height);
+}
+
+static gboolean
+eom_image_real_load (EomImage *img,
+ guint data2read,
+ EomJob *job,
+ GError **error)
+{
+ EomImagePrivate *priv;
+ GFileInputStream *input_stream;
+ EomMetadataReader *md_reader = NULL;
+ GdkPixbufFormat *format;
+ gchar *mime_type;
+ GdkPixbufLoader *loader = NULL;
+ guchar *buffer;
+ goffset bytes_read, bytes_read_total = 0;
+ gboolean failed = FALSE;
+ gboolean first_run = TRUE;
+ gboolean set_metadata = TRUE;
+ gboolean read_image_data = (data2read & EOM_IMAGE_DATA_IMAGE);
+ gboolean read_only_dimension = (data2read & EOM_IMAGE_DATA_DIMENSION) &&
+ ((data2read ^ EOM_IMAGE_DATA_DIMENSION) == 0);
+
+
+ priv = img->priv;
+
+ g_assert (!read_image_data || priv->image == NULL);
+
+ if (read_image_data && priv->file_type != NULL) {
+ g_free (priv->file_type);
+ priv->file_type = NULL;
+ }
+
+ priv->threadsafe_format = FALSE;
+
+ eom_image_get_file_info (img, &priv->bytes, &mime_type, error);
+
+ if (error && *error) {
+ g_free (mime_type);
+ return FALSE;
+ }
+
+ if (read_only_dimension) {
+ gint width, height;
+ gboolean done;
+
+ done = eom_image_get_dimension_from_thumbnail (img,
+ &width,
+ &height);
+
+ if (done) {
+ priv->width = width;
+ priv->height = height;
+
+ g_free (mime_type);
+ return TRUE;
+ }
+ }
+
+ input_stream = g_file_read (priv->file, NULL, error);
+
+ if (input_stream == NULL) {
+ g_free (mime_type);
+
+ if (error != NULL) {
+ g_clear_error (error);
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_VFS,
+ "Failed to open input stream for file");
+ }
+ return FALSE;
+ }
+
+ buffer = g_new0 (guchar, EOM_IMAGE_READ_BUFFER_SIZE);
+
+ if (read_image_data || read_only_dimension) {
+ gboolean checked_threadsafety = FALSE;
+
+#ifdef HAVE_RSVG
+ if (priv->svg != NULL) {
+ g_object_unref (priv->svg);
+ priv->svg = NULL;
+ }
+
+ if (!strcmp (mime_type, "image/svg+xml")) {
+ gchar *file_path;
+ /* Keep the object for rendering */
+ priv->svg = rsvg_handle_new ();
+ file_path = g_file_get_path (priv->file);
+ rsvg_handle_set_base_uri (priv->svg, file_path);
+ g_free (file_path);
+ }
+#endif
+ loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error);
+
+ if (error && *error) {
+ g_error_free (*error);
+ *error = NULL;
+
+ loader = gdk_pixbuf_loader_new ();
+ } else {
+ /* The mimetype-based loader should know the
+ * format here already. */
+ checked_threadsafety = check_loader_threadsafety (loader, &priv->threadsafe_format);
+ }
+
+ /* This is used to detect non-threadsafe loaders and disable
+ * any possible asyncronous task that could bring deadlocks
+ * to image loading process. */
+ if (!checked_threadsafety)
+ g_signal_connect (loader,
+ "size-prepared",
+ G_CALLBACK (eom_image_pre_size_prepared),
+ img);
+
+ g_signal_connect_object (G_OBJECT (loader),
+ "size-prepared",
+ G_CALLBACK (eom_image_size_prepared),
+ img,
+ 0);
+ }
+ g_free (mime_type);
+
+ while (!priv->cancel_loading) {
+ /* FIXME: make this async */
+ bytes_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
+ buffer,
+ EOM_IMAGE_READ_BUFFER_SIZE,
+ NULL, error);
+
+ if (bytes_read == 0) {
+ /* End of the file */
+ break;
+ } else if (bytes_read == -1) {
+ failed = TRUE;
+
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_VFS,
+ "Failed to read from input stream");
+
+ break;
+ }
+
+ if ((read_image_data || read_only_dimension)) {
+ if (!gdk_pixbuf_loader_write (loader, buffer, bytes_read, error)) {
+ failed = TRUE;
+ break;
+ }
+#ifdef HAVE_RSVG
+ if (eom_image_is_svg (img) &&
+ !rsvg_handle_write (priv->svg, buffer, bytes_read, error)) {
+ failed = TRUE;
+ break;
+ }
+#endif
+ }
+
+ bytes_read_total += bytes_read;
+
+ if (job != NULL) {
+ float progress = (float) bytes_read_total / (float) priv->bytes;
+ eom_job_set_progress (job, progress);
+ }
+
+ if (first_run) {
+ md_reader = check_for_metadata_img_format (img, buffer, bytes_read);
+
+ if (md_reader == NULL) {
+ if (data2read == EOM_IMAGE_DATA_EXIF) {
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_GENERIC,
+ _("EXIF not supported for this file format."));
+ break;
+ }
+
+ if (priv->threadsafe_format)
+ eom_image_emit_size_prepared (img);
+
+ priv->metadata_status = EOM_IMAGE_METADATA_NOT_AVAILABLE;
+ }
+
+ first_run = FALSE;
+ }
+
+ if (md_reader != NULL) {
+ eom_metadata_reader_consume (md_reader, buffer, bytes_read);
+
+ if (eom_metadata_reader_finished (md_reader)) {
+ if (set_metadata) {
+ eom_image_set_exif_data (img, md_reader);
+
+#ifdef HAVE_LCMS
+ eom_image_set_icc_data (img, md_reader);
+#endif
+
+#ifdef HAVE_EXEMPI
+ eom_image_set_xmp_data (img, md_reader);
+#endif
+ set_metadata = FALSE;
+ priv->metadata_status = EOM_IMAGE_METADATA_READY;
+ }
+
+ if (data2read == EOM_IMAGE_DATA_EXIF)
+ break;
+ }
+ }
+
+ if (read_only_dimension &&
+ eom_image_has_data (img, EOM_IMAGE_DATA_DIMENSION)) {
+ break;
+ }
+ }
+
+ if (read_image_data || read_only_dimension) {
+ if (failed) {
+ gdk_pixbuf_loader_close (loader, NULL);
+ } else if (!gdk_pixbuf_loader_close (loader, error)) {
+ if (gdk_pixbuf_loader_get_pixbuf (loader) != NULL) {
+ /* Clear error in order to support partial
+ * images as well. */
+ g_clear_error (error);
+ }
+ }
+#ifdef HAVE_RSVG
+ if (eom_image_is_svg (img))
+ rsvg_handle_close (priv->svg, error);
+#endif
+ }
+
+ g_free (buffer);
+
+ g_object_unref (G_OBJECT (input_stream));
+
+ failed = (failed ||
+ priv->cancel_loading ||
+ bytes_read_total == 0 ||
+ (error && *error != NULL));
+
+ if (failed) {
+ if (priv->cancel_loading) {
+ priv->cancel_loading = FALSE;
+ priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+ } else {
+ priv->status = EOM_IMAGE_STATUS_FAILED;
+ }
+ } else if (read_image_data) {
+ if (priv->image != NULL) {
+ g_object_unref (priv->image);
+ }
+
+ priv->anim = gdk_pixbuf_loader_get_animation (loader);
+
+ if (gdk_pixbuf_animation_is_static_image (priv->anim)) {
+ priv->image = gdk_pixbuf_animation_get_static_image (priv->anim);
+ priv->anim = NULL;
+ } else {
+ priv->anim_iter = gdk_pixbuf_animation_get_iter (priv->anim,NULL);
+ priv->image = gdk_pixbuf_animation_iter_get_pixbuf (priv->anim_iter);
+ }
+
+ if (G_LIKELY (priv->image != NULL)) {
+ g_object_ref (priv->image);
+
+ priv->width = gdk_pixbuf_get_width (priv->image);
+ priv->height = gdk_pixbuf_get_height (priv->image);
+
+ format = gdk_pixbuf_loader_get_format (loader);
+
+ if (format != NULL) {
+ priv->file_type = gdk_pixbuf_format_get_name (format);
+ }
+
+ /* If it's non-threadsafe loader, then trigger window
+ * showing in the end of the process. */
+ if (!priv->threadsafe_format)
+ eom_image_emit_size_prepared (img);
+ } else {
+ /* Some loaders don't report errors correctly.
+ * Error will be set below. */
+ failed = TRUE;
+ priv->status = EOM_IMAGE_STATUS_FAILED;
+ }
+ }
+
+ if (loader != NULL) {
+ g_object_unref (loader);
+ }
+
+ if (md_reader != NULL) {
+ g_object_unref (md_reader);
+ md_reader = NULL;
+ }
+
+ /* Catch-all in case of poor-error reporting */
+ if (failed && error && *error == NULL) {
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_GENERIC,
+ _("Image loading failed."));
+ }
+
+ return !failed;
+}
+
+gboolean
+eom_image_has_data (EomImage *img, EomImageData req_data)
+{
+ EomImagePrivate *priv;
+ gboolean has_data = TRUE;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ priv = img->priv;
+
+ if ((req_data & EOM_IMAGE_DATA_IMAGE) > 0) {
+ req_data = (req_data & !EOM_IMAGE_DATA_IMAGE);
+ has_data = has_data && (priv->image != NULL);
+ }
+
+ if ((req_data & EOM_IMAGE_DATA_DIMENSION) > 0 ) {
+ req_data = (req_data & !EOM_IMAGE_DATA_DIMENSION);
+ has_data = has_data && (priv->width >= 0) && (priv->height >= 0);
+ }
+
+ if ((req_data & EOM_IMAGE_DATA_EXIF) > 0) {
+ req_data = (req_data & !EOM_IMAGE_DATA_EXIF);
+#ifdef HAVE_EXIF
+ has_data = has_data && (priv->exif != NULL);
+#else
+ has_data = has_data && (priv->exif_chunk != NULL);
+#endif
+ }
+
+ if ((req_data & EOM_IMAGE_DATA_XMP) > 0) {
+ req_data = (req_data & !EOM_IMAGE_DATA_XMP);
+#ifdef HAVE_EXEMPI
+ has_data = has_data && (priv->xmp != NULL);
+#endif
+ }
+
+ if (req_data != 0) {
+ g_warning ("Asking for unknown data, remaining: %i\n", req_data);
+ has_data = FALSE;
+ }
+
+ return has_data;
+}
+
+gboolean
+eom_image_load (EomImage *img, EomImageData data2read, EomJob *job, GError **error)
+{
+ EomImagePrivate *priv;
+ gboolean success = FALSE;
+
+ eom_debug (DEBUG_IMAGE_LOAD);
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ priv = EOM_IMAGE (img)->priv;
+
+ if (data2read == 0) {
+ return TRUE;
+ }
+
+ if (eom_image_has_data (img, data2read)) {
+ return TRUE;
+ }
+
+ priv->status = EOM_IMAGE_STATUS_LOADING;
+
+ success = eom_image_real_load (img, data2read, job, error);
+
+#ifdef HAVE_EXIF
+ /* Check that the metadata was loaded at least once before
+ * trying to autorotate. */
+ if (priv->autorotate &&
+ priv->metadata_status == EOM_IMAGE_METADATA_READY) {
+ eom_image_real_autorotate (img);
+ }
+#endif
+
+ if (success && eom_image_needs_transformation (img)) {
+ success = eom_image_apply_transformations (img, error);
+ }
+
+ if (success) {
+ priv->status = EOM_IMAGE_STATUS_LOADED;
+ } else {
+ priv->status = EOM_IMAGE_STATUS_FAILED;
+ }
+
+ return success;
+}
+
+void
+eom_image_set_thumbnail (EomImage *img, GdkPixbuf *thumbnail)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+ g_return_if_fail (GDK_IS_PIXBUF (thumbnail) || thumbnail == NULL);
+
+ priv = img->priv;
+
+ if (priv->thumbnail != NULL) {
+ g_object_unref (priv->thumbnail);
+ priv->thumbnail = NULL;
+ }
+
+ if (thumbnail != NULL && priv->trans != NULL) {
+ priv->thumbnail = eom_transform_apply (priv->trans, thumbnail, NULL);
+ } else {
+ priv->thumbnail = thumbnail;
+
+ if (thumbnail != NULL) {
+ g_object_ref (priv->thumbnail);
+ }
+ }
+
+ if (priv->thumbnail != NULL) {
+ g_signal_emit (img, signals[SIGNAL_THUMBNAIL_CHANGED], 0);
+ }
+}
+
+GdkPixbuf *
+eom_image_get_pixbuf (EomImage *img)
+{
+ GdkPixbuf *image = NULL;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ g_mutex_lock (img->priv->status_mutex);
+ image = img->priv->image;
+ g_mutex_unlock (img->priv->status_mutex);
+
+ if (image != NULL) {
+ g_object_ref (image);
+ }
+
+ return image;
+}
+
+#ifdef HAVE_LCMS
+cmsHPROFILE
+eom_image_get_profile (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ return img->priv->profile;
+}
+#endif
+
+GdkPixbuf *
+eom_image_get_thumbnail (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ if (img->priv->thumbnail != NULL) {
+ g_object_ref (img->priv->thumbnail);
+
+ return img->priv->thumbnail;
+ }
+
+ return NULL;
+}
+
+void
+eom_image_get_size (EomImage *img, int *width, int *height)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ *width = priv->width;
+ *height = priv->height;
+}
+
+void
+eom_image_transform (EomImage *img, EomTransform *trans, EomJob *job)
+{
+ eom_image_real_transform (img, trans, FALSE, job);
+}
+
+void
+eom_image_undo (EomImage *img)
+{
+ EomImagePrivate *priv;
+ EomTransform *trans;
+ EomTransform *inverse;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ if (priv->undo_stack != NULL) {
+ trans = EOM_TRANSFORM (priv->undo_stack->data);
+
+ inverse = eom_transform_reverse (trans);
+
+ eom_image_real_transform (img, inverse, TRUE, NULL);
+
+ priv->undo_stack = g_slist_delete_link (priv->undo_stack, priv->undo_stack);
+
+ g_object_unref (trans);
+ g_object_unref (inverse);
+
+ if (eom_transform_is_identity (priv->trans)) {
+ g_object_unref (priv->trans);
+ priv->trans = NULL;
+ }
+ }
+
+ priv->modified = (priv->undo_stack != NULL);
+}
+
+static GFile *
+tmp_file_get (void)
+{
+ GFile *tmp_file;
+ char *tmp_file_path;
+ gint fd;
+
+ tmp_file_path = g_build_filename (g_get_tmp_dir (), "eom-save-XXXXXX", NULL);
+ fd = g_mkstemp (tmp_file_path);
+ if (fd == -1) {
+ g_free (tmp_file_path);
+ return NULL;
+ }
+ else {
+ tmp_file = g_file_new_for_path (tmp_file_path);
+ g_free (tmp_file_path);
+ return tmp_file;
+ }
+}
+
+static void
+transfer_progress_cb (goffset cur_bytes,
+ goffset total_bytes,
+ gpointer user_data)
+{
+ EomImage *image = EOM_IMAGE (user_data);
+
+ if (cur_bytes > 0) {
+ g_signal_emit (G_OBJECT(image),
+ signals[SIGNAL_SAVE_PROGRESS],
+ 0,
+ (gfloat) cur_bytes / (gfloat) total_bytes);
+ }
+}
+
+static gboolean
+tmp_file_move_to_uri (EomImage *image,
+ GFile *tmpfile,
+ GFile *file,
+ gboolean overwrite,
+ GError **error)
+{
+ gboolean result;
+ GError *ioerror = NULL;
+
+ result = g_file_move (tmpfile,
+ file,
+ (overwrite ? G_FILE_COPY_OVERWRITE : 0) |
+ G_FILE_COPY_ALL_METADATA,
+ NULL,
+ (GFileProgressCallback) transfer_progress_cb,
+ image,
+ &ioerror);
+
+ if (result == FALSE) {
+ if (g_error_matches (ioerror, G_IO_ERROR,
+ G_IO_ERROR_EXISTS)) {
+ g_set_error (error, EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_FILE_EXISTS,
+ "File exists");
+ } else {
+ g_set_error (error, EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_VFS,
+ "VFS error moving the temp file");
+ }
+ g_clear_error (&ioerror);
+ }
+
+ return result;
+}
+
+static gboolean
+tmp_file_delete (GFile *tmpfile)
+{
+ gboolean result;
+ GError *err = NULL;
+
+ if (tmpfile == NULL) return FALSE;
+
+ result = g_file_delete (tmpfile, NULL, &err);
+ if (result == FALSE) {
+ char *tmpfile_path;
+ if (err != NULL) {
+ if (err->code == G_IO_ERROR_NOT_FOUND) {
+ g_error_free (err);
+ return TRUE;
+ }
+ g_error_free (err);
+ }
+ tmpfile_path = g_file_get_path (tmpfile);
+ g_warning ("Couldn't delete temporary file: %s", tmpfile_path);
+ g_free (tmpfile_path);
+ }
+
+ return result;
+}
+
+static void
+eom_image_reset_modifications (EomImage *image)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (image));
+
+ priv = image->priv;
+
+ g_slist_foreach (priv->undo_stack, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->undo_stack);
+ priv->undo_stack = NULL;
+
+ if (priv->trans != NULL) {
+ g_object_unref (priv->trans);
+ priv->trans = NULL;
+ }
+
+ if (priv->trans_autorotate != NULL) {
+ g_object_unref (priv->trans_autorotate);
+ priv->trans_autorotate = NULL;
+ }
+
+ priv->modified = FALSE;
+}
+
+static void
+eom_image_link_with_target (EomImage *image, EomImageSaveInfo *target)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (image));
+ g_return_if_fail (EOM_IS_IMAGE_SAVE_INFO (target));
+
+ priv = image->priv;
+
+ /* update file location */
+ if (priv->file != NULL) {
+ g_object_unref (priv->file);
+ }
+ priv->file = g_object_ref (target->file);
+
+ /* Clear caption and caption key, these will be
+ * updated on next eom_image_get_caption call.
+ */
+ if (priv->caption != NULL) {
+ g_free (priv->caption);
+ priv->caption = NULL;
+ }
+ if (priv->collate_key != NULL) {
+ g_free (priv->collate_key);
+ priv->collate_key = NULL;
+ }
+
+ /* update file format */
+ if (priv->file_type != NULL) {
+ g_free (priv->file_type);
+ }
+ priv->file_type = g_strdup (target->format);
+}
+
+gboolean
+eom_image_save_by_info (EomImage *img, EomImageSaveInfo *source, GError **error)
+{
+ EomImagePrivate *priv;
+ EomImageStatus prev_status;
+ gboolean success = FALSE;
+ GFile *tmp_file;
+ char *tmp_file_path;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+ g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (source), FALSE);
+
+ priv = img->priv;
+
+ prev_status = priv->status;
+
+ /* Image is now being saved */
+ priv->status = EOM_IMAGE_STATUS_SAVING;
+
+ /* see if we need any saving at all */
+ if (source->exists && !source->modified) {
+ return TRUE;
+ }
+
+ /* fail if there is no image to save */
+ if (priv->image == NULL) {
+ g_set_error (error, EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_NOT_LOADED,
+ _("No image loaded."));
+ return FALSE;
+ }
+
+ /* generate temporary file */
+ tmp_file = tmp_file_get ();
+
+ if (tmp_file == NULL) {
+ g_set_error (error, EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_TMP_FILE_FAILED,
+ _("Temporary file creation failed."));
+ return FALSE;
+ }
+
+ tmp_file_path = g_file_get_path (tmp_file);
+
+#ifdef HAVE_JPEG
+ /* determine kind of saving */
+ if ((g_ascii_strcasecmp (source->format, EOM_FILE_FORMAT_JPEG) == 0) &&
+ source->exists && source->modified)
+ {
+ success = eom_image_jpeg_save_file (img, tmp_file_path, source, NULL, error);
+ }
+#endif
+
+ if (!success && (*error == NULL)) {
+ success = gdk_pixbuf_save (priv->image, tmp_file_path, source->format, error, NULL);
+ }
+
+ if (success) {
+ /* try to move result file to target uri */
+ success = tmp_file_move_to_uri (img, tmp_file, priv->file, TRUE /*overwrite*/, error);
+ }
+
+ if (success) {
+ eom_image_reset_modifications (img);
+ }
+
+ tmp_file_delete (tmp_file);
+
+ g_free (tmp_file_path);
+ g_object_unref (tmp_file);
+
+ priv->status = prev_status;
+
+ return success;
+}
+
+static gboolean
+eom_image_copy_file (EomImage *image, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error)
+{
+ gboolean result;
+ GError *ioerror = NULL;
+
+ g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (source), FALSE);
+ g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (target), FALSE);
+
+ result = g_file_copy (source->file,
+ target->file,
+ (target->overwrite ? G_FILE_COPY_OVERWRITE : 0) |
+ G_FILE_COPY_ALL_METADATA,
+ NULL,
+ EOM_IS_IMAGE (image) ? transfer_progress_cb :NULL,
+ image,
+ &ioerror);
+
+ if (result == FALSE) {
+ if (ioerror->code == G_IO_ERROR_EXISTS) {
+ g_set_error (error, EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_FILE_EXISTS,
+ "%s", ioerror->message);
+ } else {
+ g_set_error (error, EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_VFS,
+ "%s", ioerror->message);
+ }
+ g_error_free (ioerror);
+ }
+
+ return result;
+}
+
+gboolean
+eom_image_save_as_by_info (EomImage *img, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error)
+{
+ EomImagePrivate *priv;
+ gboolean success = FALSE;
+ char *tmp_file_path;
+ GFile *tmp_file;
+ gboolean direct_copy = FALSE;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+ g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (source), FALSE);
+ g_return_val_if_fail (EOM_IS_IMAGE_SAVE_INFO (target), FALSE);
+
+ priv = img->priv;
+
+ /* fail if there is no image to save */
+ if (priv->image == NULL) {
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_NOT_LOADED,
+ _("No image loaded."));
+
+ return FALSE;
+ }
+
+ /* generate temporary file name */
+ tmp_file = tmp_file_get ();
+
+ if (tmp_file == NULL) {
+ g_set_error (error,
+ EOM_IMAGE_ERROR,
+ EOM_IMAGE_ERROR_TMP_FILE_FAILED,
+ _("Temporary file creation failed."));
+
+ return FALSE;
+ }
+ tmp_file_path = g_file_get_path (tmp_file);
+
+ /* determine kind of saving */
+ if (g_ascii_strcasecmp (source->format, target->format) == 0 && !source->modified) {
+ success = eom_image_copy_file (img, source, target, error);
+ direct_copy = success;
+ }
+
+#ifdef HAVE_JPEG
+ else if ((g_ascii_strcasecmp (source->format, EOM_FILE_FORMAT_JPEG) == 0 && source->exists) ||
+ (g_ascii_strcasecmp (target->format, EOM_FILE_FORMAT_JPEG) == 0))
+ {
+ success = eom_image_jpeg_save_file (img, tmp_file_path, source, target, error);
+ }
+#endif
+
+ if (!success && (*error == NULL)) {
+ success = gdk_pixbuf_save (priv->image, tmp_file_path, target->format, error, NULL);
+ }
+
+ if (success && !direct_copy) { /* not required if we alredy copied the file directly */
+ /* try to move result file to target uri */
+ success = tmp_file_move_to_uri (img, tmp_file, target->file, target->overwrite, error);
+ }
+
+ if (success) {
+ /* update image information to new uri */
+ eom_image_reset_modifications (img);
+ eom_image_link_with_target (img, target);
+ }
+
+ tmp_file_delete (tmp_file);
+ g_object_unref (tmp_file);
+ g_free (tmp_file_path);
+
+ priv->status = EOM_IMAGE_STATUS_UNKNOWN;
+
+ return success;
+}
+
+
+/*
+ * This function is extracted from
+ * File: caja/libcaja-private/caja-file.c
+ * Revision: 1.309
+ * Author: Darin Adler <[email protected]>
+ */
+static gboolean
+have_broken_filenames (void)
+{
+ static gboolean initialized = FALSE;
+ static gboolean broken;
+
+ if (initialized) {
+ return broken;
+ }
+
+ broken = g_getenv ("G_BROKEN_FILENAMES") != NULL;
+
+ initialized = TRUE;
+
+ return broken;
+}
+
+/*
+ * This function is inspired by
+ * caja/libcaja-private/caja-file.c:caja_file_get_display_name_nocopy
+ * Revision: 1.309
+ * Author: Darin Adler <[email protected]>
+ */
+const gchar*
+eom_image_get_caption (EomImage *img)
+{
+ EomImagePrivate *priv;
+ char *name;
+ char *utf8_name;
+ char *scheme;
+ gboolean validated = FALSE;
+ gboolean broken_filenames;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ priv = img->priv;
+
+ if (priv->file == NULL) return NULL;
+
+ if (priv->caption != NULL)
+ /* Use cached caption string */
+ return priv->caption;
+
+ name = g_file_get_basename (priv->file);
+ scheme = g_file_get_uri_scheme (priv->file);
+
+ if (name != NULL && g_ascii_strcasecmp (scheme, "file") == 0) {
+ /* Support the G_BROKEN_FILENAMES feature of
+ * glib by using g_filename_to_utf8 to convert
+ * local filenames to UTF-8. Also do the same
+ * thing with any local filename that does not
+ * validate as good UTF-8.
+ */
+ broken_filenames = have_broken_filenames ();
+
+ if (broken_filenames || !g_utf8_validate (name, -1, NULL)) {
+ utf8_name = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
+ if (utf8_name != NULL) {
+ g_free (name);
+ name = utf8_name;
+ /* Guaranteed to be correct utf8 here */
+ validated = TRUE;
+ }
+ } else if (!broken_filenames) {
+ /* name was valid, no need to re-validate */
+ validated = TRUE;
+ }
+ }
+
+ if (!validated && !g_utf8_validate (name, -1, NULL)) {
+ if (name == NULL) {
+ name = g_strdup ("[Invalid Unicode]");
+ } else {
+ utf8_name = eom_util_make_valid_utf8 (name);
+ g_free (name);
+ name = utf8_name;
+ }
+ }
+
+ priv->caption = name;
+
+ if (priv->caption == NULL) {
+ char *short_str;
+
+ short_str = g_file_get_basename (priv->file);
+ if (g_utf8_validate (short_str, -1, NULL)) {
+ priv->caption = g_strdup (short_str);
+ } else {
+ priv->caption = g_filename_to_utf8 (short_str, -1, NULL, NULL, NULL);
+ }
+ g_free (short_str);
+ }
+ g_free (scheme);
+
+ return priv->caption;
+}
+
+const gchar*
+eom_image_get_collate_key (EomImage *img)
+{
+ EomImagePrivate *priv;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ priv = img->priv;
+
+ if (priv->collate_key == NULL) {
+ const char *caption;
+
+ caption = eom_image_get_caption (img);
+
+ priv->collate_key = g_utf8_collate_key_for_filename (caption, -1);
+ }
+
+ return priv->collate_key;
+}
+
+void
+eom_image_cancel_load (EomImage *img)
+{
+ EomImagePrivate *priv;
+
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ g_mutex_lock (priv->status_mutex);
+
+ if (priv->status == EOM_IMAGE_STATUS_LOADING) {
+ priv->cancel_loading = TRUE;
+ }
+
+ g_mutex_unlock (priv->status_mutex);
+}
+
+gpointer
+eom_image_get_exif_info (EomImage *img)
+{
+ EomImagePrivate *priv;
+ gpointer data = NULL;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ priv = img->priv;
+
+#ifdef HAVE_EXIF
+ g_mutex_lock (priv->status_mutex);
+
+ exif_data_ref (priv->exif);
+ data = priv->exif;
+
+ g_mutex_unlock (priv->status_mutex);
+#endif
+
+ return data;
+}
+
+
+gpointer
+eom_image_get_xmp_info (EomImage *img)
+{
+ EomImagePrivate *priv;
+ gpointer data = NULL;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ priv = img->priv;
+
+#ifdef HAVE_EXEMPI
+ g_mutex_lock (priv->status_mutex);
+ data = (gpointer) xmp_copy (priv->xmp);
+ g_mutex_unlock (priv->status_mutex);
+#endif
+
+ return data;
+}
+
+
+GFile *
+eom_image_get_file (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ return g_object_ref (img->priv->file);
+}
+
+gboolean
+eom_image_is_modified (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ return img->priv->modified;
+}
+
+goffset
+eom_image_get_bytes (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), 0);
+
+ return img->priv->bytes;
+}
+
+void
+eom_image_modified (EomImage *img)
+{
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ g_signal_emit (G_OBJECT (img), signals[SIGNAL_CHANGED], 0);
+}
+
+gchar*
+eom_image_get_uri_for_display (EomImage *img)
+{
+ EomImagePrivate *priv;
+ gchar *uri_str = NULL;
+ gchar *str = NULL;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ priv = img->priv;
+
+ if (priv->file != NULL) {
+ uri_str = g_file_get_uri (priv->file);
+
+ if (uri_str != NULL) {
+ str = g_uri_unescape_string (uri_str, NULL);
+ g_free (uri_str);
+ }
+ }
+
+ return str;
+}
+
+EomImageStatus
+eom_image_get_status (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), EOM_IMAGE_STATUS_UNKNOWN);
+
+ return img->priv->status;
+}
+
+/**
+ * eom_image_get_metadata_status:
+ * @img: a #EomImage
+ *
+ * Returns the current status of the image metadata, that is,
+ * whether the metadata has not been read yet, is ready, or not available at all.
+ *
+ * Returns: one of #EomImageMetadataStatus
+ **/
+EomImageMetadataStatus
+eom_image_get_metadata_status (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), EOM_IMAGE_METADATA_NOT_AVAILABLE);
+
+ return img->priv->metadata_status;
+}
+
+void
+eom_image_data_ref (EomImage *img)
+{
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ g_object_ref (G_OBJECT (img));
+ img->priv->data_ref_count++;
+
+ g_assert (img->priv->data_ref_count <= G_OBJECT (img)->ref_count);
+}
+
+void
+eom_image_data_unref (EomImage *img)
+{
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ if (img->priv->data_ref_count > 0) {
+ img->priv->data_ref_count--;
+ } else {
+ g_warning ("More image data unrefs than refs.");
+ }
+
+ if (img->priv->data_ref_count == 0) {
+ eom_image_free_mem_private (img);
+ }
+
+ g_object_unref (G_OBJECT (img));
+
+ g_assert (img->priv->data_ref_count <= G_OBJECT (img)->ref_count);
+}
+
+static gint
+compare_quarks (gconstpointer a, gconstpointer b)
+{
+ GQuark quark;
+
+ quark = g_quark_from_string ((const gchar *) a);
+
+ return quark - GPOINTER_TO_INT (b);
+}
+
+GList *
+eom_image_get_supported_mime_types (void)
+{
+ GSList *format_list, *it;
+ gchar **mime_types;
+ int i;
+
+ if (!supported_mime_types) {
+ format_list = gdk_pixbuf_get_formats ();
+
+ for (it = format_list; it != NULL; it = it->next) {
+ mime_types =
+ gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) it->data);
+
+ for (i = 0; mime_types[i] != NULL; i++) {
+ supported_mime_types =
+ g_list_prepend (supported_mime_types,
+ g_strdup (mime_types[i]));
+ }
+
+ g_strfreev (mime_types);
+ }
+
+ supported_mime_types = g_list_sort (supported_mime_types,
+ (GCompareFunc) compare_quarks);
+
+ g_slist_free (format_list);
+ }
+
+ return supported_mime_types;
+}
+
+gboolean
+eom_image_is_supported_mime_type (const char *mime_type)
+{
+ GList *supported_mime_types, *result;
+ GQuark quark;
+
+ if (mime_type == NULL) {
+ return FALSE;
+ }
+
+ supported_mime_types = eom_image_get_supported_mime_types ();
+
+ quark = g_quark_from_string (mime_type);
+
+ result = g_list_find_custom (supported_mime_types,
+ GINT_TO_POINTER (quark),
+ (GCompareFunc) compare_quarks);
+
+ return (result != NULL);
+}
+
+static gboolean
+eom_image_iter_advance (EomImage *img)
+{
+ EomImagePrivate *priv;
+ gboolean new_frame;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (img->priv->anim_iter), FALSE);
+
+ priv = img->priv;
+
+ if ((new_frame = gdk_pixbuf_animation_iter_advance (img->priv->anim_iter, NULL)) == TRUE)
+ {
+ g_mutex_lock (priv->status_mutex);
+ g_object_unref (priv->image);
+ priv->image = gdk_pixbuf_animation_iter_get_pixbuf (priv->anim_iter);
+ g_object_ref (priv->image);
+ /* keep the transformation over time */
+ if (EOM_IS_TRANSFORM (priv->trans)) {
+ GdkPixbuf* transformed = eom_transform_apply (priv->trans, priv->image, NULL);
+ g_object_unref (priv->image);
+ priv->image = transformed;
+ priv->width = gdk_pixbuf_get_width (transformed);
+ priv->height = gdk_pixbuf_get_height (transformed);
+ }
+ g_mutex_unlock (priv->status_mutex);
+ /* Emit next frame signal so we can update the display */
+ g_signal_emit (img, signals[SIGNAL_NEXT_FRAME], 0,
+ gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter));
+ }
+
+ return new_frame;
+}
+
+/**
+ * eom_image_is_animation:
+ * @img: a #EomImage
+ *
+ * Checks whether a given image is animated.
+ *
+ * Returns: #TRUE if it is an animated image, #FALSE otherwise.
+ *
+ **/
+gboolean
+eom_image_is_animation (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+ return img->priv->anim != NULL;
+}
+
+static gboolean
+private_timeout (gpointer data)
+{
+ EomImage *img = EOM_IMAGE (data);
+ EomImagePrivate *priv = img->priv;
+
+ if (eom_image_is_animation (img) &&
+ !g_source_is_destroyed (g_main_current_source ()) &&
+ priv->is_playing) {
+ while (eom_image_iter_advance (img) != TRUE) {}; /* cpu-sucking ? */
+ g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter), private_timeout, img);
+ return FALSE;
+ }
+ priv->is_playing = FALSE;
+ return FALSE; /* stop playing */
+}
+
+/**
+ * eom_image_start_animation:
+ * @img: a #EomImage
+ *
+ * Starts playing an animated image.
+ *
+ * Returns: %TRUE on success, %FALSE if @img is already playing or isn't an animated image.
+ **/
+gboolean
+eom_image_start_animation (EomImage *img)
+{
+ EomImagePrivate *priv;
+
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+ priv = img->priv;
+
+ if (!eom_image_is_animation (img) || priv->is_playing)
+ return FALSE;
+
+ g_mutex_lock (priv->status_mutex);
+ g_object_ref (priv->anim_iter);
+ priv->is_playing = TRUE;
+ g_mutex_unlock (priv->status_mutex);
+
+ g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter), private_timeout, img);
+
+ return TRUE;
+}
+
+#ifdef HAVE_RSVG
+gboolean
+eom_image_is_svg (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ return (img->priv->svg != NULL);
+}
+
+RsvgHandle *
+eom_image_get_svg (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ return img->priv->svg;
+}
+
+EomTransform *
+eom_image_get_transform (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ return img->priv->trans;
+}
+
+#endif
+
+/**
+ * eom_image_file_changed:
+ * @img: a #EomImage
+ *
+ * Emits EomImage::file-changed signal
+ **/
+void
+eom_image_file_changed (EomImage *img)
+{
+ g_return_if_fail (EOM_IS_IMAGE (img));
+
+ g_signal_emit (img, signals[SIGNAL_FILE_CHANGED], 0);
+}
diff --git a/src/eom-image.h b/src/eom-image.h
new file mode 100644
index 0000000..791eb8a
--- /dev/null
+++ b/src/eom-image.h
@@ -0,0 +1,218 @@
+/* Eye Of Mate - Image
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_IMAGE_H__
+#define __EOM_IMAGE_H__
+
+#include "eom-jobs.h"
+#include "eom-window.h"
+#include "eom-transform.h"
+#include "eom-image-save-info.h"
+#include "eom-enums.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifdef HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+
+#ifdef HAVE_LCMS
+#include <lcms.h>
+#endif
+
+#ifdef HAVE_EXEMPI
+#include <exempi/xmp.h>
+#endif
+
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#endif
+
+G_BEGIN_DECLS
+
+#ifndef __EOM_IMAGE_DECLR__
+#define __EOM_IMAGE_DECLR__
+typedef struct _EomImage EomImage;
+#endif
+typedef struct _EomImageClass EomImageClass;
+typedef struct _EomImagePrivate EomImagePrivate;
+
+#define EOM_TYPE_IMAGE (eom_image_get_type ())
+#define EOM_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_IMAGE, EomImage))
+#define EOM_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_IMAGE, EomImageClass))
+#define EOM_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_IMAGE))
+#define EOM_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EOM_TYPE_IMAGE))
+#define EOM_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EOM_TYPE_IMAGE, EomImageClass))
+
+typedef enum {
+ EOM_IMAGE_ERROR_SAVE_NOT_LOCAL,
+ EOM_IMAGE_ERROR_NOT_LOADED,
+ EOM_IMAGE_ERROR_VFS,
+ EOM_IMAGE_ERROR_FILE_EXISTS,
+ EOM_IMAGE_ERROR_TMP_FILE_FAILED,
+ EOM_IMAGE_ERROR_GENERIC,
+ EOM_IMAGE_ERROR_UNKNOWN
+} EomImageError;
+
+#define EOM_IMAGE_ERROR eom_image_error_quark ()
+
+typedef enum {
+ EOM_IMAGE_STATUS_UNKNOWN,
+ EOM_IMAGE_STATUS_LOADING,
+ EOM_IMAGE_STATUS_LOADED,
+ EOM_IMAGE_STATUS_SAVING,
+ EOM_IMAGE_STATUS_FAILED
+} EomImageStatus;
+
+typedef enum {
+ EOM_IMAGE_METADATA_NOT_READ,
+ EOM_IMAGE_METADATA_NOT_AVAILABLE,
+ EOM_IMAGE_METADATA_READY
+} EomImageMetadataStatus;
+
+struct _EomImage {
+ GObject parent;
+
+ EomImagePrivate *priv;
+};
+
+struct _EomImageClass {
+ GObjectClass parent_class;
+
+ void (* changed) (EomImage *img);
+
+ void (* size_prepared) (EomImage *img,
+ int width,
+ int height);
+
+ void (* thumbnail_changed) (EomImage *img);
+
+ void (* save_progress) (EomImage *img,
+ gfloat progress);
+
+ void (* next_frame) (EomImage *img,
+ gint delay);
+
+ void (* file_changed) (EomImage *img);
+};
+
+GType eom_image_get_type (void) G_GNUC_CONST;
+
+GQuark eom_image_error_quark (void);
+
+EomImage *eom_image_new (const char *txt_uri);
+
+EomImage *eom_image_new_file (GFile *file);
+
+gboolean eom_image_load (EomImage *img,
+ EomImageData data2read,
+ EomJob *job,
+ GError **error);
+
+void eom_image_cancel_load (EomImage *img);
+
+gboolean eom_image_has_data (EomImage *img,
+ EomImageData data);
+
+void eom_image_data_ref (EomImage *img);
+
+void eom_image_data_unref (EomImage *img);
+
+void eom_image_set_thumbnail (EomImage *img,
+ GdkPixbuf *pixbuf);
+
+gboolean eom_image_save_as_by_info (EomImage *img,
+ EomImageSaveInfo *source,
+ EomImageSaveInfo *target,
+ GError **error);
+
+gboolean eom_image_save_by_info (EomImage *img,
+ EomImageSaveInfo *source,
+ GError **error);
+
+GdkPixbuf* eom_image_get_pixbuf (EomImage *img);
+
+GdkPixbuf* eom_image_get_thumbnail (EomImage *img);
+
+void eom_image_get_size (EomImage *img,
+ gint *width,
+ gint *height);
+
+goffset eom_image_get_bytes (EomImage *img);
+
+gboolean eom_image_is_modified (EomImage *img);
+
+void eom_image_modified (EomImage *img);
+
+const gchar* eom_image_get_caption (EomImage *img);
+
+const gchar *eom_image_get_collate_key (EomImage *img);
+
+gpointer eom_image_get_exif_info (EomImage *img);
+
+gpointer eom_image_get_xmp_info (EomImage *img);
+
+GFile* eom_image_get_file (EomImage *img);
+
+gchar* eom_image_get_uri_for_display (EomImage *img);
+
+EomImageStatus eom_image_get_status (EomImage *img);
+
+EomImageMetadataStatus eom_image_get_metadata_status (EomImage *img);
+
+void eom_image_transform (EomImage *img,
+ EomTransform *trans,
+ EomJob *job);
+
+#ifdef HAVE_EXIF
+void eom_image_autorotate (EomImage *img);
+#endif
+
+#ifdef HAVE_LCMS
+cmsHPROFILE eom_image_get_profile (EomImage *img);
+
+void eom_image_apply_display_profile (EomImage *img,
+ cmsHPROFILE display_profile);
+#endif
+
+void eom_image_undo (EomImage *img);
+
+GList *eom_image_get_supported_mime_types (void);
+
+gboolean eom_image_is_supported_mime_type (const char *mime_type);
+
+gboolean eom_image_is_animation (EomImage *img);
+
+gboolean eom_image_start_animation (EomImage *img);
+
+#ifdef HAVE_RSVG
+gboolean eom_image_is_svg (EomImage *img);
+RsvgHandle *eom_image_get_svg (EomImage *img);
+EomTransform *eom_image_get_transform (EomImage *img);
+#endif
+
+void eom_image_file_changed (EomImage *img);
+
+G_END_DECLS
+
+#endif /* __EOM_IMAGE_H__ */
diff --git a/src/eom-job-queue.c b/src/eom-job-queue.c
new file mode 100644
index 0000000..93ed903
--- /dev/null
+++ b/src/eom-job-queue.c
@@ -0,0 +1,238 @@
+/* Eye Of Mate - Jobs Queue
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on evince code (shell/ev-job-queue.c) by:
+ * - Martin Kretzschmar <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "eom-jobs.h"
+#include "eom-job-queue.h"
+
+static GCond *render_cond = NULL;
+static GMutex *eom_queue_mutex = NULL;
+
+static GQueue *thumbnail_queue = NULL;
+static GQueue *load_queue = NULL;
+static GQueue *model_queue = NULL;
+static GQueue *transform_queue = NULL;
+static GQueue *save_queue = NULL;
+static GQueue *copy_queue = NULL;
+
+static gboolean
+remove_job_from_queue (GQueue *queue, EomJob *job)
+{
+ GList *list;
+
+ list = g_queue_find (queue, job);
+
+ if (list) {
+ g_object_unref (G_OBJECT (job));
+ g_queue_delete_link (queue, list);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+add_job_to_queue_locked (GQueue *queue, EomJob *job)
+{
+ g_object_ref (job);
+ g_queue_push_tail (queue, job);
+ g_cond_broadcast (render_cond);
+}
+
+static gboolean
+notify_finished (GObject *job)
+{
+ eom_job_finished (EOM_JOB (job));
+
+ return FALSE;
+}
+
+static void
+handle_job (EomJob *job)
+{
+ g_object_ref (G_OBJECT (job));
+
+ // Do the EOM_JOB cast for safety
+ eom_job_run (EOM_JOB (job));
+
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) notify_finished,
+ job,
+ g_object_unref);
+}
+
+static gboolean
+no_jobs_available_unlocked (void)
+{
+ return g_queue_is_empty (load_queue) &&
+ g_queue_is_empty (transform_queue) &&
+ g_queue_is_empty (thumbnail_queue) &&
+ g_queue_is_empty (model_queue) &&
+ g_queue_is_empty (save_queue) &&
+ g_queue_is_empty (copy_queue);
+}
+
+static EomJob *
+search_for_jobs_unlocked (void)
+{
+ EomJob *job;
+
+ job = (EomJob *) g_queue_pop_head (load_queue);
+ if (job)
+ return job;
+
+ job = (EomJob *) g_queue_pop_head (transform_queue);
+ if (job)
+ return job;
+
+ job = (EomJob *) g_queue_pop_head (thumbnail_queue);
+ if (job)
+ return job;
+
+ job = (EomJob *) g_queue_pop_head (model_queue);
+ if (job)
+ return job;
+
+ job = (EomJob *) g_queue_pop_head (save_queue);
+ if (job)
+ return job;
+
+ job = (EomJob *) g_queue_pop_head (copy_queue);
+ if (job)
+ return job;
+
+ return NULL;
+}
+
+static gpointer
+eom_render_thread (gpointer data)
+{
+ while (TRUE) {
+ EomJob *job;
+
+ g_mutex_lock (eom_queue_mutex);
+
+ if (no_jobs_available_unlocked ()) {
+ g_cond_wait (render_cond, eom_queue_mutex);
+ }
+
+ job = search_for_jobs_unlocked ();
+
+ g_mutex_unlock (eom_queue_mutex);
+
+ /* Now that we have our job, we handle it */
+ if (job) {
+ handle_job (job);
+ g_object_unref (G_OBJECT (job));
+ }
+ }
+ return NULL;
+
+}
+
+void
+eom_job_queue_init (void)
+{
+ if (!g_thread_supported ()) g_thread_init (NULL);
+
+ render_cond = g_cond_new ();
+ eom_queue_mutex = g_mutex_new ();
+
+ thumbnail_queue = g_queue_new ();
+ load_queue = g_queue_new ();
+ model_queue = g_queue_new ();
+ transform_queue = g_queue_new ();
+ save_queue = g_queue_new ();
+ copy_queue = g_queue_new ();
+
+ g_thread_create (eom_render_thread, NULL, FALSE, NULL);
+}
+
+static GQueue *
+find_queue (EomJob *job)
+{
+ if (EOM_IS_JOB_THUMBNAIL (job)) {
+ return thumbnail_queue;
+ } else if (EOM_IS_JOB_LOAD (job)) {
+ return load_queue;
+ } else if (EOM_IS_JOB_MODEL (job)) {
+ return model_queue;
+ } else if (EOM_IS_JOB_TRANSFORM (job)) {
+ return transform_queue;
+ } else if (EOM_IS_JOB_SAVE (job)) {
+ return save_queue;
+ } else if (EOM_IS_JOB_COPY (job)) {
+ return copy_queue;
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+void
+eom_job_queue_add_job (EomJob *job)
+{
+ GQueue *queue;
+
+ g_return_if_fail (EOM_IS_JOB (job));
+
+ queue = find_queue (job);
+
+ g_mutex_lock (eom_queue_mutex);
+
+ add_job_to_queue_locked (queue, job);
+
+ g_mutex_unlock (eom_queue_mutex);
+}
+
+gboolean
+eom_job_queue_remove_job (EomJob *job)
+{
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (EOM_IS_JOB (job), FALSE);
+
+ g_mutex_lock (eom_queue_mutex);
+
+ if (EOM_IS_JOB_THUMBNAIL (job)) {
+ retval = remove_job_from_queue (thumbnail_queue, job);
+ } else if (EOM_IS_JOB_LOAD (job)) {
+ retval = remove_job_from_queue (load_queue, job);
+ } else if (EOM_IS_JOB_MODEL (job)) {
+ retval = remove_job_from_queue (model_queue, job);
+ } else if (EOM_IS_JOB_TRANSFORM (job)) {
+ retval = remove_job_from_queue (transform_queue, job);
+ } else if (EOM_IS_JOB_SAVE (job)) {
+ retval = remove_job_from_queue (save_queue, job);
+ } else if (EOM_IS_JOB_COPY (job)) {
+ retval = remove_job_from_queue (copy_queue, job);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ g_mutex_unlock (eom_queue_mutex);
+
+ return retval;
+}
diff --git a/src/eom-job-queue.h b/src/eom-job-queue.h
new file mode 100644
index 0000000..6a71e7b
--- /dev/null
+++ b/src/eom-job-queue.h
@@ -0,0 +1,42 @@
+/* Eye Of Mate - Jobs Queue
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on evince code (shell/ev-job-queue.h) by:
+ * - Martin Kretzschmar <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_JOB_QUEUE_H__
+#define __EOM_JOB_QUEUE_H__
+
+#include "eom-jobs.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void eom_job_queue_init (void);
+
+void eom_job_queue_add_job (EomJob *job);
+
+gboolean eom_job_queue_remove_job (EomJob *job);
+
+G_END_DECLS
+
+#endif /* __EOM_JOB_QUEUE_H__ */
diff --git a/src/eom-jobs.c b/src/eom-jobs.c
new file mode 100644
index 0000000..c3bac3a
--- /dev/null
+++ b/src/eom-jobs.c
@@ -0,0 +1,885 @@
+/* Eye Of Mate - Jobs
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on evince code (shell/ev-jobs.c) by:
+ * - Martin Kretzschmar <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "eom-uri-converter.h"
+#include "eom-jobs.h"
+#include "eom-job-queue.h"
+#include "eom-image.h"
+#include "eom-transform.h"
+#include "eom-list-store.h"
+#include "eom-thumbnail.h"
+#include "eom-pixbuf-util.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define EOM_JOB_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_JOB, EomJobPrivate))
+
+G_DEFINE_TYPE (EomJob, eom_job, G_TYPE_OBJECT);
+G_DEFINE_TYPE (EomJobThumbnail, eom_job_thumbnail, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobLoad, eom_job_load, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobModel, eom_job_model, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobTransform, eom_job_transform, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobSave, eom_job_save, EOM_TYPE_JOB);
+G_DEFINE_TYPE (EomJobSaveAs, eom_job_save_as, EOM_TYPE_JOB_SAVE);
+G_DEFINE_TYPE (EomJobCopy, eom_job_copy, EOM_TYPE_JOB);
+
+enum
+{
+ SIGNAL_FINISHED,
+ SIGNAL_PROGRESS,
+ SIGNAL_LAST_SIGNAL
+};
+
+static guint job_signals[SIGNAL_LAST_SIGNAL];
+
+static void eom_job_copy_run (EomJob *ejob);
+static void eom_job_load_run (EomJob *ejob);
+static void eom_job_model_run (EomJob *ejob);
+static void eom_job_save_run (EomJob *job);
+static void eom_job_save_as_run (EomJob *job);
+static void eom_job_thumbnail_run (EomJob *ejob);
+static void eom_job_transform_run (EomJob *ejob);
+
+static void eom_job_init (EomJob *job)
+{
+ job->mutex = g_mutex_new();
+ job->progress = 0.0;
+}
+
+static void
+eom_job_dispose (GObject *object)
+{
+ EomJob *job;
+
+ job = EOM_JOB (object);
+
+ if (job->error) {
+ g_error_free (job->error);
+ job->error = NULL;
+ }
+
+ if (job->mutex) {
+ g_mutex_free (job->mutex);
+ job->mutex = NULL;
+ }
+
+ (* G_OBJECT_CLASS (eom_job_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_run_default (EomJob *job)
+{
+ g_critical ("Class \"%s\" does not implement the required run action",
+ G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (job)));
+}
+
+static void
+eom_job_class_init (EomJobClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = eom_job_dispose;
+
+ class->run = eom_job_run_default;
+
+ job_signals [SIGNAL_FINISHED] =
+ g_signal_new ("finished",
+ EOM_TYPE_JOB,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomJobClass, finished),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ job_signals [SIGNAL_PROGRESS] =
+ g_signal_new ("progress",
+ EOM_TYPE_JOB,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EomJobClass, progress),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__FLOAT,
+ G_TYPE_NONE, 1,
+ G_TYPE_FLOAT);
+}
+
+void
+eom_job_finished (EomJob *job)
+{
+ g_return_if_fail (EOM_IS_JOB (job));
+
+ g_signal_emit (job, job_signals[SIGNAL_FINISHED], 0);
+}
+
+/**
+ * eom_job_run:
+ * @job: the job to execute.
+ *
+ * Executes the job passed as @job. Usually there is no need to call this
+ * on your own. Jobs should be executed by using the EomJobQueue.
+ **/
+void
+eom_job_run (EomJob *job)
+{
+ EomJobClass *class;
+
+ g_return_if_fail (EOM_IS_JOB (job));
+
+ class = EOM_JOB_GET_CLASS (job);
+ if (class->run)
+ class->run (job);
+ else
+ eom_job_run_default (job);
+}
+static gboolean
+notify_progress (gpointer data)
+{
+ EomJob *job = EOM_JOB (data);
+
+ g_signal_emit (job, job_signals[SIGNAL_PROGRESS], 0, job->progress);
+
+ return FALSE;
+}
+
+void
+eom_job_set_progress (EomJob *job, float progress)
+{
+ g_return_if_fail (EOM_IS_JOB (job));
+ g_return_if_fail (progress >= 0.0 && progress <= 1.0);
+
+ g_mutex_lock (job->mutex);
+ job->progress = progress;
+ g_mutex_unlock (job->mutex);
+
+ g_idle_add (notify_progress, job);
+}
+
+static void eom_job_thumbnail_init (EomJobThumbnail *job) { /* Do Nothing */ }
+
+static void
+eom_job_thumbnail_dispose (GObject *object)
+{
+ EomJobThumbnail *job;
+
+ job = EOM_JOB_THUMBNAIL (object);
+
+ if (job->image) {
+ g_object_unref (job->image);
+ job->image = NULL;
+ }
+
+ if (job->thumbnail) {
+ g_object_unref (job->thumbnail);
+ job->thumbnail = NULL;
+ }
+
+ (* G_OBJECT_CLASS (eom_job_thumbnail_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_thumbnail_class_init (EomJobThumbnailClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = eom_job_thumbnail_dispose;
+
+ EOM_JOB_CLASS (class)->run = eom_job_thumbnail_run;
+}
+
+EomJob *
+eom_job_thumbnail_new (EomImage *image)
+{
+ EomJobThumbnail *job;
+
+ job = g_object_new (EOM_TYPE_JOB_THUMBNAIL, NULL);
+
+ if (image) {
+ job->image = g_object_ref (image);
+ }
+
+ return EOM_JOB (job);
+}
+
+static void
+eom_job_thumbnail_run (EomJob *ejob)
+{
+ gchar *orig_width, *orig_height;
+ gint width, height;
+ GdkPixbuf *pixbuf;
+ EomJobThumbnail *job;
+
+ g_return_if_fail (EOM_IS_JOB_THUMBNAIL (ejob));
+
+ job = EOM_JOB_THUMBNAIL (ejob);
+
+ if (ejob->error) {
+ g_error_free (ejob->error);
+ ejob->error = NULL;
+ }
+
+ job->thumbnail = eom_thumbnail_load (job->image,
+ &ejob->error);
+
+ if (!job->thumbnail) {
+ ejob->finished = TRUE;
+ return;
+ }
+
+ orig_width = g_strdup (gdk_pixbuf_get_option (job->thumbnail, "tEXt::Thumb::Image::Width"));
+ orig_height = g_strdup (gdk_pixbuf_get_option (job->thumbnail, "tEXt::Thumb::Image::Height"));
+
+ pixbuf = eom_thumbnail_fit_to_size (job->thumbnail, EOM_LIST_STORE_THUMB_SIZE);
+ g_object_unref (job->thumbnail);
+ job->thumbnail = eom_thumbnail_add_frame (pixbuf);
+ g_object_unref (pixbuf);
+
+ if (orig_width) {
+ sscanf (orig_width, "%i", &width);
+ g_object_set_data (G_OBJECT (job->thumbnail),
+ EOM_THUMBNAIL_ORIGINAL_WIDTH,
+ GINT_TO_POINTER (width));
+ g_free (orig_width);
+ }
+ if (orig_height) {
+ sscanf (orig_height, "%i", &height);
+ g_object_set_data (G_OBJECT (job->thumbnail),
+ EOM_THUMBNAIL_ORIGINAL_HEIGHT,
+ GINT_TO_POINTER (height));
+ g_free (orig_height);
+ }
+
+ if (ejob->error) {
+ g_warning ("%s", ejob->error->message);
+ }
+
+ ejob->finished = TRUE;
+}
+
+static void eom_job_load_init (EomJobLoad *job) { /* Do Nothing */ }
+
+static void
+eom_job_load_dispose (GObject *object)
+{
+ EomJobLoad *job;
+
+ job = EOM_JOB_LOAD (object);
+
+ if (job->image) {
+ g_object_unref (job->image);
+ job->image = NULL;
+ }
+
+ (* G_OBJECT_CLASS (eom_job_load_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_load_class_init (EomJobLoadClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = eom_job_load_dispose;
+ EOM_JOB_CLASS (class)->run = eom_job_load_run;
+}
+
+EomJob *
+eom_job_load_new (EomImage *image, EomImageData data)
+{
+ EomJobLoad *job;
+
+ job = g_object_new (EOM_TYPE_JOB_LOAD, NULL);
+
+ if (image) {
+ job->image = g_object_ref (image);
+ }
+ job->data = data;
+
+ return EOM_JOB (job);
+}
+
+static void
+eom_job_load_run (EomJob *job)
+{
+ g_return_if_fail (EOM_IS_JOB_LOAD (job));
+
+ if (job->error) {
+ g_error_free (job->error);
+ job->error = NULL;
+ }
+
+ eom_image_load (EOM_IMAGE (EOM_JOB_LOAD (job)->image),
+ EOM_JOB_LOAD (job)->data,
+ job,
+ &job->error);
+
+ job->finished = TRUE;
+}
+
+static void eom_job_model_init (EomJobModel *job) { /* Do Nothing */ }
+
+static void
+eom_job_model_dispose (GObject *object)
+{
+ EomJobModel *job;
+
+ job = EOM_JOB_MODEL (object);
+
+ (* G_OBJECT_CLASS (eom_job_model_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_model_class_init (EomJobModelClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = eom_job_model_dispose;
+ EOM_JOB_CLASS (class)->run = eom_job_model_run;
+}
+
+EomJob *
+eom_job_model_new (GSList *file_list)
+{
+ EomJobModel *job;
+
+ job = g_object_new (EOM_TYPE_JOB_MODEL, NULL);
+
+ job->file_list = file_list;
+
+ return EOM_JOB (job);
+}
+
+static void
+filter_files (GSList *files, GList **file_list, GList **error_list)
+{
+ GSList *it;
+ GFileInfo *file_info;
+
+ for (it = files; it != NULL; it = it->next) {
+ GFile *file;
+ GFileType type = G_FILE_TYPE_UNKNOWN;
+
+ file = (GFile *) it->data;
+
+ if (file != NULL) {
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE","G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, NULL);
+ if (file_info == NULL) {
+ type = G_FILE_TYPE_UNKNOWN;
+ } else {
+ type = g_file_info_get_file_type (file_info);
+
+ /* Workaround for gvfs backends that
+ don't set the GFileType. */
+ if (G_UNLIKELY (type == G_FILE_TYPE_UNKNOWN)) {
+ const gchar *ctype;
+
+ ctype = g_file_info_get_content_type (file_info);
+
+ /* If the content type is supported
+ adjust the file_type */
+ if (eom_image_is_supported_mime_type (ctype))
+ type = G_FILE_TYPE_REGULAR;
+ }
+
+ g_object_unref (file_info);
+ }
+ }
+
+ switch (type) {
+ case G_FILE_TYPE_REGULAR:
+ case G_FILE_TYPE_DIRECTORY:
+ *file_list = g_list_prepend (*file_list, g_object_ref (file));
+ break;
+ default:
+ *error_list = g_list_prepend (*error_list,
+ g_file_get_uri (file));
+ break;
+ }
+
+ g_object_unref (file);
+ }
+
+ *file_list = g_list_reverse (*file_list);
+ *error_list = g_list_reverse (*error_list);
+}
+
+static void
+eom_job_model_run (EomJob *ejob)
+{
+ GList *filtered_list = NULL;
+ GList *error_list = NULL;
+ EomJobModel *job;
+
+ g_return_if_fail (EOM_IS_JOB_MODEL (ejob));
+
+ job = EOM_JOB_MODEL (ejob);
+
+ filter_files (job->file_list, &filtered_list, &error_list);
+
+ job->store = EOM_LIST_STORE (eom_list_store_new ());
+
+ eom_list_store_add_files (job->store, filtered_list);
+
+ g_list_foreach (filtered_list, (GFunc) g_object_unref, NULL);
+ g_list_free (filtered_list);
+
+ g_list_foreach (error_list, (GFunc) g_free, NULL);
+ g_list_free (error_list);
+
+ ejob->finished = TRUE;
+}
+
+static void eom_job_transform_init (EomJobTransform *job) { /* Do Nothing */ }
+
+static void
+eom_job_transform_dispose (GObject *object)
+{
+ EomJobTransform *job;
+
+ job = EOM_JOB_TRANSFORM (object);
+
+ if (job->trans) {
+ g_object_unref (job->trans);
+ job->trans = NULL;
+ }
+
+ g_list_foreach (job->images, (GFunc) g_object_unref, NULL);
+ g_list_free (job->images);
+
+ (* G_OBJECT_CLASS (eom_job_transform_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_transform_class_init (EomJobTransformClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = eom_job_transform_dispose;
+
+ EOM_JOB_CLASS (class)->run = eom_job_transform_run;
+}
+
+EomJob *
+eom_job_transform_new (GList *images, EomTransform *trans)
+{
+ EomJobTransform *job;
+
+ job = g_object_new (EOM_TYPE_JOB_TRANSFORM, NULL);
+
+ if (trans) {
+ job->trans = g_object_ref (trans);
+ } else {
+ job->trans = NULL;
+ }
+
+ job->images = images;
+
+ return EOM_JOB (job);
+}
+
+static gboolean
+eom_job_transform_image_modified (gpointer data)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (data), FALSE);
+
+ eom_image_modified (EOM_IMAGE (data));
+ g_object_unref (G_OBJECT (data));
+
+ return FALSE;
+}
+
+void
+eom_job_transform_run (EomJob *ejob)
+{
+ EomJobTransform *job;
+ GList *it;
+
+ g_return_if_fail (EOM_IS_JOB_TRANSFORM (ejob));
+
+ job = EOM_JOB_TRANSFORM (ejob);
+
+ if (ejob->error) {
+ g_error_free (ejob->error);
+ ejob->error = NULL;
+ }
+
+ for (it = job->images; it != NULL; it = it->next) {
+ EomImage *image = EOM_IMAGE (it->data);
+
+ if (job->trans == NULL) {
+ eom_image_undo (image);
+ } else {
+ eom_image_transform (image, job->trans, ejob);
+ }
+
+ if (eom_image_is_modified (image) || job->trans == NULL) {
+ g_object_ref (image);
+ g_idle_add (eom_job_transform_image_modified, image);
+ }
+ }
+
+ ejob->finished = TRUE;
+}
+
+static void eom_job_save_init (EomJobSave *job) { /* do nothing */ }
+
+static void
+eom_job_save_dispose (GObject *object)
+{
+ EomJobSave *job;
+
+ job = EOM_JOB_SAVE (object);
+
+ if (job->images) {
+ g_list_foreach (job->images, (GFunc) g_object_unref, NULL);
+ g_list_free (job->images);
+ job->images = NULL;
+ }
+
+ (* G_OBJECT_CLASS (eom_job_save_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_save_class_init (EomJobSaveClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = eom_job_save_dispose;
+ EOM_JOB_CLASS (class)->run = eom_job_save_run;
+}
+
+EomJob *
+eom_job_save_new (GList *images)
+{
+ EomJobSave *job;
+
+ job = g_object_new (EOM_TYPE_JOB_SAVE, NULL);
+
+ job->images = images;
+ job->current_image = NULL;
+
+ return EOM_JOB (job);
+}
+
+static void
+save_progress_handler (EomImage *image, gfloat progress, gpointer data)
+{
+ EomJobSave *job = EOM_JOB_SAVE (data);
+ guint n_images = g_list_length (job->images);
+ gfloat job_progress;
+
+ job_progress = (job->current_pos / (gfloat) n_images) + (progress / n_images);
+
+ eom_job_set_progress (EOM_JOB (job), job_progress);
+}
+
+static void
+eom_job_save_run (EomJob *ejob)
+{
+ EomJobSave *job;
+ GList *it;
+
+ g_return_if_fail (EOM_IS_JOB_SAVE (ejob));
+
+ job = EOM_JOB_SAVE (ejob);
+
+ job->current_pos = 0;
+
+ for (it = job->images; it != NULL; it = it->next, job->current_pos++) {
+ EomImage *image = EOM_IMAGE (it->data);
+ EomImageSaveInfo *save_info = NULL;
+ gulong handler_id = 0;
+ gboolean success = FALSE;
+
+ job->current_image = image;
+
+ /* Make sure the image doesn't go away while saving */
+ eom_image_data_ref (image);
+
+ if (!eom_image_has_data (image, EOM_IMAGE_DATA_ALL)) {
+ eom_image_load (image,
+ EOM_IMAGE_DATA_ALL,
+ NULL,
+ &ejob->error);
+ }
+
+ handler_id = g_signal_connect (G_OBJECT (image),
+ "save-progress",
+ G_CALLBACK (save_progress_handler),
+ job);
+
+ save_info = eom_image_save_info_from_image (image);
+
+ success = eom_image_save_by_info (image,
+ save_info,
+ &ejob->error);
+
+ if (save_info)
+ g_object_unref (save_info);
+
+ if (handler_id != 0)
+ g_signal_handler_disconnect (G_OBJECT (image), handler_id);
+
+ eom_image_data_unref (image);
+
+ if (!success) break;
+ }
+
+ ejob->finished = TRUE;
+}
+
+static void eom_job_save_as_init (EomJobSaveAs *job) { /* do nothing */ }
+
+static void eom_job_save_as_dispose (GObject *object)
+{
+ EomJobSaveAs *job = EOM_JOB_SAVE_AS (object);
+
+ if (job->converter != NULL) {
+ g_object_unref (job->converter);
+ job->converter = NULL;
+ }
+
+ if (job->file != NULL) {
+ g_object_unref (job->file);
+ job->file = NULL;
+ }
+
+ (* G_OBJECT_CLASS (eom_job_save_as_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_save_as_class_init (EomJobSaveAsClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = eom_job_save_as_dispose;
+ EOM_JOB_CLASS (class)->run = eom_job_save_as_run;
+}
+
+EomJob *
+eom_job_save_as_new (GList *images, EomURIConverter *converter, GFile *file)
+{
+ EomJobSaveAs *job;
+
+ g_assert (converter != NULL || g_list_length (images) == 1);
+
+ job = g_object_new (EOM_TYPE_JOB_SAVE_AS, NULL);
+
+ EOM_JOB_SAVE(job)->images = images;
+
+ job->converter = converter ? g_object_ref (converter) : NULL;
+ job->file = file ? g_object_ref (file) : NULL;
+
+ return EOM_JOB (job);
+}
+
+static void
+eom_job_save_as_run (EomJob *ejob)
+{
+ EomJobSave *job;
+ EomJobSaveAs *saveas_job;
+ GList *it;
+ guint n_images;
+
+ g_return_if_fail (EOM_IS_JOB_SAVE_AS (ejob));
+
+ job = EOM_JOB_SAVE (ejob);
+
+ n_images = g_list_length (job->images);
+
+ saveas_job = EOM_JOB_SAVE_AS (job);
+
+ job->current_pos = 0;
+
+ for (it = job->images; it != NULL; it = it->next, job->current_pos++) {
+ GdkPixbufFormat *format;
+ EomImageSaveInfo *src_info, *dest_info;
+ EomImage *image = EOM_IMAGE (it->data);
+ gboolean success = FALSE;
+ gulong handler_id = 0;
+
+ job->current_image = image;
+
+ eom_image_data_ref (image);
+
+ if (!eom_image_has_data (image, EOM_IMAGE_DATA_ALL)) {
+ eom_image_load (image,
+ EOM_IMAGE_DATA_ALL,
+ NULL,
+ &ejob->error);
+ }
+
+ g_assert (ejob->error == NULL);
+
+ handler_id = g_signal_connect (G_OBJECT (image),
+ "save-progress",
+ G_CALLBACK (save_progress_handler),
+ job);
+
+ src_info = eom_image_save_info_from_image (image);
+
+ if (n_images == 1) {
+ g_assert (saveas_job->file != NULL);
+
+ format = eom_pixbuf_get_format (saveas_job->file);
+
+ dest_info = eom_image_save_info_from_file (saveas_job->file,
+ format);
+
+ /* SaveAsDialog has already secured permission to overwrite */
+ if (dest_info->exists) {
+ dest_info->overwrite = TRUE;
+ }
+ } else {
+ GFile *dest_file;
+ gboolean result;
+
+ result = eom_uri_converter_do (saveas_job->converter,
+ image,
+ &dest_file,
+ &format,
+ NULL);
+
+ g_assert (result);
+
+ dest_info = eom_image_save_info_from_file (dest_file,
+ format);
+ }
+
+ success = eom_image_save_as_by_info (image,
+ src_info,
+ dest_info,
+ &ejob->error);
+
+ if (src_info)
+ g_object_unref (src_info);
+
+ if (dest_info)
+ g_object_unref (dest_info);
+
+ if (handler_id != 0)
+ g_signal_handler_disconnect (G_OBJECT (image), handler_id);
+
+ eom_image_data_unref (image);
+
+ if (!success)
+ break;
+ }
+
+ ejob->finished = TRUE;
+}
+
+static void eom_job_copy_init (EomJobCopy *job) { /* do nothing */};
+
+static void
+eom_job_copy_dispose (GObject *object)
+{
+ EomJobCopy *job = EOM_JOB_COPY (object);
+
+ if (job->dest) {
+ g_free (job->dest);
+ job->dest = NULL;
+ }
+
+ (* G_OBJECT_CLASS (eom_job_copy_parent_class)->dispose) (object);
+}
+
+static void
+eom_job_copy_class_init (EomJobCopyClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = eom_job_copy_dispose;
+ EOM_JOB_CLASS (class)->run = eom_job_copy_run;
+}
+
+EomJob *
+eom_job_copy_new (GList *images, const gchar *dest)
+{
+ EomJobCopy *job;
+
+ g_assert (images != NULL && dest != NULL);
+
+ job = g_object_new (EOM_TYPE_JOB_COPY, NULL);
+
+ job->images = images;
+ job->dest = g_strdup (dest);
+
+ return EOM_JOB (job);
+}
+
+static void
+eom_job_copy_progress_callback (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ gfloat job_progress;
+ guint n_images;
+ EomJobCopy *job;
+
+ job = EOM_JOB_COPY (user_data);
+ n_images = g_list_length (job->images);
+
+ job_progress = ((current_num_bytes / (gfloat) total_num_bytes) + job->current_pos)/n_images;
+
+ eom_job_set_progress (EOM_JOB (job), job_progress);
+}
+
+void
+eom_job_copy_run (EomJob *ejob)
+{
+ EomJobCopy *job;
+ GList *it;
+ guint n_images;
+ GFile *src, *dest;
+ gchar *filename, *dest_filename;
+
+ g_return_if_fail (EOM_IS_JOB_COPY (ejob));
+
+ job = EOM_JOB_COPY (ejob);
+
+ n_images = g_list_length (job->images);
+
+ job->current_pos = 0;
+
+ for (it = job->images; it != NULL; it = g_list_next (it), job->current_pos++) {
+ src = (GFile *) it->data;
+ filename = g_file_get_basename (src);
+ dest_filename = g_build_filename (job->dest, filename, NULL);
+ dest = g_file_new_for_path (dest_filename);
+
+ g_file_copy (src, dest,
+ G_FILE_COPY_OVERWRITE, NULL,
+ eom_job_copy_progress_callback, job,
+ &ejob->error);
+ g_free (filename);
+ g_free (dest_filename);
+ }
+
+ ejob->finished = TRUE;
+}
diff --git a/src/eom-jobs.h b/src/eom-jobs.h
new file mode 100644
index 0000000..7fd4965
--- /dev/null
+++ b/src/eom-jobs.h
@@ -0,0 +1,275 @@
+/* Eye Of Mate - Jobs
+ *
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on evince code (shell/ev-jobs.h) by:
+ * - Martin Kretzschmar <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_JOBS_H__
+#define __EOM_JOBS_H__
+
+#include "eom-list-store.h"
+#include "eom-transform.h"
+#include "eom-enums.h"
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#ifndef __EOM_IMAGE_DECLR__
+#define __EOM_IMAGE_DECLR__
+ typedef struct _EomImage EomImage;
+#endif
+
+#ifndef __EOM_URI_CONVERTER_DECLR__
+#define __EOM_URI_CONVERTER_DECLR__
+typedef struct _EomURIConverter EomURIConverter;
+#endif
+
+#ifndef __EOM_JOB_DECLR__
+#define __EOM_JOB_DECLR__
+typedef struct _EomJob EomJob;
+#endif
+typedef struct _EomJobClass EomJobClass;
+
+typedef struct _EomJobThumbnail EomJobThumbnail;
+typedef struct _EomJobThumbnailClass EomJobThumbnailClass;
+
+typedef struct _EomJobLoad EomJobLoad;
+typedef struct _EomJobLoadClass EomJobLoadClass;
+
+typedef struct _EomJobModel EomJobModel;
+typedef struct _EomJobModelClass EomJobModelClass;
+
+typedef struct _EomJobTransform EomJobTransform;
+typedef struct _EomJobTransformClass EomJobTransformClass;
+
+typedef struct _EomJobSave EomJobSave;
+typedef struct _EomJobSaveClass EomJobSaveClass;
+
+typedef struct _EomJobSaveAs EomJobSaveAs;
+typedef struct _EomJobSaveAsClass EomJobSaveAsClass;
+
+typedef struct _EomJobCopy EomJobCopy;
+typedef struct _EomJobCopyClass EomJobCopyClass;
+
+#define EOM_TYPE_JOB (eom_job_get_type())
+#define EOM_JOB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB, EomJob))
+#define EOM_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB, EomJobClass))
+#define EOM_IS_JOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB))
+#define EOM_JOB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_JOB, EomJobClass))
+
+#define EOM_TYPE_JOB_THUMBNAIL (eom_job_thumbnail_get_type())
+#define EOM_JOB_THUMBNAIL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_THUMBNAIL, EomJobThumbnail))
+#define EOM_JOB_THUMBNAIL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_THUMBNAIL, EomJobThumbnailClass))
+#define EOM_IS_JOB_THUMBNAIL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_THUMBNAIL))
+
+#define EOM_TYPE_JOB_LOAD (eom_job_load_get_type())
+#define EOM_JOB_LOAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_LOAD, EomJobLoad))
+#define EOM_JOB_LOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_LOAD, EomJobLoadClass))
+#define EOM_IS_JOB_LOAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_LOAD))
+
+#define EOM_TYPE_JOB_MODEL (eom_job_model_get_type())
+#define EOM_JOB_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_MODEL, EomJobModel))
+#define EOM_JOB_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_MODEL, EomJobModelClass))
+#define EOM_IS_JOB_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_MODEL))
+
+#define EOM_TYPE_JOB_TRANSFORM (eom_job_transform_get_type())
+#define EOM_JOB_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_TRANSFORM, EomJobTransform))
+#define EOM_JOB_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_TRANSFORM, EomJobTransformClass))
+#define EOM_IS_JOB_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_TRANSFORM))
+
+#define EOM_TYPE_JOB_SAVE (eom_job_save_get_type())
+#define EOM_JOB_SAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_SAVE, EomJobSave))
+#define EOM_JOB_SAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_SAVE, EomJobSaveClass))
+#define EOM_IS_JOB_SAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_SAVE))
+#define EOM_JOB_SAVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_JOB_SAVE, EomJobSaveClass))
+
+#define EOM_TYPE_JOB_SAVE_AS (eom_job_save_as_get_type())
+#define EOM_JOB_SAVE_AS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_SAVE_AS, EomJobSaveAs))
+#define EOM_JOB_SAVE_AS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_SAVE_AS, EomJobSaveAsClass))
+#define EOM_IS_JOB_SAVE_AS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_SAVE_AS))
+
+#define EOM_TYPE_JOB_COPY (eom_job_copy_get_type())
+#define EOM_JOB_COPY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_JOB_COPY, EomJobCopy))
+#define EOM_JOB_COPY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_JOB_COPY, EomJobCopyClass))
+#define EOM_IS_JOB_COPY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_JOB_COPY))
+
+
+struct _EomJob
+{
+ GObject parent;
+
+ GError *error;
+ GMutex *mutex;
+ float progress;
+ gboolean finished;
+};
+
+struct _EomJobClass
+{
+ GObjectClass parent_class;
+
+ void (* finished) (EomJob *job);
+ void (* progress) (EomJob *job, float progress);
+ void (*run) (EomJob *job);
+};
+
+struct _EomJobThumbnail
+{
+ EomJob parent;
+ EomImage *image;
+ GdkPixbuf *thumbnail;
+};
+
+struct _EomJobThumbnailClass
+{
+ EomJobClass parent_class;
+};
+
+struct _EomJobLoad
+{
+ EomJob parent;
+ EomImage *image;
+ EomImageData data;
+};
+
+struct _EomJobLoadClass
+{
+ EomJobClass parent_class;
+};
+
+struct _EomJobModel
+{
+ EomJob parent;
+ EomListStore *store;
+ GSList *file_list;
+};
+
+struct _EomJobModelClass
+{
+ EomJobClass parent_class;
+};
+
+struct _EomJobTransform
+{
+ EomJob parent;
+ GList *images;
+ EomTransform *trans;
+};
+
+struct _EomJobTransformClass
+{
+ EomJobClass parent_class;
+};
+
+typedef enum {
+ EOM_SAVE_RESPONSE_NONE,
+ EOM_SAVE_RESPONSE_RETRY,
+ EOM_SAVE_RESPONSE_SKIP,
+ EOM_SAVE_RESPONSE_OVERWRITE,
+ EOM_SAVE_RESPONSE_CANCEL,
+ EOM_SAVE_RESPONSE_LAST
+} EomJobSaveResponse;
+
+struct _EomJobSave
+{
+ EomJob parent;
+ GList *images;
+ guint current_pos;
+ EomImage *current_image;
+};
+
+struct _EomJobSaveClass
+{
+ EomJobClass parent_class;
+};
+
+struct _EomJobSaveAs
+{
+ EomJobSave parent;
+ EomURIConverter *converter;
+ GFile *file;
+};
+
+struct _EomJobSaveAsClass
+{
+ EomJobSaveClass parent;
+};
+
+struct _EomJobCopy
+{
+ EomJob parent;
+ GList *images;
+ guint current_pos;
+ gchar *dest;
+};
+
+struct _EomJobCopyClass
+{
+ EomJobClass parent_class;
+};
+
+/* base job class */
+GType eom_job_get_type (void) G_GNUC_CONST;
+void eom_job_finished (EomJob *job);
+void eom_job_run (EomJob *job);
+void eom_job_set_progress (EomJob *job,
+ float progress);
+
+/* EomJobThumbnail */
+GType eom_job_thumbnail_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_thumbnail_new (EomImage *image);
+
+/* EomJobLoad */
+GType eom_job_load_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_load_new (EomImage *image,
+ EomImageData data);
+
+/* EomJobModel */
+GType eom_job_model_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_model_new (GSList *file_list);
+
+/* EomJobTransform */
+GType eom_job_transform_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_transform_new (GList *images,
+ EomTransform *trans);
+
+/* EomJobSave */
+GType eom_job_save_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_save_new (GList *images);
+
+/* EomJobSaveAs */
+GType eom_job_save_as_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_save_as_new (GList *images,
+ EomURIConverter *converter,
+ GFile *file);
+
+/*EomJobCopy */
+GType eom_job_copy_get_type (void) G_GNUC_CONST;
+EomJob *eom_job_copy_new (GList *images,
+ const gchar *dest);
+
+G_END_DECLS
+
+#endif /* __EOM_JOBS_H__ */
diff --git a/src/eom-list-store.c b/src/eom-list-store.c
new file mode 100644
index 0000000..562019e
--- /dev/null
+++ b/src/eom-list-store.c
@@ -0,0 +1,931 @@
+/* Eye Of Mate - Image Store
+ *
+ * Copyright (C) 2006-2008 The Free Software Foundation
+ *
+ * Author: Claudio Saavedra <[email protected]>
+ *
+ * Based on code by: Jens Finke <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "eom-list-store.h"
+#include "eom-thumbnail.h"
+#include "eom-image.h"
+#include "eom-job-queue.h"
+#include "eom-jobs.h"
+
+#include <string.h>
+
+#define EOM_LIST_STORE_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_LIST_STORE, EomListStorePrivate))
+
+G_DEFINE_TYPE (EomListStore, eom_list_store, GTK_TYPE_LIST_STORE);
+
+struct _EomListStorePrivate {
+ GList *monitors; /* Monitors for the directories */
+ gint initial_image; /* The image that should be selected firstly by the view. */
+ GdkPixbuf *busy_image; /* Loading image icon */
+ GdkPixbuf *missing_image; /* Missing image icon */
+ GMutex *mutex; /* Mutex for saving the jobs in the model */
+};
+
+static void
+eom_list_store_finalize (GObject *object)
+{
+ EomListStore *store = EOM_LIST_STORE (object);
+
+ if (store->priv != NULL) {
+ g_free (store->priv);
+ store->priv = NULL;
+ }
+
+ G_OBJECT_CLASS (eom_list_store_parent_class)->finalize (object);
+}
+
+static void
+foreach_monitors_free (gpointer data, gpointer user_data)
+{
+ g_file_monitor_cancel (G_FILE_MONITOR (data));
+}
+
+static void
+eom_list_store_dispose (GObject *object)
+{
+ EomListStore *store = EOM_LIST_STORE (object);
+
+ g_list_foreach (store->priv->monitors,
+ foreach_monitors_free, NULL);
+
+ g_list_free (store->priv->monitors);
+
+ store->priv->monitors = NULL;
+
+ if(store->priv->busy_image != NULL) {
+ g_object_unref (store->priv->busy_image);
+ store->priv->busy_image = NULL;
+ }
+
+ if(store->priv->missing_image != NULL) {
+ g_object_unref (store->priv->missing_image);
+ store->priv->missing_image = NULL;
+ }
+
+ g_mutex_free (store->priv->mutex);
+
+ G_OBJECT_CLASS (eom_list_store_parent_class)->dispose (object);
+}
+
+static void
+eom_list_store_class_init (EomListStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = eom_list_store_finalize;
+ object_class->dispose = eom_list_store_dispose;
+
+ g_type_class_add_private (object_class, sizeof (EomListStorePrivate));
+}
+
+/*
+ Sorting functions
+*/
+
+static gint
+eom_list_store_compare_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gint r_value;
+
+ EomImage *image_a, *image_b;
+
+ gtk_tree_model_get (model, a,
+ EOM_LIST_STORE_EOM_IMAGE, &image_a,
+ -1);
+
+ gtk_tree_model_get (model, b,
+ EOM_LIST_STORE_EOM_IMAGE, &image_b,
+ -1);
+
+ r_value = strcmp (eom_image_get_collate_key (image_a),
+ eom_image_get_collate_key (image_b));
+
+ g_object_unref (G_OBJECT (image_a));
+ g_object_unref (G_OBJECT (image_b));
+
+ return r_value;
+}
+
+static GdkPixbuf *
+eom_list_store_get_icon (const gchar *icon_name)
+{
+ GError *error = NULL;
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf;
+
+ icon_theme = gtk_icon_theme_get_default ();
+
+ pixbuf = gtk_icon_theme_load_icon (icon_theme,
+ icon_name,
+ EOM_LIST_STORE_THUMB_SIZE,
+ 0,
+ &error);
+
+ if (!pixbuf) {
+ g_warning ("Couldn't load icon: %s", error->message);
+ g_error_free (error);
+ }
+
+ return pixbuf;
+}
+
+static void
+eom_list_store_init (EomListStore *self)
+{
+ GType types[EOM_LIST_STORE_NUM_COLUMNS];
+
+ types[EOM_LIST_STORE_THUMBNAIL] = GDK_TYPE_PIXBUF;
+ types[EOM_LIST_STORE_EOM_IMAGE] = G_TYPE_OBJECT;
+ types[EOM_LIST_STORE_THUMB_SET] = G_TYPE_BOOLEAN;
+ types[EOM_LIST_STORE_EOM_JOB] = G_TYPE_POINTER;
+
+ gtk_list_store_set_column_types (GTK_LIST_STORE (self),
+ EOM_LIST_STORE_NUM_COLUMNS, types);
+
+ self->priv = EOM_LIST_STORE_GET_PRIVATE (self);
+
+ self->priv->monitors = NULL;
+ self->priv->initial_image = -1;
+
+ self->priv->busy_image = eom_list_store_get_icon ("image-loading");
+ self->priv->missing_image = eom_list_store_get_icon ("image-missing");
+
+ self->priv->mutex = g_mutex_new ();
+
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (self),
+ eom_list_store_compare_func,
+ NULL, NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+}
+
+/**
+ * eom_list_store_new:
+ *
+ * Creates a new and empty #EomListStore.
+ *
+ * Returns: a newly created #EomListStore.
+ **/
+GtkListStore*
+eom_list_store_new (void)
+{
+ return g_object_new (EOM_TYPE_LIST_STORE, NULL);
+}
+
+/*
+ Searchs for a file in the store. If found and @iter_found is not NULL,
+ then sets @iter_found to a #GtkTreeIter pointing to the file.
+ */
+static gboolean
+is_file_in_list_store (EomListStore *store,
+ const gchar *info_uri,
+ GtkTreeIter *iter_found)
+{
+ gboolean found = FALSE;
+ EomImage *image;
+ GFile *file;
+ gchar *str;
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+ return FALSE;
+ }
+
+ do {
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+ if (!image)
+ continue;
+
+ file = eom_image_get_file (image);
+ str = g_file_get_uri (file);
+
+ found = (strcmp (str, info_uri) == 0)? TRUE : FALSE;
+
+ g_object_unref (file);
+ g_free (str);
+ g_object_unref (G_OBJECT (image));
+
+ } while (!found &&
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
+
+ if (found && iter_found != NULL) {
+ *iter_found = iter;
+ }
+
+ return found;
+}
+
+static gboolean
+is_file_in_list_store_file (EomListStore *store,
+ GFile *file,
+ GtkTreeIter *iter_found)
+{
+ gchar *uri_str;
+ gboolean result;
+
+ uri_str = g_file_get_uri (file);
+
+ result = is_file_in_list_store (store, uri_str, iter_found);
+
+ g_free (uri_str);
+
+ return result;
+}
+
+static void
+eom_job_thumbnail_cb (EomJobThumbnail *job, gpointer data)
+{
+ EomListStore *store;
+ GtkTreeIter iter;
+ EomImage *image;
+ GdkPixbuf *thumbnail;
+ GFile *file;
+
+ g_return_if_fail (EOM_IS_LIST_STORE (data));
+
+ store = EOM_LIST_STORE (data);
+
+ file = eom_image_get_file (job->image);
+
+ if (is_file_in_list_store_file (store, file, &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+
+ if (job->thumbnail) {
+ eom_image_set_thumbnail (image, job->thumbnail);
+
+ /* Getting the thumbnail, in case it needed
+ * transformations */
+ thumbnail = eom_image_get_thumbnail (image);
+ } else {
+ thumbnail = g_object_ref (store->priv->missing_image);
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+ EOM_LIST_STORE_THUMBNAIL, thumbnail,
+ EOM_LIST_STORE_THUMB_SET, TRUE,
+ EOM_LIST_STORE_EOM_JOB, NULL,
+ -1);
+
+ g_object_unref (thumbnail);
+ }
+
+ g_object_unref (file);
+}
+
+static void
+on_image_changed (EomImage *image, EomListStore *store)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gint pos;
+
+ pos = eom_list_store_get_pos_by_image (store, image);
+ path = gtk_tree_path_new_from_indices (pos, -1);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+ eom_list_store_thumbnail_refresh (store, &iter);
+ gtk_tree_path_free (path);
+}
+
+/**
+ * eom_list_store_remove:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter.
+ *
+ * Removes the image pointed by @iter from @store.
+ **/
+static void
+eom_list_store_remove (EomListStore *store, GtkTreeIter *iter)
+{
+ EomImage *image;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+
+ g_signal_handlers_disconnect_by_func (image, on_image_changed, store);
+ g_object_unref (image);
+
+ gtk_list_store_remove (GTK_LIST_STORE (store), iter);
+}
+
+/**
+ * eom_list_store_append_image:
+ * @store: An #EomListStore.
+ * @image: An #EomImage.
+ *
+ * Adds an #EomImage to @store. The thumbnail of the image is not
+ * loaded and will only be loaded if the thumbnail is made visible
+ * or eom_list_store_set_thumbnail() is called.
+ *
+ **/
+void
+eom_list_store_append_image (EomListStore *store, EomImage *image)
+{
+ GtkTreeIter iter;
+
+ g_signal_connect (image, "changed",
+ G_CALLBACK (on_image_changed),
+ store);
+
+ gtk_list_store_append (GTK_LIST_STORE (store), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+ EOM_LIST_STORE_EOM_IMAGE, image,
+ EOM_LIST_STORE_THUMBNAIL, store->priv->busy_image,
+ EOM_LIST_STORE_THUMB_SET, FALSE,
+ -1);
+}
+
+static void
+eom_list_store_append_image_from_file (EomListStore *store,
+ GFile *file)
+{
+ EomImage *image;
+
+ g_return_if_fail (EOM_IS_LIST_STORE (store));
+
+ image = eom_image_new_file (file);
+
+ eom_list_store_append_image (store, image);
+}
+
+static void
+file_monitor_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ EomListStore *store)
+{
+ const char *mimetype;
+ GFileInfo *file_info;
+ GtkTreeIter iter;
+ EomImage *image;
+
+ switch (event) {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, NULL);
+ if (file_info == NULL) {
+ break;
+ }
+ mimetype = g_file_info_get_content_type (file_info);
+
+ if (is_file_in_list_store_file (store, file, &iter)) {
+ if (eom_image_is_supported_mime_type (mimetype)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+ eom_image_file_changed (image);
+ g_object_unref (image);
+ eom_list_store_thumbnail_refresh (store, &iter);
+ } else {
+ eom_list_store_remove (store, &iter);
+ }
+ } else {
+ if (eom_image_is_supported_mime_type (mimetype)) {
+ eom_list_store_append_image_from_file (store, file);
+ }
+ }
+ g_object_unref (file_info);
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ if (is_file_in_list_store_file (store, file, &iter)) {
+ EomImage *image;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+
+ eom_list_store_remove (store, &iter);
+ }
+ break;
+ case G_FILE_MONITOR_EVENT_CREATED:
+ if (!is_file_in_list_store_file (store, file, NULL)) {
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, NULL);
+ if (file_info == NULL) {
+ break;
+ }
+ mimetype = g_file_info_get_content_type (file_info);
+
+ if (eom_image_is_supported_mime_type (mimetype)) {
+ eom_list_store_append_image_from_file (store, file);
+ }
+ g_object_unref (file_info);
+ }
+ break;
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, NULL);
+ if (file_info == NULL) {
+ break;
+ }
+ mimetype = g_file_info_get_content_type (file_info);
+ if (is_file_in_list_store_file (store, file, &iter) &&
+ eom_image_is_supported_mime_type (mimetype)) {
+ eom_list_store_thumbnail_refresh (store, &iter);
+ }
+ g_object_unref (file_info);
+ break;
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ break;
+ }
+}
+
+/*
+ * Called for each file in a directory. Checks if the file is some
+ * sort of image. If so, it creates an image object and adds it to the
+ * list.
+ */
+static void
+directory_visit (GFile *directory,
+ GFileInfo *children_info,
+ EomListStore *store)
+{
+ GFile *child;
+ gboolean load_uri = FALSE;
+ const char *mime_type, *name;
+
+ mime_type = g_file_info_get_content_type (children_info);
+ name = g_file_info_get_name (children_info);
+
+ if (!g_str_has_prefix (name, ".")) {
+ if (eom_image_is_supported_mime_type (mime_type)) {
+ load_uri = TRUE;
+ }
+ }
+
+ if (load_uri) {
+ child = g_file_get_child (directory, name);
+ eom_list_store_append_image_from_file (store, child);
+ }
+}
+
+static void
+eom_list_store_append_directory (EomListStore *store,
+ GFile *file,
+ GFileType file_type)
+{
+ GFileMonitor *file_monitor;
+ GFileEnumerator *file_enumerator;
+ GFileInfo *file_info;
+
+ g_return_if_fail (file_type == G_FILE_TYPE_DIRECTORY);
+
+ file_monitor = g_file_monitor_directory (file,
+ 0, NULL, NULL);
+
+ if (file_monitor != NULL) {
+ g_signal_connect (file_monitor, "changed",
+ G_CALLBACK (file_monitor_changed_cb), store);
+
+ /* prepend seems more efficient to me, we don't need this list
+ to be sorted */
+ store->priv->monitors = g_list_prepend (store->priv->monitors, file_monitor);
+ }
+
+ file_enumerator = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ 0, NULL, NULL);
+ file_info = g_file_enumerator_next_file (file_enumerator, NULL, NULL);
+
+ while (file_info != NULL)
+ {
+ directory_visit (file, file_info, store);
+ g_object_unref (file_info);
+ file_info = g_file_enumerator_next_file (file_enumerator, NULL, NULL);
+ }
+ g_object_unref (file_enumerator);
+}
+
+/**
+ * eom_list_store_add_files:
+ * @store: An #EomListStore.
+ * @file_list: A %NULL-terminated list of #GFile's.
+ *
+ * Adds a list of #GFile's to @store. The given list
+ * must be %NULL-terminated.
+ *
+ * If any of the #GFile's in @file_list is a directory, all the images
+ * in that directory will be added to @store. If the list of files contains
+ * only one file and this is a regular file, then all the images in the same
+ * directory will be added as well to @store.
+ *
+ **/
+void
+eom_list_store_add_files (EomListStore *store, GList *file_list)
+{
+ GList *it;
+ GFileInfo *file_info;
+ GFileType file_type;
+ GFile *initial_file = NULL;
+ GtkTreeIter iter;
+
+ if (file_list == NULL) {
+ return;
+ }
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ for (it = file_list; it != NULL; it = it->next) {
+ GFile *file = (GFile *) it->data;
+
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, NULL);
+ if (file_info == NULL) {
+ continue;
+ }
+ file_type = g_file_info_get_file_type (file_info);
+
+ /* Workaround for gvfs backends that don't set the GFileType. */
+ if (G_UNLIKELY (file_type == G_FILE_TYPE_UNKNOWN)) {
+ const gchar *ctype;
+
+ ctype = g_file_info_get_content_type (file_info);
+
+ /* If the content type is supported adjust file_type */
+ if (eom_image_is_supported_mime_type (ctype))
+ file_type = G_FILE_TYPE_REGULAR;
+ }
+
+ g_object_unref (file_info);
+
+ if (file_type == G_FILE_TYPE_DIRECTORY) {
+ eom_list_store_append_directory (store, file, file_type);
+ } else if (file_type == G_FILE_TYPE_REGULAR &&
+ g_list_length (file_list) == 1) {
+
+ initial_file = g_file_dup (file);
+
+ file = g_file_get_parent (file);
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ 0, NULL, NULL);
+
+ /* If we can't get a file_info,
+ file_type will stay as G_FILE_TYPE_REGULAR */
+ if (file_info != NULL) {
+ file_type = g_file_info_get_file_type (file_info);
+ g_object_unref (file_info);
+ }
+
+ if (file_type == G_FILE_TYPE_DIRECTORY) {
+ eom_list_store_append_directory (store, file, file_type);
+
+ if (!is_file_in_list_store_file (store,
+ initial_file,
+ &iter)) {
+ eom_list_store_append_image_from_file (store, initial_file);
+ }
+ } else {
+ eom_list_store_append_image_from_file (store, initial_file);
+ }
+ g_object_unref (file);
+ } else if (file_type == G_FILE_TYPE_REGULAR &&
+ g_list_length (file_list) > 1) {
+ eom_list_store_append_image_from_file (store, file);
+ }
+ }
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ if (initial_file &&
+ is_file_in_list_store_file (store, initial_file, &iter)) {
+ store->priv->initial_image = eom_list_store_get_pos_by_iter (store, &iter);
+ g_object_unref (initial_file);
+ } else {
+ store->priv->initial_image = 0;
+ }
+}
+
+/**
+ * eom_list_store_remove_image:
+ * @store: An #EomListStore.
+ * @image: An #EomImage.
+ *
+ * Removes @image from @store.
+ **/
+void
+eom_list_store_remove_image (EomListStore *store, EomImage *image)
+{
+ GtkTreeIter iter;
+ GFile *file;
+
+ g_return_if_fail (EOM_IS_LIST_STORE (store));
+ g_return_if_fail (EOM_IS_IMAGE (image));
+
+ file = eom_image_get_file (image);
+
+ if (is_file_in_list_store_file (store, file, &iter)) {
+ eom_list_store_remove (store, &iter);
+ }
+ g_object_unref (file);
+}
+
+/**
+ * eom_list_store_new_from_glist:
+ * @list: a %NULL-terminated list of #EomImage's.
+ *
+ * Creates a new #EomListStore from a list of #EomImage's.
+ * The given list must be %NULL-terminated.
+ *
+ * Returns: a new #EomListStore.
+ **/
+GtkListStore *
+eom_list_store_new_from_glist (GList *list)
+{
+ GList *it;
+
+ GtkListStore *store = eom_list_store_new ();
+
+ for (it = list; it != NULL; it = it->next) {
+ eom_list_store_append_image (EOM_LIST_STORE (store),
+ EOM_IMAGE (it->data));
+ }
+
+ return store;
+}
+
+/**
+ * eom_list_store_get_pos_by_image:
+ * @store: An #EomListStore.
+ * @image: An #EomImage.
+ *
+ * Gets the position where @image is stored in @store. If @image
+ * is not stored in @store, -1 is returned.
+ *
+ * Returns: the position of @image in @store or -1 if not found.
+ **/
+gint
+eom_list_store_get_pos_by_image (EomListStore *store, EomImage *image)
+{
+ GtkTreeIter iter;
+ gint pos = -1;
+ GFile *file;
+
+ g_return_val_if_fail (EOM_IS_LIST_STORE (store), -1);
+ g_return_val_if_fail (EOM_IS_IMAGE (image), -1);
+
+ file = eom_image_get_file (image);
+
+ if (is_file_in_list_store_file (store, file, &iter)) {
+ pos = eom_list_store_get_pos_by_iter (store, &iter);
+ }
+
+ g_object_unref (file);
+ return pos;
+}
+
+/**
+ * eom_list_store_get_image_by_pos:
+ * @store: An #EomListStore.
+ * @pos: the position of the required #EomImage.
+ *
+ * Gets the #EomImage in the position @pos of @store. If there is
+ * no image at position @pos, %NULL is returned.
+ *
+ * Returns: the #EomImage in position @pos or %NULL.
+ *
+ **/
+EomImage *
+eom_list_store_get_image_by_pos (EomListStore *store, gint pos)
+{
+ EomImage *image = NULL;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (EOM_IS_LIST_STORE (store), NULL);
+
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, NULL, pos)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+ }
+
+ return image;
+}
+
+/**
+ * eom_list_store_get_pos_by_iter:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Gets the position of the image pointed by @iter.
+ *
+ * Returns: The position of the image pointed by @iter.
+ **/
+gint
+eom_list_store_get_pos_by_iter (EomListStore *store,
+ GtkTreeIter *iter)
+{
+ gint *indices;
+ GtkTreePath *path;
+ gint pos;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+ indices = gtk_tree_path_get_indices (path);
+ pos = indices [0];
+ gtk_tree_path_free (path);
+
+ return pos;
+}
+
+/**
+ * eom_list_store_length:
+ * @store: An #EomListStore.
+ *
+ * Returns the number of images in the store.
+ *
+ * Returns: The number of images in @store.
+ **/
+gint
+eom_list_store_length (EomListStore *store)
+{
+ g_return_val_if_fail (EOM_IS_LIST_STORE (store), -1);
+
+ return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+}
+
+/**
+ * eom_list_store_get_initial_pos:
+ * @store: An #EomListStore.
+ *
+ * Gets the position of the #EomImage that should be loaded first.
+ * If not set, it returns -1.
+ *
+ * Returns: the position of the image to be loaded first or -1.
+ *
+ **/
+gint
+eom_list_store_get_initial_pos (EomListStore *store)
+{
+ g_return_val_if_fail (EOM_IS_LIST_STORE (store), -1);
+
+ return store->priv->initial_image;
+}
+
+static void
+eom_list_store_remove_thumbnail_job (EomListStore *store,
+ GtkTreeIter *iter)
+{
+ EomJob *job;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ EOM_LIST_STORE_EOM_JOB, &job,
+ -1);
+
+ if (job != NULL) {
+ g_mutex_lock (store->priv->mutex);
+ eom_job_queue_remove_job (job);
+ gtk_list_store_set (GTK_LIST_STORE (store), iter,
+ EOM_LIST_STORE_EOM_JOB, NULL,
+ -1);
+ g_mutex_unlock (store->priv->mutex);
+ }
+
+
+}
+
+static void
+eom_list_store_add_thumbnail_job (EomListStore *store, GtkTreeIter *iter)
+{
+ EomImage *image;
+ EomJob *job;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ EOM_LIST_STORE_EOM_JOB, &job,
+ -1);
+
+ if (job != NULL) {
+ g_object_unref (image);
+ return;
+ }
+
+ job = eom_job_thumbnail_new (image);
+
+ g_signal_connect (job,
+ "finished",
+ G_CALLBACK (eom_job_thumbnail_cb),
+ store);
+
+ g_mutex_lock (store->priv->mutex);
+ gtk_list_store_set (GTK_LIST_STORE (store), iter,
+ EOM_LIST_STORE_EOM_JOB, job,
+ -1);
+ eom_job_queue_add_job (job);
+ g_mutex_unlock (store->priv->mutex);
+ g_object_unref (job);
+ g_object_unref (image);
+}
+
+/**
+ * eom_list_store_thumbnail_set:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Sets the thumbnail for the image pointed by @iter.
+ *
+ **/
+void
+eom_list_store_thumbnail_set (EomListStore *store,
+ GtkTreeIter *iter)
+{
+ gboolean thumb_set = FALSE;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ EOM_LIST_STORE_THUMB_SET, &thumb_set,
+ -1);
+
+ if (thumb_set) {
+ return;
+ }
+
+ eom_list_store_add_thumbnail_job (store, iter);
+}
+
+/**
+ * eom_list_store_thumbnail_unset:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Unsets the thumbnail for the image pointed by @iter, changing
+ * it to a "busy" icon.
+ *
+ **/
+void
+eom_list_store_thumbnail_unset (EomListStore *store,
+ GtkTreeIter *iter)
+{
+ EomImage *image;
+
+ eom_list_store_remove_thumbnail_job (store, iter);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+ EOM_LIST_STORE_EOM_IMAGE, &image,
+ -1);
+ eom_image_set_thumbnail (image, NULL);
+ g_object_unref (image);
+
+ gtk_list_store_set (GTK_LIST_STORE (store), iter,
+ EOM_LIST_STORE_THUMBNAIL, store->priv->busy_image,
+ EOM_LIST_STORE_THUMB_SET, FALSE,
+ -1);
+}
+
+/**
+ * eom_list_store_thumbnail_refresh:
+ * @store: An #EomListStore.
+ * @iter: A #GtkTreeIter pointing to an image in @store.
+ *
+ * Refreshes the thumbnail for the image pointed by @iter.
+ *
+ **/
+void
+eom_list_store_thumbnail_refresh (EomListStore *store,
+ GtkTreeIter *iter)
+{
+ eom_list_store_remove_thumbnail_job (store, iter);
+ eom_list_store_add_thumbnail_job (store, iter);
+}
diff --git a/src/eom-list-store.h b/src/eom-list-store.h
new file mode 100644
index 0000000..f603e53
--- /dev/null
+++ b/src/eom-list-store.h
@@ -0,0 +1,113 @@
+/* Eye Of Mate - Image Store
+ *
+ * Copyright (C) 2006-2007 The Free Software Foundation
+ *
+ * Author: Claudio Saavedra <[email protected]>
+ *
+ * Based on code by: Jens Finke <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EOM_LIST_STORE_H
+#define EOM_LIST_STORE_H
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#ifndef __EOM_IMAGE_DECLR__
+#define __EOM_IMAGE_DECLR__
+ typedef struct _EomImage EomImage;
+#endif
+
+typedef struct _EomListStore EomListStore;
+typedef struct _EomListStoreClass EomListStoreClass;
+typedef struct _EomListStorePrivate EomListStorePrivate;
+
+#define EOM_TYPE_LIST_STORE eom_list_store_get_type()
+#define EOM_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_LIST_STORE, EomListStore))
+#define EOM_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EOM_TYPE_LIST_STORE, EomListStoreClass))
+#define EOM_IS_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_LIST_STORE))
+#define EOM_IS_LIST_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_LIST_STORE))
+#define EOM_LIST_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_LIST_STORE, EomListStoreClass))
+
+#define EOM_LIST_STORE_THUMB_SIZE 90
+
+typedef enum {
+ EOM_LIST_STORE_THUMBNAIL = 0,
+ EOM_LIST_STORE_THUMB_SET,
+ EOM_LIST_STORE_EOM_IMAGE,
+ EOM_LIST_STORE_EOM_JOB,
+ EOM_LIST_STORE_NUM_COLUMNS
+} EomListStoreColumn;
+
+struct _EomListStore {
+ GtkListStore parent;
+ EomListStorePrivate *priv;
+};
+
+struct _EomListStoreClass {
+ GtkListStoreClass parent_class;
+
+ /* Padding for future expansion */
+ void (* _eom_reserved1) (void);
+ void (* _eom_reserved2) (void);
+ void (* _eom_reserved3) (void);
+ void (* _eom_reserved4) (void);
+};
+
+GType eom_list_store_get_type (void) G_GNUC_CONST;
+
+GtkListStore *eom_list_store_new (void);
+
+GtkListStore *eom_list_store_new_from_glist (GList *list);
+
+void eom_list_store_append_image (EomListStore *store,
+ EomImage *image);
+
+void eom_list_store_add_files (EomListStore *store,
+ GList *file_list);
+
+void eom_list_store_remove_image (EomListStore *store,
+ EomImage *image);
+
+gint eom_list_store_get_pos_by_image (EomListStore *store,
+ EomImage *image);
+
+EomImage *eom_list_store_get_image_by_pos (EomListStore *store,
+ gint pos);
+
+gint eom_list_store_get_pos_by_iter (EomListStore *store,
+ GtkTreeIter *iter);
+
+gint eom_list_store_length (EomListStore *store);
+
+gint eom_list_store_get_initial_pos (EomListStore *store);
+
+void eom_list_store_thumbnail_set (EomListStore *store,
+ GtkTreeIter *iter);
+
+void eom_list_store_thumbnail_unset (EomListStore *store,
+ GtkTreeIter *iter);
+
+void eom_list_store_thumbnail_refresh (EomListStore *store,
+ GtkTreeIter *iter);
+
+G_END_DECLS
+
+#endif
diff --git a/src/eom-marshal.list b/src/eom-marshal.list
new file mode 100644
index 0000000..1a117a6
--- /dev/null
+++ b/src/eom-marshal.list
@@ -0,0 +1,2 @@
+VOID:INT,INT
+VOID:DOUBLE
diff --git a/src/eom-metadata-reader-jpg.c b/src/eom-metadata-reader-jpg.c
new file mode 100644
index 0000000..788d2d3
--- /dev/null
+++ b/src/eom-metadata-reader-jpg.c
@@ -0,0 +1,673 @@
+/* Eye Of MATE -- JPEG Metadata Reader
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <[email protected]>
+ *
+ * Based on the original EomMetadataReader code.
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "eom-metadata-reader.h"
+#include "eom-metadata-reader-jpg.h"
+#include "eom-debug.h"
+
+typedef enum {
+ EMR_READ = 0,
+ EMR_READ_SIZE_HIGH_BYTE,
+ EMR_READ_SIZE_LOW_BYTE,
+ EMR_READ_MARKER,
+ EMR_SKIP_BYTES,
+ EMR_READ_APP1,
+ EMR_READ_EXIF,
+ EMR_READ_XMP,
+ EMR_READ_ICC,
+ EMR_READ_IPTC,
+ EMR_FINISHED
+} EomMetadataReaderState;
+
+typedef enum {
+ EJA_EXIF = 0,
+ EJA_XMP,
+ EJA_OTHER
+} EomJpegApp1Type;
+
+
+#define EOM_JPEG_MARKER_START 0xFF
+#define EOM_JPEG_MARKER_SOI 0xD8
+#define EOM_JPEG_MARKER_APP1 0xE1
+#define EOM_JPEG_MARKER_APP2 0xE2
+#define EOM_JPEG_MARKER_APP14 0xED
+
+#define IS_FINISHED(priv) (priv->state == EMR_READ && \
+ priv->exif_chunk != NULL && \
+ priv->icc_chunk != NULL && \
+ priv->iptc_chunk != NULL && \
+ priv->xmp_chunk != NULL)
+
+struct _EomMetadataReaderJpgPrivate {
+ EomMetadataReaderState state;
+
+ /* data fields */
+ guint exif_len;
+ gpointer exif_chunk;
+
+ gpointer iptc_chunk;
+ guint iptc_len;
+
+ guint icc_len;
+ gpointer icc_chunk;
+
+ gpointer xmp_chunk;
+ guint xmp_len;
+
+ /* management fields */
+ int size;
+ int last_marker;
+ int bytes_read;
+};
+
+#define EOM_METADATA_READER_JPG_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_METADATA_READER_JPG, EomMetadataReaderJpgPrivate))
+
+static void
+eom_metadata_reader_jpg_init_emr_iface (gpointer g_iface, gpointer iface_data);
+
+
+G_DEFINE_TYPE_WITH_CODE (EomMetadataReaderJpg, eom_metadata_reader_jpg,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (EOM_TYPE_METADATA_READER,
+ eom_metadata_reader_jpg_init_emr_iface))
+
+
+static void
+eom_metadata_reader_jpg_dispose (GObject *object)
+{
+ EomMetadataReaderJpg *emr = EOM_METADATA_READER_JPG (object);
+
+ if (emr->priv->exif_chunk != NULL) {
+ g_free (emr->priv->exif_chunk);
+ emr->priv->exif_chunk = NULL;
+ }
+
+ if (emr->priv->iptc_chunk != NULL) {
+ g_free (emr->priv->iptc_chunk);
+ emr->priv->iptc_chunk = NULL;
+ }
+
+ if (emr->priv->xmp_chunk != NULL) {
+ g_free (emr->priv->xmp_chunk);
+ emr->priv->xmp_chunk = NULL;
+ }
+
+ if (emr->priv->icc_chunk != NULL) {
+ g_free (emr->priv->icc_chunk);
+ emr->priv->icc_chunk = NULL;
+ }
+
+ G_OBJECT_CLASS (eom_metadata_reader_jpg_parent_class)->dispose (object);
+}
+
+static void
+eom_metadata_reader_jpg_init (EomMetadataReaderJpg *obj)
+{
+ EomMetadataReaderJpgPrivate *priv;
+
+ priv = obj->priv = EOM_METADATA_READER_JPG_GET_PRIVATE (obj);
+ priv->exif_chunk = NULL;
+ priv->exif_len = 0;
+ priv->iptc_chunk = NULL;
+ priv->iptc_len = 0;
+ priv->icc_chunk = NULL;
+ priv->icc_len = 0;
+}
+
+static void
+eom_metadata_reader_jpg_class_init (EomMetadataReaderJpgClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eom_metadata_reader_jpg_dispose;
+
+ g_type_class_add_private (klass, sizeof (EomMetadataReaderJpgPrivate));
+}
+
+static gboolean
+eom_metadata_reader_jpg_finished (EomMetadataReaderJpg *emr)
+{
+ g_return_val_if_fail (EOM_IS_METADATA_READER_JPG (emr), TRUE);
+
+ return (emr->priv->state == EMR_FINISHED);
+}
+
+
+static EomJpegApp1Type
+eom_metadata_identify_app1 (gchar *buf, guint len)
+{
+ if (len < 5) {
+ return EJA_OTHER;
+ }
+
+ if (len < 29) {
+ return (strncmp ("Exif", buf, 5) == 0 ? EJA_EXIF : EJA_OTHER);
+ }
+
+ if (strncmp ("Exif", buf, 5) == 0) {
+ return EJA_EXIF;
+ } else if (strncmp ("http://ns.adobe.com/xap/1.0/", buf, 29) == 0) {
+ return EJA_XMP;
+ }
+
+ return EJA_OTHER;
+}
+
+static void
+eom_metadata_reader_get_next_block (EomMetadataReaderJpgPrivate* priv,
+ guchar *chunk,
+ int* i,
+ const guchar *buf,
+ int len,
+ EomMetadataReaderState state)
+{
+ if (*i + priv->size < len) {
+ /* read data in one block */
+ memcpy ((guchar*) (chunk) + priv->bytes_read, &buf[*i], priv->size);
+ priv->state = EMR_READ;
+ *i = *i + priv->size - 1; /* the for-loop consumes the other byte */
+ } else {
+ int chunk_len = len - *i;
+ memcpy ((guchar*) (chunk) + priv->bytes_read, &buf[*i], chunk_len);
+ priv->bytes_read += chunk_len; /* bytes already read */
+ priv->size = (*i + priv->size) - len; /* remaining data to read */
+ *i = len - 1;
+ priv->state = state;
+ }
+}
+
+static void
+eom_metadata_reader_jpg_consume (EomMetadataReaderJpg *emr, const guchar *buf, guint len)
+{
+ EomMetadataReaderJpgPrivate *priv;
+ EomJpegApp1Type app1_type;
+ int i;
+ EomMetadataReaderState next_state = EMR_READ;
+ guchar *chunk = NULL;
+
+ g_return_if_fail (EOM_IS_METADATA_READER_JPG (emr));
+
+ priv = emr->priv;
+
+ if (priv->state == EMR_FINISHED) return;
+
+ for (i = 0; (i < len) && (priv->state != EMR_FINISHED); i++) {
+
+ switch (priv->state) {
+ case EMR_READ:
+ if (buf[i] == EOM_JPEG_MARKER_START) {
+ priv->state = EMR_READ_MARKER;
+ }
+ else {
+ priv->state = EMR_FINISHED;
+ }
+ break;
+
+ case EMR_READ_MARKER:
+ if ((buf [i] & 0xF0) == 0xE0 || buf[i] == 0xFE) {
+ /* we are reading some sort of APPxx or COM marker */
+ /* these are always followed by 2 bytes of size information */
+ priv->last_marker = buf [i];
+ priv->size = 0;
+ priv->state = EMR_READ_SIZE_HIGH_BYTE;
+
+ eom_debug_message (DEBUG_IMAGE_DATA, "APPx or COM Marker Found: %x", priv->last_marker);
+ }
+ else {
+ /* otherwise simply consume the byte */
+ priv->state = EMR_READ;
+ }
+ break;
+
+ case EMR_READ_SIZE_HIGH_BYTE:
+ priv->size = (buf [i] & 0xff) << 8;
+ priv->state = EMR_READ_SIZE_LOW_BYTE;
+ break;
+
+ case EMR_READ_SIZE_LOW_BYTE:
+ priv->size |= (buf [i] & 0xff);
+
+ if (priv->size > 2) /* ignore the two size-bytes */
+ priv->size -= 2;
+
+ if (priv->size == 0) {
+ priv->state = EMR_READ;
+ } else if (priv->last_marker == EOM_JPEG_MARKER_APP1 &&
+ ((priv->exif_chunk == NULL) || (priv->xmp_chunk == NULL)))
+ {
+ priv->state = EMR_READ_APP1;
+ } else if (priv->last_marker == EOM_JPEG_MARKER_APP2 &&
+ priv->icc_chunk == NULL && priv->size > 14)
+ {
+ /* Chunk has 14 bytes identification data */
+ priv->state = EMR_READ_ICC;
+ } else if (priv->last_marker == EOM_JPEG_MARKER_APP14 &&
+ priv->iptc_chunk == NULL)
+ {
+ priv->state = EMR_READ_IPTC;
+ } else {
+ priv->state = EMR_SKIP_BYTES;
+ }
+
+ priv->last_marker = 0;
+ break;
+
+ case EMR_SKIP_BYTES:
+ eom_debug_message (DEBUG_IMAGE_DATA, "Skip bytes: %i", priv->size);
+
+ if (i + priv->size < len) {
+ i = i + priv->size - 1; /* the for-loop consumes the other byte */
+ priv->size = 0;
+ }
+ else {
+ priv->size = (i + priv->size) - len;
+ i = len - 1;
+ }
+ if (priv->size == 0) { /* don't need to skip any more bytes */
+ priv->state = EMR_READ;
+ }
+ break;
+
+ case EMR_READ_APP1:
+ eom_debug_message (DEBUG_IMAGE_DATA, "Read APP1 data, Length: %i", priv->size);
+
+ app1_type = eom_metadata_identify_app1 ((gchar*) &buf[i], priv->size);
+
+ switch (app1_type) {
+ case EJA_EXIF:
+ if (priv->exif_chunk == NULL) {
+ priv->exif_chunk = g_new0 (guchar, priv->size);
+ priv->exif_len = priv->size;
+ priv->bytes_read = 0;
+ chunk = priv->exif_chunk;
+ next_state = EMR_READ_EXIF;
+ } else {
+ chunk = NULL;
+ priv->state = EMR_SKIP_BYTES;
+ }
+ break;
+ case EJA_XMP:
+ if (priv->xmp_chunk == NULL) {
+ priv->xmp_chunk = g_new0 (guchar, priv->size);
+ priv->xmp_len = priv->size;
+ priv->bytes_read = 0;
+ chunk = priv->xmp_chunk;
+ next_state = EMR_READ_XMP;
+ } else {
+ chunk = NULL;
+ priv->state = EMR_SKIP_BYTES;
+ }
+ break;
+ case EJA_OTHER:
+ default:
+ /* skip unknown data */
+ chunk = NULL;
+ priv->state = EMR_SKIP_BYTES;
+ break;
+ }
+
+ if (chunk) {
+ eom_metadata_reader_get_next_block (priv, chunk,
+ &i, buf,
+ len,
+ next_state);
+ }
+
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_EXIF:
+ eom_debug_message (DEBUG_IMAGE_DATA, "Read continuation of EXIF data, length: %i", priv->size);
+ {
+ eom_metadata_reader_get_next_block (priv, priv->exif_chunk,
+ &i, buf, len, EMR_READ_EXIF);
+ }
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_XMP:
+ eom_debug_message (DEBUG_IMAGE_DATA, "Read continuation of XMP data, length: %i", priv->size);
+ {
+ eom_metadata_reader_get_next_block (priv, priv->xmp_chunk,
+ &i, buf, len, EMR_READ_XMP);
+ }
+ if (IS_FINISHED (priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_ICC:
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read continuation of ICC data, "
+ "length: %i", priv->size);
+
+ if (priv->icc_chunk == NULL) {
+ priv->icc_chunk = g_new0 (guchar, priv->size);
+ priv->icc_len = priv->size;
+ priv->bytes_read = 0;
+ }
+
+ eom_metadata_reader_get_next_block (priv,
+ priv->icc_chunk,
+ &i, buf, len,
+ EMR_READ_ICC);
+
+ /* Test that the chunk actually contains ICC data. */
+ if (priv->state == EMR_READ && priv->icc_chunk) {
+ const char* icc_chunk = priv->icc_chunk;
+ gboolean valid = TRUE;
+
+ /* Chunk should begin with the
+ * ICC_PROFILE\0 identifier */
+ valid &= strncmp (icc_chunk,
+ "ICC_PROFILE\0",12) == 0;
+ /* Make sure this is the first and only
+ * ICC chunk in the file as we don't
+ * support merging chunks yet. */
+ valid &= *(guint16*)(icc_chunk+12) == 0x101;
+
+ if (!valid) {
+ /* This no ICC data. Throw it away. */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Supposed ICC chunk didn't validate. "
+ "Ignoring.");
+ g_free (priv->icc_chunk);
+ priv->icc_chunk = NULL;
+ priv->icc_len = 0;
+ }
+ }
+
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_IPTC:
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read continuation of IPTC data, "
+ "length: %i", priv->size);
+
+ if (priv->iptc_chunk == NULL) {
+ priv->iptc_chunk = g_new0 (guchar, priv->size);
+ priv->iptc_len = priv->size;
+ priv->bytes_read = 0;
+ }
+
+ eom_metadata_reader_get_next_block (priv,
+ priv->iptc_chunk,
+ &i, buf, len,
+ EMR_READ_IPTC);
+
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+ }
+}
+
+/* Returns the raw exif data. NOTE: The caller of this function becomes
+ * the new owner of this piece of memory and is responsible for freeing it!
+ */
+static void
+eom_metadata_reader_jpg_get_exif_chunk (EomMetadataReaderJpg *emr, guchar **data, guint *len)
+{
+ EomMetadataReaderJpgPrivate *priv;
+
+ g_return_if_fail (EOM_IS_METADATA_READER (emr));
+ priv = emr->priv;
+
+ *data = (guchar*) priv->exif_chunk;
+ *len = priv->exif_len;
+
+ priv->exif_chunk = NULL;
+ priv->exif_len = 0;
+}
+
+#ifdef HAVE_EXIF
+static gpointer
+eom_metadata_reader_jpg_get_exif_data (EomMetadataReaderJpg *emr)
+{
+ EomMetadataReaderJpgPrivate *priv;
+ ExifData *data = NULL;
+
+ g_return_val_if_fail (EOM_IS_METADATA_READER (emr), NULL);
+ priv = emr->priv;
+
+ if (priv->exif_chunk != NULL) {
+ data = exif_data_new_from_data (priv->exif_chunk, priv->exif_len);
+ }
+
+ return data;
+}
+#endif
+
+
+#ifdef HAVE_EXEMPI
+
+/* skip the signature */
+#define EOM_XMP_OFFSET (29)
+
+static gpointer
+eom_metadata_reader_jpg_get_xmp_data (EomMetadataReaderJpg *emr )
+{
+ EomMetadataReaderJpgPrivate *priv;
+ XmpPtr xmp = NULL;
+
+ g_return_val_if_fail (EOM_IS_METADATA_READER (emr), NULL);
+
+ priv = emr->priv;
+
+ if (priv->xmp_chunk != NULL) {
+ xmp = xmp_new (priv->xmp_chunk+EOM_XMP_OFFSET,
+ priv->xmp_len-EOM_XMP_OFFSET);
+ }
+
+ return (gpointer)xmp;
+}
+#endif
+
+/*
+ * FIXME: very broken, assumes the profile fits in a single chunk. Change to
+ * parse the sections and construct a single memory chunk, or maybe even parse
+ * the profile.
+ */
+#ifdef HAVE_LCMS
+static gpointer
+eom_metadata_reader_jpg_get_icc_profile (EomMetadataReaderJpg *emr)
+{
+ EomMetadataReaderJpgPrivate *priv;
+ cmsHPROFILE profile = NULL;
+
+ g_return_val_if_fail (EOM_IS_METADATA_READER (emr), NULL);
+
+ priv = emr->priv;
+
+ if (priv->icc_chunk) {
+ cmsErrorAction (LCMS_ERROR_SHOW);
+
+ profile = cmsOpenProfileFromMem(priv->icc_chunk + 14, priv->icc_len - 14);
+
+ if (profile) {
+ eom_debug_message (DEBUG_LCMS, "JPEG has ICC profile");
+ } else {
+ eom_debug_message (DEBUG_LCMS, "JPEG has invalid ICC profile");
+ }
+ }
+
+#ifdef HAVE_EXIF
+ if (!profile && priv->exif_chunk != NULL) {
+ ExifEntry *entry;
+ ExifByteOrder o;
+ gint color_space;
+ ExifData *exif = eom_metadata_reader_jpg_get_exif_data (emr);
+
+ if (!exif) return NULL;
+
+ o = exif_data_get_byte_order (exif);
+
+ entry = exif_data_get_entry (exif, EXIF_TAG_COLOR_SPACE);
+
+ if (entry == NULL) {
+ exif_data_unref (exif);
+ return NULL;
+ }
+
+ color_space = exif_get_short (entry->data, o);
+
+ switch (color_space) {
+ case 1:
+ eom_debug_message (DEBUG_LCMS, "JPEG is sRGB");
+
+ profile = cmsCreate_sRGBProfile ();
+
+ break;
+ case 2:
+ eom_debug_message (DEBUG_LCMS, "JPEG is Adobe RGB (Disabled)");
+
+ /* TODO: create Adobe RGB profile */
+ //profile = cmsCreate_Adobe1998Profile ();
+
+ break;
+ case 0xFFFF:
+ {
+ cmsCIExyY whitepoint;
+ cmsCIExyYTRIPLE primaries;
+ LPGAMMATABLE gamma[3];
+ double gammaValue;
+ ExifRational r;
+
+ const int offset = exif_format_get_size (EXIF_FORMAT_RATIONAL);
+
+ entry = exif_data_get_entry (exif, EXIF_TAG_WHITE_POINT);
+
+ if (entry && entry->components == 2) {
+ r = exif_get_rational (entry->data, o);
+ whitepoint.x = (double) r.numerator / r.denominator;
+
+ r = exif_get_rational (entry->data + offset, o);
+ whitepoint.y = (double) r.numerator / r.denominator;
+ whitepoint.Y = 1.0;
+ } else {
+ eom_debug_message (DEBUG_LCMS, "No whitepoint found");
+ break;
+ }
+
+ entry = exif_data_get_entry (exif, EXIF_TAG_PRIMARY_CHROMATICITIES);
+
+ if (entry && entry->components == 6) {
+ r = exif_get_rational (entry->data + 0 * offset, o);
+ primaries.Red.x = (double) r.numerator / r.denominator;
+
+ r = exif_get_rational (entry->data + 1 * offset, o);
+ primaries.Red.y = (double) r.numerator / r.denominator;
+
+ r = exif_get_rational (entry->data + 2 * offset, o);
+ primaries.Green.x = (double) r.numerator / r.denominator;
+
+ r = exif_get_rational (entry->data + 3 * offset, o);
+ primaries.Green.y = (double) r.numerator / r.denominator;
+
+ r = exif_get_rational (entry->data + 4 * offset, o);
+ primaries.Blue.x = (double) r.numerator / r.denominator;
+
+ r = exif_get_rational (entry->data + 5 * offset, o);
+ primaries.Blue.y = (double) r.numerator / r.denominator;
+
+ primaries.Red.Y = primaries.Green.Y = primaries.Blue.Y = 1.0;
+ } else {
+ eom_debug_message (DEBUG_LCMS, "No primary chromaticities found");
+ break;
+ }
+
+ entry = exif_data_get_entry (exif, EXIF_TAG_GAMMA);
+
+ if (entry) {
+ r = exif_get_rational (entry->data, o);
+ gammaValue = (double) r.numerator / r.denominator;
+ } else {
+ eom_debug_message (DEBUG_LCMS, "No gamma found");
+ gammaValue = 2.2;
+ }
+
+ gamma[0] = gamma[1] = gamma[2] = cmsBuildGamma (256, gammaValue);
+
+ profile = cmsCreateRGBProfile (&whitepoint, &primaries, gamma);
+
+ cmsFreeGamma(gamma[0]);
+
+ eom_debug_message (DEBUG_LCMS, "JPEG is calibrated");
+
+ break;
+ }
+ }
+
+ exif_data_unref (exif);
+ }
+#endif
+ return profile;
+}
+#endif
+
+static void
+eom_metadata_reader_jpg_init_emr_iface (gpointer g_iface, gpointer iface_data)
+{
+ EomMetadataReaderInterface *iface;
+
+ iface = (EomMetadataReaderInterface*)g_iface;
+
+ iface->consume =
+ (void (*) (EomMetadataReader *self, const guchar *buf, guint len))
+ eom_metadata_reader_jpg_consume;
+ iface->finished =
+ (gboolean (*) (EomMetadataReader *self))
+ eom_metadata_reader_jpg_finished;
+ iface->get_raw_exif =
+ (void (*) (EomMetadataReader *self, guchar **data, guint *len))
+ eom_metadata_reader_jpg_get_exif_chunk;
+#ifdef HAVE_EXIF
+ iface->get_exif_data =
+ (gpointer (*) (EomMetadataReader *self))
+ eom_metadata_reader_jpg_get_exif_data;
+#endif
+#ifdef HAVE_LCMS
+ iface->get_icc_profile =
+ (gpointer (*) (EomMetadataReader *self))
+ eom_metadata_reader_jpg_get_icc_profile;
+#endif
+#ifdef HAVE_EXEMPI
+ iface->get_xmp_ptr =
+ (gpointer (*) (EomMetadataReader *self))
+ eom_metadata_reader_jpg_get_xmp_data;
+#endif
+}
+
diff --git a/src/eom-metadata-reader-jpg.h b/src/eom-metadata-reader-jpg.h
new file mode 100644
index 0000000..722a720
--- /dev/null
+++ b/src/eom-metadata-reader-jpg.h
@@ -0,0 +1,55 @@
+/* Eye Of MATE -- JPEG Metadata Reader
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <[email protected]>
+ *
+ * Based on the original EomMetadataReader code.
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _EOM_METADATA_READER_JPG_H_
+#define _EOM_METADATA_READER_JPG_H_
+
+G_BEGIN_DECLS
+
+#define EOM_TYPE_METADATA_READER_JPG (eom_metadata_reader_jpg_get_type ())
+#define EOM_METADATA_READER_JPG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),EOM_TYPE_METADATA_READER_JPG, EomMetadataReaderJpg))
+#define EOM_METADATA_READER_JPG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EOM_TYPE_METADATA_READER_JPG, EomMetadataReaderJpgClass))
+#define EOM_IS_METADATA_READER_JPG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOM_TYPE_METADATA_READER_JPG))
+#define EOM_IS_METADATA_READER_JPG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EOM_TYPE_METADATA_READER_JPG))
+#define EOM_METADATA_READER_JPG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EOM_TYPE_METADATA_READER_JPG, EomMetadataReaderJpgClass))
+
+typedef struct _EomMetadataReaderJpg EomMetadataReaderJpg;
+typedef struct _EomMetadataReaderJpgClass EomMetadataReaderJpgClass;
+typedef struct _EomMetadataReaderJpgPrivate EomMetadataReaderJpgPrivate;
+
+struct _EomMetadataReaderJpg {
+ GObject parent;
+
+ EomMetadataReaderJpgPrivate *priv;
+};
+
+struct _EomMetadataReaderJpgClass {
+ GObjectClass parent_klass;
+};
+
+G_GNUC_INTERNAL
+GType eom_metadata_reader_jpg_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* _EOM_METADATA_READER_JPG_H_ */
diff --git a/src/eom-metadata-reader-png.c b/src/eom-metadata-reader-png.c
new file mode 100644
index 0000000..2092f62
--- /dev/null
+++ b/src/eom-metadata-reader-png.c
@@ -0,0 +1,648 @@
+/* Eye Of MATE -- PNG Metadata Reader
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <[email protected]>
+ *
+ * Based on the old EomMetadataReader code.
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <zlib.h>
+
+#include "eom-metadata-reader.h"
+#include "eom-metadata-reader-png.h"
+#include "eom-debug.h"
+
+typedef enum {
+ EMR_READ_MAGIC,
+ EMR_READ_SIZE_HIGH_HIGH_BYTE,
+ EMR_READ_SIZE_HIGH_LOW_BYTE,
+ EMR_READ_SIZE_LOW_HIGH_BYTE,
+ EMR_READ_SIZE_LOW_LOW_BYTE,
+ EMR_READ_CHUNK_NAME,
+ EMR_SKIP_BYTES,
+ EMR_CHECK_CRC,
+ EMR_SKIP_CRC,
+ EMR_READ_XMP_ITXT,
+ EMR_READ_ICCP,
+ EMR_READ_SRGB,
+ EMR_READ_CHRM,
+ EMR_READ_GAMA,
+ EMR_FINISHED
+} EomMetadataReaderPngState;
+
+#if 0
+#define IS_FINISHED(priv) (priv->icc_chunk != NULL && \
+ priv->xmp_chunk != NULL)
+#endif
+
+struct _EomMetadataReaderPngPrivate {
+ EomMetadataReaderPngState state;
+
+ /* data fields */
+ guint32 icc_len;
+ gpointer icc_chunk;
+
+ gpointer xmp_chunk;
+ guint32 xmp_len;
+
+ guint32 sRGB_len;
+ gpointer sRGB_chunk;
+
+ gpointer cHRM_chunk;
+ guint32 cHRM_len;
+
+ guint32 gAMA_len;
+ gpointer gAMA_chunk;
+
+ /* management fields */
+ gsize size;
+ gsize bytes_read;
+ guint sub_step;
+ guchar chunk_name[4];
+ gpointer *crc_chunk;
+ guint32 *crc_len;
+ guint32 target_crc;
+ gboolean hasIHDR;
+};
+
+#define EOM_METADATA_READER_PNG_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_METADATA_READER_PNG, EomMetadataReaderPngPrivate))
+
+static void
+eom_metadata_reader_png_init_emr_iface (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (EomMetadataReaderPng, eom_metadata_reader_png,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (EOM_TYPE_METADATA_READER,
+ eom_metadata_reader_png_init_emr_iface))
+
+static void
+eom_metadata_reader_png_dispose (GObject *object)
+{
+ EomMetadataReaderPng *emr = EOM_METADATA_READER_PNG (object);
+ EomMetadataReaderPngPrivate *priv = emr->priv;
+
+ g_free (priv->xmp_chunk);
+ priv->xmp_chunk = NULL;
+
+ g_free (priv->icc_chunk);
+ priv->icc_chunk = NULL;
+
+ g_free (priv->sRGB_chunk);
+ priv->sRGB_chunk = NULL;
+
+ g_free (priv->cHRM_chunk);
+ priv->cHRM_chunk = NULL;
+
+ g_free (priv->gAMA_chunk);
+ priv->gAMA_chunk = NULL;
+
+ G_OBJECT_CLASS (eom_metadata_reader_png_parent_class)->dispose (object);
+}
+
+static void
+eom_metadata_reader_png_init (EomMetadataReaderPng *obj)
+{
+ EomMetadataReaderPngPrivate *priv;
+
+ priv = obj->priv = EOM_METADATA_READER_PNG_GET_PRIVATE (obj);
+ priv->icc_chunk = NULL;
+ priv->icc_len = 0;
+ priv->xmp_chunk = NULL;
+ priv->xmp_len = 0;
+ priv->sRGB_chunk = NULL;
+ priv->sRGB_len = 0;
+ priv->cHRM_chunk = NULL;
+ priv->cHRM_len = 0;
+ priv->gAMA_chunk = NULL;
+ priv->gAMA_len = 0;
+
+ priv->sub_step = 0;
+ priv->state = EMR_READ_MAGIC;
+ priv->hasIHDR = FALSE;
+}
+
+static void
+eom_metadata_reader_png_class_init (EomMetadataReaderPngClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eom_metadata_reader_png_dispose;
+
+ g_type_class_add_private (klass, sizeof (EomMetadataReaderPngPrivate));
+}
+
+static gboolean
+eom_metadata_reader_png_finished (EomMetadataReaderPng *emr)
+{
+ g_return_val_if_fail (EOM_IS_METADATA_READER_PNG (emr), TRUE);
+
+ return (emr->priv->state == EMR_FINISHED);
+}
+
+
+static void
+eom_metadata_reader_png_get_next_block (EomMetadataReaderPngPrivate* priv,
+ guchar *chunk,
+ int* i,
+ const guchar *buf,
+ int len,
+ EomMetadataReaderPngState state)
+{
+ if (*i + priv->size < len) {
+ /* read data in one block */
+ memcpy ((guchar*) (chunk) + priv->bytes_read, &buf[*i], priv->size);
+ priv->state = EMR_CHECK_CRC;
+ *i = *i + priv->size - 1; /* the for-loop consumes the other byte */
+ priv->size = 0;
+ } else {
+ int chunk_len = len - *i;
+ memcpy ((guchar*) (chunk) + priv->bytes_read, &buf[*i], chunk_len);
+ priv->bytes_read += chunk_len; /* bytes already read */
+ priv->size = (*i + priv->size) - len; /* remaining data to read */
+ *i = len - 1;
+ priv->state = state;
+ }
+}
+
+static void
+eom_metadata_reader_png_consume (EomMetadataReaderPng *emr, const guchar *buf, guint len)
+{
+ EomMetadataReaderPngPrivate *priv;
+ int i;
+ guint32 chunk_crc;
+ static const gchar PNGMAGIC[8] = "\x89PNG\x0D\x0A\x1a\x0A";
+
+ g_return_if_fail (EOM_IS_METADATA_READER_PNG (emr));
+
+ priv = emr->priv;
+
+ if (priv->state == EMR_FINISHED) return;
+
+ for (i = 0; (i < len) && (priv->state != EMR_FINISHED); i++) {
+
+ switch (priv->state) {
+ case EMR_READ_MAGIC:
+ /* Check PNG magic string */
+ if (priv->sub_step < 8 &&
+ (gchar)buf[i] == PNGMAGIC[priv->sub_step]) {
+ if (priv->sub_step == 7)
+ priv->state = EMR_READ_SIZE_HIGH_HIGH_BYTE;
+ priv->sub_step++;
+ } else {
+ priv->state = EMR_FINISHED;
+ }
+ break;
+ case EMR_READ_SIZE_HIGH_HIGH_BYTE:
+ /* Read the high byte of the size's high word */
+ priv->size |= (buf[i] & 0xFF) << 24;
+ priv->state = EMR_READ_SIZE_HIGH_LOW_BYTE;
+ break;
+ case EMR_READ_SIZE_HIGH_LOW_BYTE:
+ /* Read the low byte of the size's high word */
+ priv->size |= (buf[i] & 0xFF) << 16;
+ priv->state = EMR_READ_SIZE_LOW_HIGH_BYTE;
+ break;
+ case EMR_READ_SIZE_LOW_HIGH_BYTE:
+ /* Read the high byte of the size's low word */
+ priv->size |= (buf [i] & 0xff) << 8;
+ priv->state = EMR_READ_SIZE_LOW_LOW_BYTE;
+ break;
+ case EMR_READ_SIZE_LOW_LOW_BYTE:
+ /* Read the high byte of the size's low word */
+ priv->size |= (buf [i] & 0xff);
+ /* The maximum chunk length is 2^31-1 */
+ if (G_LIKELY (priv->size <= (guint32) 0x7fffffff)) {
+ priv->state = EMR_READ_CHUNK_NAME;
+ /* Make sure sub_step is 0 before next step */
+ priv->sub_step = 0;
+ } else {
+ priv->state = EMR_FINISHED;
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "chunk size larger than "
+ "2^31-1; stopping parser");
+ }
+
+ break;
+ case EMR_READ_CHUNK_NAME:
+ /* Read the 4-byte chunk name */
+ if (priv->sub_step > 3)
+ g_assert_not_reached ();
+
+ priv->chunk_name[priv->sub_step] = buf[i];
+
+ if (priv->sub_step++ != 3)
+ break;
+
+ if (G_UNLIKELY (!priv->hasIHDR)) {
+ /* IHDR should be the first chunk in a PNG */
+ if (priv->size == 13
+ && memcmp (priv->chunk_name, "IHDR", 4) == 0){
+ priv->hasIHDR = TRUE;
+ } else {
+ /* Stop parsing if it is not */
+ priv->state = EMR_FINISHED;
+ }
+ }
+
+ /* Try to identify the chunk by its name.
+ * Already do some sanity checks where possible */
+ if (memcmp (priv->chunk_name, "iTXt", 4) == 0 &&
+ priv->size > (22 + 54) && priv->xmp_chunk == NULL) {
+ priv->state = EMR_READ_XMP_ITXT;
+ } else if (memcmp (priv->chunk_name, "iCCP", 4) == 0 &&
+ priv->icc_chunk == NULL) {
+ priv->state = EMR_READ_ICCP;
+ } else if (memcmp (priv->chunk_name, "sRGB", 4) == 0 &&
+ priv->sRGB_chunk == NULL && priv->size == 1) {
+ priv->state = EMR_READ_SRGB;
+ } else if (memcmp (priv->chunk_name, "cHRM", 4) == 0 &&
+ priv->cHRM_chunk == NULL && priv->size == 32) {
+ priv->state = EMR_READ_CHRM;
+ } else if (memcmp (priv->chunk_name, "gAMA", 4) == 0 &&
+ priv->gAMA_chunk == NULL && priv->size == 4) {
+ priv->state = EMR_READ_GAMA;
+ } else if (memcmp (priv->chunk_name, "IEND", 4) == 0) {
+ priv->state = EMR_FINISHED;
+ } else {
+ /* Skip chunk + 4-byte CRC32 value */
+ priv->size += 4;
+ priv->state = EMR_SKIP_BYTES;
+ }
+ priv->sub_step = 0;
+ break;
+ case EMR_SKIP_CRC:
+ /* Skip the 4-byte CRC32 value following every chunk */
+ priv->size = 4;
+ case EMR_SKIP_BYTES:
+ /* Skip chunk and start reading the size of the next one */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Skip bytes: %" G_GSIZE_FORMAT,
+ priv->size);
+
+ if (i + priv->size < len) {
+ i = i + priv->size - 1; /* the for-loop consumes the other byte */
+ priv->size = 0;
+ priv->state = EMR_READ_SIZE_HIGH_HIGH_BYTE;
+ }
+ else {
+ priv->size = (i + priv->size) - len;
+ i = len - 1;
+ }
+ break;
+ case EMR_CHECK_CRC:
+ /* Read the chunks CRC32 value from the file,... */
+ if (priv->sub_step == 0)
+ priv->target_crc = 0;
+
+ priv->target_crc |= buf[i] << ((3 - priv->sub_step) * 8);
+
+ if (priv->sub_step++ != 3)
+ break;
+
+ /* ...generate the chunks CRC32,... */
+ chunk_crc = crc32 (crc32 (0L, Z_NULL, 0), priv->chunk_name, 4);
+ chunk_crc = crc32 (chunk_crc, *priv->crc_chunk, *priv->crc_len);
+
+ eom_debug_message (DEBUG_IMAGE_DATA, "Checking CRC: Chunk: 0x%X - Target: 0x%X", chunk_crc, priv->target_crc);
+
+ /* ...and check if they match. If they don't throw
+ * the chunk away and stop parsing. */
+ if (priv->target_crc == chunk_crc) {
+ priv->state = EMR_READ_SIZE_HIGH_HIGH_BYTE;
+ } else {
+ g_free (*priv->crc_chunk);
+ *priv->crc_chunk = NULL;
+ *priv->crc_len = 0;
+ /* Stop parsing for security reasons */
+ priv->state = EMR_FINISHED;
+ }
+ priv->sub_step = 0;
+ break;
+ case EMR_READ_XMP_ITXT:
+ /* Extract an iTXt chunk possibly containing
+ * an XMP packet */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read XMP Chunk - size: %"
+ G_GSIZE_FORMAT, priv->size);
+
+ if (priv->xmp_chunk == NULL) {
+ priv->xmp_chunk = g_new0 (guchar, priv->size);
+ priv->xmp_len = priv->size;
+ priv->crc_len = &priv->xmp_len;
+ priv->bytes_read = 0;
+ priv->crc_chunk = &priv->xmp_chunk;
+ }
+ eom_metadata_reader_png_get_next_block (priv,
+ priv->xmp_chunk,
+ &i, buf, len,
+ EMR_READ_XMP_ITXT);
+
+ if (priv->state == EMR_CHECK_CRC) {
+ /* Check if it is actually an XMP chunk.
+ * Throw it away if not.
+ * The check has 4 extra \0's to check
+ * if the chunk is configured correctly. */
+ if (memcmp (priv->xmp_chunk, "XML:com.adobe.xmp\0\0\0\0\0", 22) != 0) {
+ priv->state = EMR_SKIP_CRC;
+ g_free (priv->xmp_chunk);
+ priv->xmp_chunk = NULL;
+ priv->xmp_len = 0;
+ }
+ }
+ break;
+ case EMR_READ_ICCP:
+ /* Extract an iCCP chunk containing a
+ * deflated ICC profile. */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read ICC Chunk - size: %"
+ G_GSIZE_FORMAT, priv->size);
+
+ if (priv->icc_chunk == NULL) {
+ priv->icc_chunk = g_new0 (guchar, priv->size);
+ priv->icc_len = priv->size;
+ priv->crc_len = &priv->icc_len;
+ priv->bytes_read = 0;
+ priv->crc_chunk = &priv->icc_chunk;
+ }
+
+ eom_metadata_reader_png_get_next_block (priv,
+ priv->icc_chunk,
+ &i, buf, len,
+ EMR_READ_ICCP);
+ break;
+ case EMR_READ_SRGB:
+ /* Extract the sRGB chunk. Marks the image data as
+ * being in sRGB colorspace. */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read sRGB Chunk - value: %u", *(buf+i));
+
+ if (priv->sRGB_chunk == NULL) {
+ priv->sRGB_chunk = g_new0 (guchar, priv->size);
+ priv->sRGB_len = priv->size;
+ priv->crc_len = &priv->sRGB_len;
+ priv->bytes_read = 0;
+ priv->crc_chunk = &priv->sRGB_chunk;
+ }
+
+ eom_metadata_reader_png_get_next_block (priv,
+ priv->sRGB_chunk,
+ &i, buf, len,
+ EMR_READ_SRGB);
+ break;
+ case EMR_READ_CHRM:
+ /* Extract the cHRM chunk. Contains the coordinates of
+ * the image's whitepoint and primary chromacities. */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read cHRM Chunk - size: %"
+ G_GSIZE_FORMAT, priv->size);
+
+ if (priv->cHRM_chunk == NULL) {
+ priv->cHRM_chunk = g_new0 (guchar, priv->size);
+ priv->cHRM_len = priv->size;
+ priv->crc_len = &priv->cHRM_len;
+ priv->bytes_read = 0;
+ priv->crc_chunk = &priv->cHRM_chunk;
+ }
+
+ eom_metadata_reader_png_get_next_block (priv,
+ priv->cHRM_chunk,
+ &i, buf, len,
+ EMR_READ_ICCP);
+ break;
+ case EMR_READ_GAMA:
+ /* Extract the gAMA chunk containing the
+ * image's gamma value */
+ eom_debug_message (DEBUG_IMAGE_DATA,
+ "Read gAMA-Chunk - size: %"
+ G_GSIZE_FORMAT, priv->size);
+
+ if (priv->gAMA_chunk == NULL) {
+ priv->gAMA_chunk = g_new0 (guchar, priv->size);
+ priv->gAMA_len = priv->size;
+ priv->crc_len = &priv->gAMA_len;
+ priv->bytes_read = 0;
+ priv->crc_chunk = &priv->gAMA_chunk;
+ }
+
+ eom_metadata_reader_png_get_next_block (priv,
+ priv->gAMA_chunk,
+ &i, buf, len,
+ EMR_READ_ICCP);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+}
+
+#ifdef HAVE_EXEMPI
+
+/* skip the chunk ID */
+#define EOM_XMP_OFFSET (22)
+
+static gpointer
+eom_metadata_reader_png_get_xmp_data (EomMetadataReaderPng *emr )
+{
+ EomMetadataReaderPngPrivate *priv;
+ XmpPtr xmp = NULL;
+
+ g_return_val_if_fail (EOM_IS_METADATA_READER_PNG (emr), NULL);
+
+ priv = emr->priv;
+
+ if (priv->xmp_chunk != NULL) {
+ xmp = xmp_new (priv->xmp_chunk+EOM_XMP_OFFSET,
+ priv->xmp_len-EOM_XMP_OFFSET);
+ }
+
+ return (gpointer) xmp;
+}
+#endif
+
+#ifdef HAVE_LCMS
+
+#define EXTRACT_DOUBLE_UINT_BLOCK_OFFSET(chunk,offset,divider) \
+ (double)(GUINT32_FROM_BE(*((guint32*)((chunk)+((offset)*4))))/(double)(divider))
+
+/* This is the amount of memory the inflate output buffer gets increased by
+ * while decompressing the ICC profile */
+#define EOM_ICC_INFLATE_BUFFER_STEP 1024
+
+/* I haven't seen ICC profiles larger than 1MB yet.
+ * A maximum output buffer of 5MB should be enough. */
+#define EOM_ICC_INFLATE_BUFFER_LIMIT (1024*1024*5)
+
+static gpointer
+eom_metadata_reader_png_get_icc_profile (EomMetadataReaderPng *emr)
+{
+ EomMetadataReaderPngPrivate *priv;
+ cmsHPROFILE profile = NULL;
+
+ g_return_val_if_fail (EOM_IS_METADATA_READER_PNG (emr), NULL);
+
+ priv = emr->priv;
+
+ if (priv->icc_chunk) {
+ gpointer outbuf;
+ gsize offset = 0;
+ z_stream zstr;
+ int z_ret;
+
+ /* Use default allocation functions */
+ zstr.zalloc = Z_NULL;
+ zstr.zfree = Z_NULL;
+ zstr.opaque = Z_NULL;
+
+ /* Skip the name of the ICC profile */
+ while (*((guchar*)priv->icc_chunk+offset) != '\0')
+ offset++;
+ /* Ensure the compression method (deflate) */
+ if (*((guchar*)priv->icc_chunk+(++offset)) != '\0')
+ return NULL;
+ ++offset; //offset now points to the start of the deflated data
+
+ /* Prepare the zlib data structure for decompression */
+ zstr.next_in = priv->icc_chunk + offset;
+ zstr.avail_in = priv->icc_len - offset;
+ if (inflateInit (&zstr) != Z_OK) {
+ return NULL;
+ }
+
+ /* Prepare output buffer and make zlib aware of it */
+ outbuf = g_malloc (EOM_ICC_INFLATE_BUFFER_STEP);
+ zstr.next_out = outbuf;
+ zstr.avail_out = EOM_ICC_INFLATE_BUFFER_STEP;
+
+ do {
+ if (zstr.avail_out == 0) {
+ /* The output buffer was not large enough to
+ * hold all the decompressed data. Increase its
+ * size and continue decompression. */
+ gsize new_size = zstr.total_out + EOM_ICC_INFLATE_BUFFER_STEP;
+
+ if (G_UNLIKELY (new_size > EOM_ICC_INFLATE_BUFFER_LIMIT)) {
+ /* Enforce a memory limit for the output
+ * buffer to avoid possible OOM cases */
+ inflateEnd (&zstr);
+ g_free (outbuf);
+ eom_debug_message (DEBUG_IMAGE_DATA, "ICC profile is too large. Ignoring.");
+ return NULL;
+ }
+ outbuf = g_realloc(outbuf, new_size);
+ zstr.avail_out = EOM_ICC_INFLATE_BUFFER_STEP;
+ zstr.next_out = outbuf + zstr.total_out;
+ }
+ z_ret = inflate (&zstr, Z_SYNC_FLUSH);
+ } while (z_ret == Z_OK);
+
+ if (G_UNLIKELY (z_ret != Z_STREAM_END)) {
+ eom_debug_message (DEBUG_IMAGE_DATA, "Error while inflating ICC profile: %s (%d)", zstr.msg, z_ret);
+ inflateEnd (&zstr);
+ g_free (outbuf);
+ return NULL;
+ }
+
+ cmsErrorAction (LCMS_ERROR_SHOW);
+
+ profile = cmsOpenProfileFromMem(outbuf, zstr.total_out);
+ inflateEnd (&zstr);
+ g_free (outbuf);
+
+ eom_debug_message (DEBUG_LCMS, "PNG has %s ICC profile", profile ? "valid" : "invalid");
+ }
+
+ if (!profile && priv->sRGB_chunk) {
+ eom_debug_message (DEBUG_LCMS, "PNG is sRGB");
+ /* If the file has an sRGB chunk the image data is in the sRGB
+ * colorspace. lcms has a built-in sRGB profile. */
+
+ profile = cmsCreate_sRGBProfile ();
+ }
+
+ if (!profile && priv->cHRM_chunk) {
+ cmsCIExyY whitepoint;
+ cmsCIExyYTRIPLE primaries;
+ LPGAMMATABLE gamma[3];
+ double gammaValue = 2.2; // 2.2 should be a sane default gamma
+
+ /* This uglyness extracts the chromacity and whitepoint values
+ * from a PNG's cHRM chunk. These can be accurate up to the
+ * 5th decimal point.
+ * They are saved as integer values multiplied by 100000. */
+
+ eom_debug_message (DEBUG_LCMS, "Trying to calculate color profile");
+
+ whitepoint.x = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 0, 100000);
+ whitepoint.y = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 1, 100000);
+
+ primaries.Red.x = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 2, 100000);
+ primaries.Red.y = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 3, 100000);
+ primaries.Green.x = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 4, 100000);
+ primaries.Green.y = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 5, 100000);
+ primaries.Blue.x = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 6, 100000);
+ primaries.Blue.y = EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->cHRM_chunk, 7, 100000);
+
+ primaries.Red.Y = primaries.Green.Y = primaries.Blue.Y = 1.0;
+
+ /* If the gAMA_chunk is present use its value which is saved
+ * the same way as the whitepoint. Use 2.2 as default value if
+ * the chunk is not present. */
+ if (priv->gAMA_chunk)
+ gammaValue = (double) 1.0/EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->gAMA_chunk, 0, 100000);
+
+ gamma[0] = gamma[1] = gamma[2] = cmsBuildGamma (256, gammaValue);
+
+ profile = cmsCreateRGBProfile (&whitepoint, &primaries, gamma);
+
+ cmsFreeGamma(gamma[0]);
+ }
+
+ return profile;
+}
+#endif
+
+static void
+eom_metadata_reader_png_init_emr_iface (gpointer g_iface, gpointer iface_data)
+{
+ EomMetadataReaderInterface *iface;
+
+ iface = (EomMetadataReaderInterface*) g_iface;
+
+ iface->consume =
+ (void (*) (EomMetadataReader *self, const guchar *buf, guint len))
+ eom_metadata_reader_png_consume;
+ iface->finished =
+ (gboolean (*) (EomMetadataReader *self))
+ eom_metadata_reader_png_finished;
+#ifdef HAVE_LCMS
+ iface->get_icc_profile =
+ (cmsHPROFILE (*) (EomMetadataReader *self))
+ eom_metadata_reader_png_get_icc_profile;
+#endif
+#ifdef HAVE_EXEMPI
+ iface->get_xmp_ptr =
+ (gpointer (*) (EomMetadataReader *self))
+ eom_metadata_reader_png_get_xmp_data;
+#endif
+}
diff --git a/src/eom-metadata-reader-png.h b/src/eom-metadata-reader-png.h
new file mode 100644
index 0000000..7dde41f
--- /dev/null
+++ b/src/eom-metadata-reader-png.h
@@ -0,0 +1,55 @@
+/* Eye Of MATE -- PNG Metadata Reader
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <[email protected]>
+ *
+ * Based on the old EomMetadataReader code.
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _EOM_METADATA_READER_PNG_H_
+#define _EOM_METADATA_READER_PNG_H_
+
+G_BEGIN_DECLS
+
+#define EOM_TYPE_METADATA_READER_PNG (eom_metadata_reader_png_get_type ())
+#define EOM_METADATA_READER_PNG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EOM_TYPE_METADATA_READER_PNG, EomMetadataReaderPng))
+#define EOM_METADATA_READER_PNG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EOM_TYPE_METADATA_READER_PNG, EomMetadataReaderPngClass))
+#define EOM_IS_METADATA_READER_PNG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOM_TYPE_METADATA_READER_PNG))
+#define EOM_IS_METADATA_READER_PNG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EOM_TYPE_METADATA_READER_PNG))
+#define EOM_METADATA_READER_PNG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EOM_TYPE_METADATA_READER_PNG, EomMetadataReaderPngClass))
+
+typedef struct _EomMetadataReaderPng EomMetadataReaderPng;
+typedef struct _EomMetadataReaderPngClass EomMetadataReaderPngClass;
+typedef struct _EomMetadataReaderPngPrivate EomMetadataReaderPngPrivate;
+
+struct _EomMetadataReaderPng {
+ GObject parent;
+
+ EomMetadataReaderPngPrivate *priv;
+};
+
+struct _EomMetadataReaderPngClass {
+ GObjectClass parent_klass;
+};
+
+G_GNUC_INTERNAL
+GType eom_metadata_reader_png_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* _EOM_METADATA_READER_PNG_H_ */
diff --git a/src/eom-metadata-reader.c b/src/eom-metadata-reader.c
new file mode 100644
index 0000000..82955e8
--- /dev/null
+++ b/src/eom-metadata-reader.c
@@ -0,0 +1,150 @@
+/* Eye Of MATE -- Metadata Reader Interface
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-metadata-reader.h"
+#include "eom-metadata-reader-jpg.h"
+#include "eom-metadata-reader-png.h"
+#include "eom-debug.h"
+
+
+GType
+eom_metadata_reader_get_type (void)
+{
+ static GType reader_type = 0;
+
+ if (G_UNLIKELY (reader_type == 0)) {
+ reader_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "EomMetadataReader",
+ sizeof (EomMetadataReaderInterface),
+ NULL, 0, NULL, 0);
+ }
+
+ return reader_type;
+}
+
+EomMetadataReader*
+eom_metadata_reader_new (EomMetadataFileType type)
+{
+ EomMetadataReader *emr;
+
+ switch (type) {
+ case EOM_METADATA_JPEG:
+ emr = EOM_METADATA_READER (g_object_new (EOM_TYPE_METADATA_READER_JPG, NULL));
+ break;
+ case EOM_METADATA_PNG:
+ emr = EOM_METADATA_READER (g_object_new (EOM_TYPE_METADATA_READER_PNG, NULL));
+ break;
+ default:
+ emr = NULL;
+ break;
+ }
+
+ return emr;
+}
+
+gboolean
+eom_metadata_reader_finished (EomMetadataReader *emr)
+{
+ g_return_val_if_fail (EOM_IS_METADATA_READER (emr), TRUE);
+
+ return EOM_METADATA_READER_GET_INTERFACE (emr)->finished (emr);
+}
+
+
+void
+eom_metadata_reader_consume (EomMetadataReader *emr, const guchar *buf, guint len)
+{
+ EOM_METADATA_READER_GET_INTERFACE (emr)->consume (emr, buf, len);
+}
+
+/* Returns the raw exif data. NOTE: The caller of this function becomes
+ * the new owner of this piece of memory and is responsible for freeing it!
+ */
+void
+eom_metadata_reader_get_exif_chunk (EomMetadataReader *emr, guchar **data, guint *len)
+{
+ EomMetadataReaderInterface *iface;
+
+ g_return_if_fail (data != NULL && len != NULL);
+ iface = EOM_METADATA_READER_GET_INTERFACE (emr);
+
+ if (iface->get_raw_exif) {
+ iface->get_raw_exif (emr, data, len);
+ } else {
+ g_return_if_fail (data != NULL && len != NULL);
+
+ *data = NULL;
+ *len = 0;
+ }
+
+}
+
+#ifdef HAVE_EXIF
+ExifData*
+eom_metadata_reader_get_exif_data (EomMetadataReader *emr)
+{
+ gpointer exif_data = NULL;
+ EomMetadataReaderInterface *iface;
+
+ iface = EOM_METADATA_READER_GET_INTERFACE (emr);
+
+ if (iface->get_exif_data)
+ exif_data = iface->get_exif_data (emr);
+
+ return exif_data;
+}
+#endif
+
+#ifdef HAVE_EXEMPI
+XmpPtr
+eom_metadata_reader_get_xmp_data (EomMetadataReader *emr )
+{
+ gpointer xmp_data = NULL;
+ EomMetadataReaderInterface *iface;
+
+ iface = EOM_METADATA_READER_GET_INTERFACE (emr);
+
+ if (iface->get_xmp_ptr)
+ xmp_data = iface->get_xmp_ptr (emr);
+
+ return xmp_data;
+}
+#endif
+
+#ifdef HAVE_LCMS
+cmsHPROFILE
+eom_metadata_reader_get_icc_profile (EomMetadataReader *emr)
+{
+ EomMetadataReaderInterface *iface;
+ gpointer profile = NULL;
+
+ iface = EOM_METADATA_READER_GET_INTERFACE (emr);
+
+ if (iface->get_icc_profile)
+ profile = iface->get_icc_profile (emr);
+
+ return profile;
+}
+#endif
diff --git a/src/eom-metadata-reader.h b/src/eom-metadata-reader.h
new file mode 100644
index 0000000..ad8803d
--- /dev/null
+++ b/src/eom-metadata-reader.h
@@ -0,0 +1,112 @@
+/* Eye Of MATE -- Metadata Reader Interface
+ *
+ * Copyright (C) 2008 The Free Software Foundation
+ *
+ * Author: Felix Riemann <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _EOM_METADATA_READER_H_
+#define _EOM_METADATA_READER_H_
+
+#include <glib-object.h>
+#if HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#endif
+#if HAVE_LCMS
+#include <lcms.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define EOM_TYPE_METADATA_READER (eom_metadata_reader_get_type ())
+#define EOM_METADATA_READER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EOM_TYPE_METADATA_READER, EomMetadataReader))
+#define EOM_IS_METADATA_READER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOM_TYPE_METADATA_READER))
+#define EOM_METADATA_READER_GET_INTERFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), EOM_TYPE_METADATA_READER, EomMetadataReaderInterface))
+
+typedef struct _EomMetadataReader EomMetadataReader;
+typedef struct _EomMetadataReaderInterface EomMetadataReaderInterface;
+
+struct _EomMetadataReaderInterface {
+ GTypeInterface parent;
+
+ void (*consume) (EomMetadataReader *self,
+ const guchar *buf,
+ guint len);
+
+ gboolean (*finished) (EomMetadataReader *self);
+
+ void (*get_raw_exif) (EomMetadataReader *self,
+ guchar **data,
+ guint *len);
+
+ gpointer (*get_exif_data) (EomMetadataReader *self);
+
+ gpointer (*get_icc_profile) (EomMetadataReader *self);
+
+ gpointer (*get_xmp_ptr) (EomMetadataReader *self);
+};
+
+typedef enum {
+ EOM_METADATA_JPEG,
+ EOM_METADATA_PNG
+} EomMetadataFileType;
+
+G_GNUC_INTERNAL
+GType eom_metadata_reader_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+EomMetadataReader* eom_metadata_reader_new (EomMetadataFileType type);
+
+G_GNUC_INTERNAL
+void eom_metadata_reader_consume (EomMetadataReader *emr,
+ const guchar *buf,
+ guint len);
+
+G_GNUC_INTERNAL
+gboolean eom_metadata_reader_finished (EomMetadataReader *emr);
+
+G_GNUC_INTERNAL
+void eom_metadata_reader_get_exif_chunk (EomMetadataReader *emr,
+ guchar **data,
+ guint *len);
+
+#ifdef HAVE_EXIF
+G_GNUC_INTERNAL
+ExifData* eom_metadata_reader_get_exif_data (EomMetadataReader *emr);
+#endif
+
+#ifdef HAVE_EXEMPI
+G_GNUC_INTERNAL
+XmpPtr eom_metadata_reader_get_xmp_data (EomMetadataReader *emr);
+#endif
+
+#if 0
+gpointer eom_metadata_reader_get_iptc_chunk (EomMetadataReader *emr);
+IptcData* eom_metadata_reader_get_iptc_data (EomMetadataReader *emr);
+#endif
+
+#ifdef HAVE_LCMS
+G_GNUC_INTERNAL
+cmsHPROFILE eom_metadata_reader_get_icc_profile (EomMetadataReader *emr);
+#endif
+
+G_END_DECLS
+
+#endif /* _EOM_METADATA_READER_H_ */
diff --git a/src/eom-module.c b/src/eom-module.c
new file mode 100644
index 0000000..79fac47
--- /dev/null
+++ b/src/eom-module.c
@@ -0,0 +1,167 @@
+/* Eye Of Mate - EOM Module
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ * - Marco Pesenti Gritti <[email protected]>
+ * - Christian Persch <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eom-module.h"
+#include "eom-debug.h"
+
+#include <gmodule.h>
+
+#define EOM_MODULE_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_MODULE, EomModulePrivate))
+
+G_DEFINE_TYPE (EomModule, eom_module, G_TYPE_TYPE_MODULE);
+
+typedef GType (*EomModuleRegisterFunc) (GTypeModule *);
+
+static gboolean
+eom_module_load (GTypeModule *gmodule)
+{
+ EomModule *module = EOM_MODULE (gmodule);
+ EomModuleRegisterFunc register_func;
+
+ eom_debug_message (DEBUG_PLUGINS, "Loading %s", module->path);
+
+ module->library = g_module_open (module->path, 0);
+
+ if (module->library == NULL) {
+ g_warning ("%s", g_module_error());
+
+ return FALSE;
+ }
+
+ /* Extract symbols from the lib */
+ if (!g_module_symbol (module->library,
+ "register_eom_plugin",
+ (void *) &register_func)) {
+ g_warning ("%s", g_module_error());
+ g_module_close (module->library);
+
+ return FALSE;
+ }
+
+ /* Symbol can still be NULL even though g_module_symbol
+ * returned TRUE */
+ if (register_func == NULL) {
+ g_warning ("Symbol 'register_eom_plugin' should not be NULL");
+ g_module_close (module->library);
+
+ return FALSE;
+ }
+
+ module->type = register_func (gmodule);
+
+ if (module->type == 0) {
+ g_warning ("Invalid eom plugin contained by module %s", module->path);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+eom_module_unload (GTypeModule *gmodule)
+{
+ EomModule *module = EOM_MODULE (gmodule);
+
+ eom_debug_message (DEBUG_PLUGINS, "Unloading %s", module->path);
+
+ g_module_close (module->library);
+
+ module->library = NULL;
+ module->type = 0;
+}
+
+const gchar *
+eom_module_get_path (EomModule *module)
+{
+ g_return_val_if_fail (EOM_IS_MODULE (module), NULL);
+
+ return module->path;
+}
+
+GObject *
+eom_module_new_object (EomModule *module)
+{
+ eom_debug_message (DEBUG_PLUGINS, "Creating object of type %s", g_type_name (module->type));
+
+ if (module->type == 0) {
+ return NULL;
+ }
+
+ return g_object_new (module->type, NULL);
+}
+
+static void
+eom_module_init (EomModule *module)
+{
+ eom_debug_message (DEBUG_PLUGINS, "EomModule %p initialising", module);
+}
+
+static void
+eom_module_finalize (GObject *object)
+{
+ EomModule *module = EOM_MODULE (object);
+
+ eom_debug_message (DEBUG_PLUGINS, "EomModule %p finalising", module);
+
+ g_free (module->path);
+
+ G_OBJECT_CLASS (eom_module_parent_class)->finalize (object);
+}
+
+static void
+eom_module_class_init (EomModuleClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
+
+ object_class->finalize = eom_module_finalize;
+
+ module_class->load = eom_module_load;
+ module_class->unload = eom_module_unload;
+}
+
+EomModule *
+eom_module_new (const gchar *path)
+{
+ EomModule *module;
+
+ if (path == NULL || path[0] == '\0') {
+ return NULL;
+ }
+
+ module = g_object_new (EOM_TYPE_MODULE, NULL);
+
+ g_type_module_set_name (G_TYPE_MODULE (module), path);
+
+ module->path = g_strdup (path);
+
+ return module;
+}
diff --git a/src/eom-module.h b/src/eom-module.h
new file mode 100644
index 0000000..241ba28
--- /dev/null
+++ b/src/eom-module.h
@@ -0,0 +1,72 @@
+/* Eye Of Mate - Main Window
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ * - Marco Pesenti Gritti <[email protected]>
+ * - Christian Persch <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EOM_MODULE_H
+#define EOM_MODULE_H
+
+#include <glib-object.h>
+#include <gmodule.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EomModule EomModule;
+typedef struct _EomModuleClass EomModuleClass;
+typedef struct _EomModulePrivate EomModulePrivate;
+
+#define EOM_TYPE_MODULE (eom_module_get_type ())
+#define EOM_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_MODULE, EomModule))
+#define EOM_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EOM_TYPE_MODULE, EomModuleClass))
+#define EOM_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_MODULE))
+#define EOM_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EOM_TYPE_MODULE))
+#define EOM_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EOM_TYPE_MODULE, EomModuleClass))
+
+struct _EomModule {
+ GTypeModule parent_instance;
+
+ GModule *library;
+ gchar *path;
+ GType type;
+};
+
+struct _EomModuleClass {
+ GTypeModuleClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType eom_module_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+EomModule *eom_module_new (const gchar *path);
+
+G_GNUC_INTERNAL
+const gchar *eom_module_get_path (EomModule *module);
+
+G_GNUC_INTERNAL
+GObject *eom_module_new_object (EomModule *module);
+
+G_END_DECLS
+
+#endif
diff --git a/src/eom-pixbuf-util.c b/src/eom-pixbuf-util.c
new file mode 100644
index 0000000..837bb42
--- /dev/null
+++ b/src/eom-pixbuf-util.c
@@ -0,0 +1,136 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include "eom-pixbuf-util.h"
+
+GSList*
+eom_pixbuf_get_savable_formats (void)
+{
+ GSList *list;
+ GSList *write_list = NULL;
+ GSList *it;
+
+ list = gdk_pixbuf_get_formats ();
+
+ for (it = list; it != NULL; it = it->next) {
+ GdkPixbufFormat *format;
+
+ format = (GdkPixbufFormat*) it->data;
+ if (gdk_pixbuf_format_is_writable (format)) {
+ write_list = g_slist_prepend (write_list, format);
+ }
+ }
+
+ g_slist_free (list);
+ write_list = g_slist_reverse (write_list);
+
+ return write_list;
+}
+
+GdkPixbufFormat*
+eom_pixbuf_get_format_by_suffix (const char *suffix)
+{
+ GSList *list;
+ GSList *it;
+ GdkPixbufFormat *result = NULL;
+
+ g_return_val_if_fail (suffix != NULL, NULL);
+
+ list = gdk_pixbuf_get_formats ();
+
+ for (it = list; (it != NULL) && (result == NULL); it = it->next) {
+ GdkPixbufFormat *format;
+ gchar **extensions;
+ int i;
+
+ format = (GdkPixbufFormat*) it->data;
+
+ extensions = gdk_pixbuf_format_get_extensions (format);
+ for (i = 0; extensions[i] != NULL; i++) {
+ /* g_print ("check extension: %s against %s\n", extensions[i], suffix); */
+ if (g_ascii_strcasecmp (suffix, extensions[i]) == 0) {
+ result = format;
+ break;
+ }
+ }
+
+ g_strfreev (extensions);
+ }
+
+ g_slist_free (list);
+
+ return result;
+}
+
+char*
+eom_pixbuf_get_common_suffix (GdkPixbufFormat *format)
+{
+ char **extensions;
+ int i;
+ char *result = NULL;
+
+ if (format == NULL) return NULL;
+
+ extensions = gdk_pixbuf_format_get_extensions (format);
+ if (extensions[0] == NULL) return NULL;
+
+ /* try to find 3-char suffix first, use the last occurence */
+ for (i = 0; extensions [i] != NULL; i++) {
+ if (strlen (extensions[i]) <= 3) {
+ g_free (result);
+ result = g_ascii_strdown (extensions[i], -1);
+ }
+ }
+
+ /* otherwise take the first one */
+ if (result == NULL) {
+ result = g_ascii_strdown (extensions[0], -1);
+ }
+
+ g_strfreev (extensions);
+
+ return result;
+}
+
+static char*
+get_suffix_from_basename (const char *basename)
+{
+ char *suffix;
+ char *suffix_start;
+ guint len;
+
+ /* FIXME: does this work for all locales? */
+ suffix_start = g_utf8_strrchr (basename, -1, '.');
+
+ if (suffix_start == NULL)
+ return NULL;
+
+ len = strlen (suffix_start) - 1;
+ suffix = g_strndup (suffix_start+1, len);
+
+ return suffix;
+
+}
+
+GdkPixbufFormat *
+eom_pixbuf_get_format (GFile *file)
+{
+ GdkPixbufFormat *format;
+ char *path, *basename, *suffix;
+ g_return_val_if_fail (file != NULL, NULL);
+
+ path = g_file_get_path (file);
+ basename = g_path_get_basename (path);
+ suffix = get_suffix_from_basename (basename);
+
+ format = eom_pixbuf_get_format_by_suffix (suffix);
+
+ g_free (path);
+ g_free (basename);
+ g_free (suffix);
+
+ return format;
+}
+
diff --git a/src/eom-pixbuf-util.h b/src/eom-pixbuf-util.h
new file mode 100644
index 0000000..e3d6268
--- /dev/null
+++ b/src/eom-pixbuf-util.h
@@ -0,0 +1,20 @@
+#ifndef _EOM_PIXBUF_UTIL_H_
+#define _EOM_PIXBUF_UTIL_H_
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gio/gio.h>
+
+G_GNUC_INTERNAL
+GSList* eom_pixbuf_get_savable_formats (void);
+
+G_GNUC_INTERNAL
+GdkPixbufFormat* eom_pixbuf_get_format_by_suffix (const char *suffix);
+
+G_GNUC_INTERNAL
+GdkPixbufFormat* eom_pixbuf_get_format (GFile *file);
+
+G_GNUC_INTERNAL
+char* eom_pixbuf_get_common_suffix (GdkPixbufFormat *format);
+
+#endif /* _EOM_PIXBUF_UTIL_H_ */
+
diff --git a/src/eom-plugin-engine.c b/src/eom-plugin-engine.c
new file mode 100644
index 0000000..09662b5
--- /dev/null
+++ b/src/eom-plugin-engine.c
@@ -0,0 +1,943 @@
+/* Eye Of Mate - EOM Plugin Manager
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "eom-plugin-engine.h"
+#include "eom-plugin.h"
+#include "eom-module.h"
+#include "eom-debug.h"
+#include "eom-application.h"
+#include "eom-config-keys.h"
+#include "eom-util.h"
+
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <mateconf/mateconf-client.h>
+
+#ifdef ENABLE_PYTHON
+#include "eom-python-module.h"
+#endif
+
+#define USER_EOM_PLUGINS_LOCATION "plugins/"
+
+#define EOM_PLUGINS_ENGINE_BASE_KEY "/apps/eom/plugins"
+
+#define PLUGIN_EXT ".eom-plugin"
+
+typedef enum {
+ EOM_PLUGIN_LOADER_C,
+ EOM_PLUGIN_LOADER_PY,
+} EomPluginLoader;
+
+struct _EomPluginInfo
+{
+ gchar *file;
+
+ gchar *location;
+ EomPluginLoader loader;
+ GTypeModule *module;
+
+ gchar *name;
+ gchar *desc;
+ gchar *icon_name;
+ gchar **authors;
+ gchar *copyright;
+ gchar *website;
+
+ EomPlugin *plugin;
+
+ gint active : 1;
+
+ /* A plugin is unavailable if it is not possible to activate it
+ due to an error loading the plugin module (e.g. for Python plugins
+ when the interpreter has not been correctly initializated) */
+ gint available : 1;
+};
+
+static void eom_plugin_engine_active_plugins_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data);
+
+static GList *eom_plugins_list = NULL;
+
+static MateConfClient *eom_plugin_engine_mateconf_client = NULL;
+
+static GSList *active_plugins = NULL;
+
+static void
+eom_plugin_info_free (EomPluginInfo *info)
+{
+ if (info->plugin != NULL) {
+ eom_debug_message (DEBUG_PLUGINS, "Unref plugin %s", info->name);
+
+ g_object_unref (info->plugin);
+ }
+
+ g_free (info->file);
+ g_free (info->location);
+ g_free (info->name);
+ g_free (info->desc);
+ g_free (info->icon_name);
+ g_free (info->website);
+ g_free (info->copyright);
+ g_strfreev (info->authors);
+
+ g_free (info);
+}
+
+static EomPluginInfo *
+eom_plugin_engine_load (const gchar *file)
+{
+ EomPluginInfo *info;
+ GKeyFile *plugin_file = NULL;
+ gchar *str;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ eom_debug_message (DEBUG_PLUGINS, "Loading plugin: %s", file);
+
+ info = g_new0 (EomPluginInfo, 1);
+ info->file = g_strdup (file);
+
+ plugin_file = g_key_file_new ();
+
+ if (!g_key_file_load_from_file (plugin_file, file, G_KEY_FILE_NONE, NULL)) {
+ g_warning ("Bad plugin file: %s", file);
+
+ goto error;
+ }
+
+ if (!g_key_file_has_key (plugin_file,
+ "Eom Plugin",
+ "IAge",
+ NULL)) {
+ eom_debug_message (DEBUG_PLUGINS,
+ "IAge key does not exist in file: %s", file);
+
+ goto error;
+ }
+
+ /* Check IAge=2 */
+ if (g_key_file_get_integer (plugin_file,
+ "Eom Plugin",
+ "IAge",
+ NULL) != 2) {
+ eom_debug_message (DEBUG_PLUGINS,
+ "Wrong IAge in file: %s", file);
+
+ goto error;
+ }
+
+ /* Get Location */
+ str = g_key_file_get_string (plugin_file,
+ "Eom Plugin",
+ "Module",
+ NULL);
+
+ if ((str != NULL) && (*str != '\0')) {
+ info->location = str;
+ } else {
+ g_warning ("Could not find 'Module' in %s", file);
+
+ goto error;
+ }
+
+ /* Get the loader for this plugin */
+ str = g_key_file_get_string (plugin_file,
+ "Eom Plugin",
+ "Loader",
+ NULL);
+
+ if (str && strcmp(str, "python") == 0) {
+ info->loader = EOM_PLUGIN_LOADER_PY;
+
+#ifndef ENABLE_PYTHON
+ g_warning ("Cannot load Python plugin '%s' since eom was not "
+ "compiled with Python support.", file);
+
+ goto error;
+#endif
+
+ } else {
+ info->loader = EOM_PLUGIN_LOADER_C;
+ }
+
+ g_free (str);
+
+ /* Get Name */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Eom Plugin",
+ "Name",
+ NULL, NULL);
+ if (str) {
+ info->name = str;
+ } else {
+ g_warning ("Could not find 'Name' in %s", file);
+
+ goto error;
+ }
+
+ /* Get Description */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Eom Plugin",
+ "Description",
+ NULL, NULL);
+ if (str) {
+ info->desc = str;
+ } else {
+ eom_debug_message (DEBUG_PLUGINS, "Could not find 'Description' in %s", file);
+ }
+
+ /* Get Icon */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Eom Plugin",
+ "Icon",
+ NULL, NULL);
+ if (str) {
+ info->icon_name = str;
+ } else {
+ eom_debug_message (DEBUG_PLUGINS, "Could not find 'Icon' in %s, "
+ "using 'eom-plugin'", file);
+ }
+
+ /* Get Authors */
+ info->authors = g_key_file_get_string_list (plugin_file,
+ "Eom Plugin",
+ "Authors",
+ NULL,
+ NULL);
+
+ if (info->authors == NULL)
+ eom_debug_message (DEBUG_PLUGINS, "Could not find 'Authors' in %s", file);
+
+
+ /* Get Copyright */
+ str = g_key_file_get_string (plugin_file,
+ "Eom Plugin",
+ "Copyright",
+ NULL);
+ if (str) {
+ info->copyright = str;
+ } else {
+ eom_debug_message (DEBUG_PLUGINS, "Could not find 'Copyright' in %s", file);
+ }
+
+ /* Get Website */
+ str = g_key_file_get_string (plugin_file,
+ "Eom Plugin",
+ "Website",
+ NULL);
+ if (str) {
+ info->website = str;
+ } else {
+ eom_debug_message (DEBUG_PLUGINS, "Could not find 'Website' in %s", file);
+ }
+
+ g_key_file_free (plugin_file);
+
+ /* If we know nothing about the availability of the plugin,
+ set it as available */
+ info->available = TRUE;
+
+ return info;
+
+error:
+ g_free (info->file);
+ g_free (info->location);
+ g_free (info->name);
+ g_free (info);
+ g_key_file_free (plugin_file);
+
+ return NULL;
+}
+
+static gint
+compare_plugin_info (EomPluginInfo *info1,
+ EomPluginInfo *info2)
+{
+ return strcmp (info1->location, info2->location);
+}
+
+static void
+eom_plugin_engine_load_dir (const gchar *dir)
+{
+ GError *error = NULL;
+ GDir *d;
+ const gchar *dirent;
+
+ if (!g_file_test (dir, G_FILE_TEST_IS_DIR)) {
+ return;
+ }
+
+ g_return_if_fail (eom_plugin_engine_mateconf_client != NULL);
+
+ eom_debug_message (DEBUG_PLUGINS, "DIR: %s", dir);
+
+ d = g_dir_open (dir, 0, &error);
+
+ if (!d) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+
+ return;
+ }
+
+ while ((dirent = g_dir_read_name (d))) {
+ if (g_str_has_suffix (dirent, PLUGIN_EXT)) {
+ gchar *plugin_file;
+ EomPluginInfo *info;
+
+ plugin_file = g_build_filename (dir, dirent, NULL);
+ info = eom_plugin_engine_load (plugin_file);
+ g_free (plugin_file);
+
+ if (info == NULL)
+ continue;
+
+ /* If a plugin with this name has already been loaded
+ * drop this one (user plugins override system plugins) */
+ if (g_list_find_custom (eom_plugins_list,
+ info,
+ (GCompareFunc)compare_plugin_info) != NULL) {
+ g_warning ("Two or more plugins named '%s'. "
+ "Only the first will be considered.\n",
+ info->location);
+
+ eom_plugin_info_free (info);
+
+ continue;
+ }
+
+ /* Actually, the plugin will be activated when reactivate_all
+ * will be called for the first time. */
+ info->active = (g_slist_find_custom (active_plugins,
+ info->location,
+ (GCompareFunc)strcmp) != NULL);
+
+ eom_plugins_list = g_list_prepend (eom_plugins_list, info);
+
+ eom_debug_message (DEBUG_PLUGINS, "Plugin %s loaded", info->name);
+ }
+ }
+
+ eom_plugins_list = g_list_reverse (eom_plugins_list);
+
+ g_dir_close (d);
+}
+
+static void
+eom_plugin_engine_load_all (void)
+{
+ gchar *pdir;
+
+ pdir = g_build_filename (eom_util_dot_dir (),
+ USER_EOM_PLUGINS_LOCATION, NULL);
+
+ /* Load user's plugins */
+ eom_plugin_engine_load_dir (pdir);
+
+ g_free (pdir);
+
+ /* Load system plugins */
+ eom_plugin_engine_load_dir (EOM_PLUGIN_DIR "/");
+}
+
+gboolean
+eom_plugin_engine_init (void)
+{
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (eom_plugins_list == NULL, FALSE);
+
+ if (!g_module_supported ()) {
+ g_warning ("eom is not able to initialize the plugins engine.");
+
+ return FALSE;
+ }
+
+ eom_plugin_engine_mateconf_client = mateconf_client_get_default ();
+
+ g_return_val_if_fail (eom_plugin_engine_mateconf_client != NULL, FALSE);
+
+ mateconf_client_add_dir (eom_plugin_engine_mateconf_client,
+ EOM_PLUGINS_ENGINE_BASE_KEY,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ mateconf_client_notify_add (eom_plugin_engine_mateconf_client,
+ EOM_CONF_PLUGINS_ACTIVE_PLUGINS,
+ eom_plugin_engine_active_plugins_changed,
+ NULL, NULL, NULL);
+
+ active_plugins = mateconf_client_get_list (eom_plugin_engine_mateconf_client,
+ EOM_CONF_PLUGINS_ACTIVE_PLUGINS,
+ MATECONF_VALUE_STRING,
+ NULL);
+
+ eom_plugin_engine_load_all ();
+
+ return TRUE;
+}
+
+void
+eom_plugin_engine_garbage_collect (void)
+{
+#ifdef ENABLE_PYTHON
+ eom_python_garbage_collect ();
+#endif
+}
+
+void
+eom_plugin_engine_shutdown (void)
+{
+ GList *pl;
+
+ eom_debug (DEBUG_PLUGINS);
+
+#ifdef ENABLE_PYTHON
+ /* Note: that this may cause finalization of objects (typically
+ * the EomWindow) by running the garbage collector. Since some
+ * of the plugin may have installed callbacks upon object
+ * finalization (typically they need to free the WindowData)
+ * it must run before we get rid of the plugins.
+ */
+ eom_python_shutdown ();
+#endif
+
+ g_return_if_fail (eom_plugin_engine_mateconf_client != NULL);
+
+ for (pl = eom_plugins_list; pl; pl = pl->next) {
+ EomPluginInfo *info = (EomPluginInfo*) pl->data;
+
+ eom_plugin_info_free (info);
+ }
+
+ g_slist_foreach (active_plugins, (GFunc)g_free, NULL);
+ g_slist_free (active_plugins);
+
+ active_plugins = NULL;
+
+ g_list_free (eom_plugins_list);
+ eom_plugins_list = NULL;
+
+ g_object_unref (eom_plugin_engine_mateconf_client);
+ eom_plugin_engine_mateconf_client = NULL;
+}
+
+const GList *
+eom_plugin_engine_get_plugins_list (void)
+{
+ eom_debug (DEBUG_PLUGINS);
+
+ return eom_plugins_list;
+}
+
+static gboolean
+load_plugin_module (EomPluginInfo *info)
+{
+ gchar *path;
+ gchar *dirname;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+ g_return_val_if_fail (info->file != NULL, FALSE);
+ g_return_val_if_fail (info->location != NULL, FALSE);
+ g_return_val_if_fail (info->plugin == NULL, FALSE);
+ g_return_val_if_fail (info->available, FALSE);
+
+ switch (info->loader) {
+ case EOM_PLUGIN_LOADER_C:
+ dirname = g_path_get_dirname (info->file);
+ g_return_val_if_fail (dirname != NULL, FALSE);
+
+ path = g_module_build_path (dirname, info->location);
+
+ g_free (dirname);
+
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ info->module = G_TYPE_MODULE (eom_module_new (path));
+
+ g_free (path);
+
+ break;
+
+#ifdef ENABLE_PYTHON
+ case EOM_PLUGIN_LOADER_PY:
+ {
+ gchar *dir;
+
+ if (!eom_python_init ()) {
+ /* Mark plugin as unavailable and fails */
+ info->available = FALSE;
+
+ g_warning ("Cannot load Python plugin '%s' since eom "
+ "was not able to initialize the Python interpreter.",
+ info->name);
+
+ return FALSE;
+ }
+
+ dir = g_path_get_dirname (info->file);
+
+ g_return_val_if_fail ((info->location != NULL) &&
+ (info->location[0] != '\0'),
+ FALSE);
+
+ info->module = G_TYPE_MODULE (
+ eom_python_module_new (dir, info->location));
+
+ g_free (dir);
+
+ break;
+ }
+#endif
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ if (!g_type_module_use (info->module)) {
+ switch (info->loader) {
+ case EOM_PLUGIN_LOADER_C:
+ g_warning ("Cannot load plugin '%s' since file '%s' cannot be read.",
+ info->name,
+ eom_module_get_path (EOM_MODULE (info->module)));
+ break;
+
+ case EOM_PLUGIN_LOADER_PY:
+ g_warning ("Cannot load Python plugin '%s' since file '%s' cannot be read.",
+ info->name,
+ info->location);
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ g_object_unref (G_OBJECT (info->module));
+
+ info->module = NULL;
+
+ /* Mark plugin as unavailable and fails */
+ info->available = FALSE;
+
+ return FALSE;
+ }
+
+ switch (info->loader) {
+ case EOM_PLUGIN_LOADER_C:
+ info->plugin =
+ EOM_PLUGIN (eom_module_new_object (EOM_MODULE (info->module)));
+ break;
+
+#ifdef ENABLE_PYTHON
+ case EOM_PLUGIN_LOADER_PY:
+ info->plugin =
+ EOM_PLUGIN (eom_python_module_new_object (EOM_PYTHON_MODULE (info->module)));
+ break;
+#endif
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ g_type_module_unuse (info->module);
+
+ eom_debug_message (DEBUG_PLUGINS, "End");
+
+ return TRUE;
+}
+
+static gboolean
+eom_plugin_engine_activate_plugin_real (EomPluginInfo *info)
+{
+ gboolean res = TRUE;
+
+ /* Plugin is not available, don't try to activate/load it */
+ if (!info->available) {
+ return FALSE;
+ }
+
+ if (info->plugin == NULL)
+ res = load_plugin_module (info);
+
+ if (res) {
+ const GList *wins = eom_application_get_windows (EOM_APP);
+
+ while (wins != NULL) {
+ eom_plugin_activate (info->plugin,
+ EOM_WINDOW (wins->data));
+
+ wins = g_list_next (wins);
+ }
+ } else {
+ g_warning ("Error activating plugin '%s'", info->name);
+ }
+
+ return res;
+}
+
+gboolean
+eom_plugin_engine_activate_plugin (EomPluginInfo *info)
+{
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (!info->available)
+ return FALSE;
+
+ if (info->active)
+ return TRUE;
+
+ if (eom_plugin_engine_activate_plugin_real (info)) {
+ gboolean res;
+ GSList *list;
+
+ /* Update plugin state */
+ info->active = TRUE;
+
+ list = active_plugins;
+
+ while (list != NULL) {
+ if (strcmp (info->location, (gchar *)list->data) == 0) {
+ g_warning ("Plugin '%s' is already active.", info->name);
+
+ return TRUE;
+ }
+
+ list = g_slist_next (list);
+ }
+
+ active_plugins = g_slist_insert_sorted (active_plugins,
+ g_strdup (info->location),
+ (GCompareFunc)strcmp);
+
+ res = mateconf_client_set_list (eom_plugin_engine_mateconf_client,
+ EOM_CONF_PLUGINS_ACTIVE_PLUGINS,
+ MATECONF_VALUE_STRING,
+ active_plugins,
+ NULL);
+
+ if (!res)
+ g_warning ("Error saving the list of active plugins.");
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+eom_plugin_engine_deactivate_plugin_real (EomPluginInfo *info)
+{
+ const GList *wins = eom_application_get_windows (EOM_APP);
+
+ while (wins != NULL) {
+ eom_plugin_deactivate (info->plugin,
+ EOM_WINDOW (wins->data));
+
+ wins = g_list_next (wins);
+ }
+}
+
+gboolean
+eom_plugin_engine_deactivate_plugin (EomPluginInfo *info)
+{
+ gboolean res;
+ GSList *list;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (!info->active || !info->available)
+ return TRUE;
+
+ eom_plugin_engine_deactivate_plugin_real (info);
+
+ /* Update plugin state */
+ info->active = FALSE;
+
+ list = active_plugins;
+ res = (list == NULL);
+
+ while (list != NULL) {
+ if (strcmp (info->location, (gchar *)list->data) == 0) {
+ g_free (list->data);
+ active_plugins = g_slist_delete_link (active_plugins, list);
+ list = NULL;
+ res = TRUE;
+ } else {
+ list = g_slist_next (list);
+ }
+ }
+
+ if (!res) {
+ g_warning ("Plugin '%s' is already deactivated.", info->name);
+
+ return TRUE;
+ }
+
+ res = mateconf_client_set_list (eom_plugin_engine_mateconf_client,
+ EOM_CONF_PLUGINS_ACTIVE_PLUGINS,
+ MATECONF_VALUE_STRING,
+ active_plugins,
+ NULL);
+
+ if (!res)
+ g_warning ("Error saving the list of active plugins.");
+
+ return TRUE;
+}
+
+gboolean
+eom_plugin_engine_plugin_is_active (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return (info->available && info->active);
+}
+
+gboolean
+eom_plugin_engine_plugin_is_available (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return (info->available != FALSE);
+}
+
+static void
+reactivate_all (EomWindow *window)
+{
+ GList *pl;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ for (pl = eom_plugins_list; pl; pl = pl->next) {
+ gboolean res = TRUE;
+
+ EomPluginInfo *info = (EomPluginInfo*)pl->data;
+
+ /* If plugin is not available, don't try to activate/load it */
+ if (info->available && info->active) {
+ if (info->plugin == NULL)
+ res = load_plugin_module (info);
+
+ if (res)
+ eom_plugin_activate (info->plugin,
+ window);
+ }
+ }
+
+ eom_debug_message (DEBUG_PLUGINS, "End");
+}
+
+void
+eom_plugin_engine_update_plugins_ui (EomWindow *window,
+ gboolean new_window)
+{
+ GList *pl;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (EOM_IS_WINDOW (window));
+
+ if (new_window)
+ reactivate_all (window);
+
+ /* Updated ui of all the plugins that implement update_ui */
+ for (pl = eom_plugins_list; pl; pl = pl->next) {
+ EomPluginInfo *info = (EomPluginInfo*)pl->data;
+
+ if (!info->available || !info->active)
+ continue;
+
+ eom_debug_message (DEBUG_PLUGINS, "Updating UI of %s", info->name);
+
+ eom_plugin_update_ui (info->plugin, window);
+ }
+}
+
+gboolean
+eom_plugin_engine_plugin_is_configurable (EomPluginInfo *info) {
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if ((info->plugin == NULL) || !info->active || !info->available)
+ return FALSE;
+
+ return eom_plugin_is_configurable (info->plugin);
+}
+
+void
+eom_plugin_engine_configure_plugin (EomPluginInfo *info,
+ GtkWindow *parent)
+{
+ GtkWidget *conf_dlg;
+
+ GtkWindowGroup *wg;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (info != NULL);
+
+ conf_dlg = eom_plugin_create_configure_dialog (info->plugin);
+
+ g_return_if_fail (conf_dlg != NULL);
+
+ gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
+ parent);
+
+ // Will return a default group if no group is set
+ wg = gtk_window_get_group (parent);
+
+ // For now assign a dedicated window group if it is
+ // the default one until we know if this is really needed
+ if (wg == gtk_window_get_group (NULL)) {
+ wg = gtk_window_group_new ();
+ gtk_window_group_add_window (wg, parent);
+ }
+
+ gtk_window_group_add_window (wg,
+ GTK_WINDOW (conf_dlg));
+
+ gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
+
+ gtk_widget_show (conf_dlg);
+}
+
+static void
+eom_plugin_engine_active_plugins_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ GList *pl;
+ gboolean to_activate;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (entry->key != NULL);
+ g_return_if_fail (entry->value != NULL);
+
+ if (!((entry->value->type == MATECONF_VALUE_LIST) &&
+ (mateconf_value_get_list_type (entry->value) == MATECONF_VALUE_STRING))) {
+ g_warning ("The mateconf key '%s' may be corrupted.", EOM_CONF_PLUGINS_ACTIVE_PLUGINS);
+ return;
+ }
+
+ active_plugins = mateconf_client_get_list (eom_plugin_engine_mateconf_client,
+ EOM_CONF_PLUGINS_ACTIVE_PLUGINS,
+ MATECONF_VALUE_STRING,
+ NULL);
+
+ for (pl = eom_plugins_list; pl; pl = pl->next) {
+ EomPluginInfo *info = (EomPluginInfo*)pl->data;
+
+ if (!info->available)
+ continue;
+
+ to_activate = (g_slist_find_custom (active_plugins,
+ info->location,
+ (GCompareFunc)strcmp) != NULL);
+
+ if (!info->active && to_activate) {
+ /* Activate plugin */
+ if (eom_plugin_engine_activate_plugin_real (info))
+ /* Update plugin state */
+ info->active = TRUE;
+ } else {
+ if (info->active && !to_activate) {
+ eom_plugin_engine_deactivate_plugin_real (info);
+
+ /* Update plugin state */
+ info->active = FALSE;
+ }
+ }
+ }
+}
+
+const gchar *
+eom_plugin_engine_get_plugin_name (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->name;
+}
+
+const gchar *
+eom_plugin_engine_get_plugin_description (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->desc;
+}
+
+const gchar *
+eom_plugin_engine_get_plugin_icon_name (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ /* Use the eom-plugin icon as a default if the plugin does not
+ have its own */
+ if (info->icon_name != NULL &&
+ gtk_icon_theme_has_icon (gtk_icon_theme_get_default (),
+ info->icon_name))
+ return info->icon_name;
+ else
+ return "eom-plugin";
+}
+
+const gchar **
+eom_plugin_engine_get_plugin_authors (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, (const gchar **)NULL);
+
+ return (const gchar **) info->authors;
+}
+
+const gchar *
+eom_plugin_engine_get_plugin_website (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->website;
+}
+
+const gchar *
+eom_plugin_engine_get_plugin_copyright (EomPluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->copyright;
+}
diff --git a/src/eom-plugin-engine.h b/src/eom-plugin-engine.h
new file mode 100644
index 0000000..bd2ce7f
--- /dev/null
+++ b/src/eom-plugin-engine.h
@@ -0,0 +1,89 @@
+/* Eye Of Mate - EOM Plugin Engine
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-plugins-engine.h) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_PLUGIN_ENGINE_H__
+#define __EOM_PLUGIN_ENGINE_H__
+
+#include "eom-window.h"
+
+#include <glib.h>
+
+typedef struct _EomPluginInfo EomPluginInfo;
+
+G_GNUC_INTERNAL
+gboolean eom_plugin_engine_init (void);
+
+G_GNUC_INTERNAL
+void eom_plugin_engine_shutdown (void);
+
+G_GNUC_INTERNAL
+void eom_plugin_engine_garbage_collect (void);
+
+G_GNUC_INTERNAL
+const GList *eom_plugin_engine_get_plugins_list (void);
+
+G_GNUC_INTERNAL
+gboolean eom_plugin_engine_activate_plugin (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+gboolean eom_plugin_engine_deactivate_plugin (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+gboolean eom_plugin_engine_plugin_is_active (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+gboolean eom_plugin_engine_plugin_is_available (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+gboolean eom_plugin_engine_plugin_is_configurable
+ (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+void eom_plugin_engine_configure_plugin (EomPluginInfo *info,
+ GtkWindow *parent);
+
+G_GNUC_INTERNAL
+void eom_plugin_engine_update_plugins_ui (EomWindow *window,
+ gboolean new_window);
+
+G_GNUC_INTERNAL
+const gchar *eom_plugin_engine_get_plugin_name (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+const gchar *eom_plugin_engine_get_plugin_description
+ (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+const gchar *eom_plugin_engine_get_plugin_icon_name (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+const gchar **eom_plugin_engine_get_plugin_authors (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+const gchar *eom_plugin_engine_get_plugin_website (EomPluginInfo *info);
+
+G_GNUC_INTERNAL
+const gchar *eom_plugin_engine_get_plugin_copyright (EomPluginInfo *info);
+
+#endif /* __EOM_PLUGIN_ENGINE_H__ */
diff --git a/src/eom-plugin-manager.c b/src/eom-plugin-manager.c
new file mode 100644
index 0000000..623827f
--- /dev/null
+++ b/src/eom-plugin-manager.c
@@ -0,0 +1,917 @@
+/* Eye Of Mate - EOM Plugin Manager
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "eom-plugin-manager.h"
+#include "eom-plugin-engine.h"
+#include "eom-util.h"
+#include "eom-plugin.h"
+#include "eom-debug.h"
+
+#include <glib/gi18n.h>
+
+enum {
+ ACTIVE_COLUMN,
+ AVAILABLE_COLUMN,
+ INFO_COLUMN,
+ N_COLUMNS
+};
+
+#define EOM_PLUGIN_MANAGER_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_PLUGIN_MANAGER, EomPluginManagerPrivate))
+
+G_DEFINE_TYPE (EomPluginManager, eom_plugin_manager, GTK_TYPE_VBOX)
+
+#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
+#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
+
+struct _EomPluginManagerPrivate {
+ GtkWidget *tree;
+
+ GtkWidget *about_button;
+ GtkWidget *configure_button;
+
+ const GList *plugins;
+
+ GtkWidget *about;
+
+ GtkWidget *popup_menu;
+};
+
+static EomPluginInfo *plugin_manager_get_selected_plugin (EomPluginManager *pm);
+static void plugin_manager_toggle_active (GtkTreeIter *iter, GtkTreeModel *model);
+static void eom_plugin_manager_finalize (GObject *object);
+
+static void
+eom_plugin_manager_class_init (EomPluginManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = eom_plugin_manager_finalize;
+
+ g_type_class_add_private (object_class, sizeof (EomPluginManagerPrivate));
+}
+
+static void
+about_button_cb (GtkWidget *button,
+ EomPluginManager *pm)
+{
+ EomPluginInfo *info;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ g_return_if_fail (info != NULL);
+
+ /* If there is another about dialog already open destroy it */
+ if (pm->priv->about)
+ gtk_widget_destroy (pm->priv->about);
+
+ pm->priv->about = g_object_new (GTK_TYPE_ABOUT_DIALOG,
+ "program-name" , eom_plugin_engine_get_plugin_name (info),
+ "copyright", eom_plugin_engine_get_plugin_copyright (info),
+ "authors", eom_plugin_engine_get_plugin_authors (info),
+ "comments", eom_plugin_engine_get_plugin_description (info),
+ "website", eom_plugin_engine_get_plugin_website (info),
+ "logo-icon-name", eom_plugin_engine_get_plugin_icon_name (info),
+ NULL);
+
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (pm->priv->about),
+ TRUE);
+
+ g_signal_connect (pm->priv->about,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ g_signal_connect (pm->priv->about,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &pm->priv->about);
+
+ gtk_window_set_transient_for (GTK_WINDOW (pm->priv->about),
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm))));
+
+ gtk_widget_show (pm->priv->about);
+}
+
+static void
+configure_button_cb (GtkWidget *button,
+ EomPluginManager *pm)
+{
+ EomPluginInfo *info;
+ GtkWindow *toplevel;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ g_return_if_fail (info != NULL);
+
+ eom_debug_message (DEBUG_PLUGINS, "Configuring: %s\n",
+ eom_plugin_engine_get_plugin_name (info));
+
+ toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm)));
+
+ eom_plugin_engine_configure_plugin (info, toplevel);
+
+ eom_debug_message (DEBUG_PLUGINS, "Done");
+}
+
+static void
+plugin_manager_view_info_cell_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ EomPluginInfo *info;
+ gchar *text;
+
+ g_return_if_fail (tree_model != NULL);
+ g_return_if_fail (tree_column != NULL);
+
+ gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
+
+ if (info == NULL)
+ return;
+
+ text = g_markup_printf_escaped ("<b>%s</b>\n%s",
+ eom_plugin_engine_get_plugin_name (info),
+ eom_plugin_engine_get_plugin_description (info));
+
+ g_object_set (G_OBJECT (cell),
+ "markup", text,
+ "sensitive", eom_plugin_engine_plugin_is_available (info),
+ NULL);
+
+ g_free (text);
+}
+
+static void
+plugin_manager_view_icon_cell_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ EomPluginInfo *info;
+
+ g_return_if_fail (tree_model != NULL);
+ g_return_if_fail (tree_column != NULL);
+
+ gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
+
+ if (info == NULL)
+ return;
+
+ g_object_set (G_OBJECT (cell),
+ "icon-name", eom_plugin_engine_get_plugin_icon_name (info),
+ "sensitive", eom_plugin_engine_plugin_is_available (info),
+ NULL);
+}
+
+
+static void
+active_toggled_cb (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ EomPluginManager *pm)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ path = gtk_tree_path_new_from_string (path_str);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ if (&iter != NULL)
+ plugin_manager_toggle_active (&iter, model);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+cursor_changed_cb (GtkTreeView *view,
+ gpointer data)
+{
+ EomPluginManager *pm = data;
+ EomPluginInfo *info;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->about_button),
+ info != NULL);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
+ (info != NULL) &&
+ eom_plugin_engine_plugin_is_configurable (info));
+}
+
+static void
+row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data)
+{
+ EomPluginManager *pm = data;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ g_return_if_fail (&iter != NULL);
+
+ plugin_manager_toggle_active (&iter, model);
+}
+
+static void
+plugin_manager_populate_lists (EomPluginManager *pm)
+{
+ const GList *plugins;
+ GtkListStore *model;
+ GtkTreeIter iter;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ plugins = pm->priv->plugins;
+
+ model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)));
+
+ while (plugins) {
+ EomPluginInfo *info;
+ info = (EomPluginInfo *)plugins->data;
+
+ gtk_list_store_append (model, &iter);
+ gtk_list_store_set (model, &iter,
+ ACTIVE_COLUMN, eom_plugin_engine_plugin_is_active (info),
+ AVAILABLE_COLUMN, eom_plugin_engine_plugin_is_available (info),
+ INFO_COLUMN, info,
+ -1);
+
+ plugins = plugins->next;
+ }
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
+ GtkTreeSelection *selection;
+ EomPluginInfo* info;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (selection != NULL);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
+ INFO_COLUMN, &info, -1);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
+ eom_plugin_engine_plugin_is_configurable (info));
+ }
+}
+
+static gboolean
+plugin_manager_set_active (GtkTreeIter *iter,
+ GtkTreeModel *model,
+ gboolean active)
+{
+ EomPluginInfo *info;
+ gboolean res = TRUE;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (active) {
+ /* Activate the plugin */
+ if (!eom_plugin_engine_activate_plugin (info)) {
+ eom_debug_message (DEBUG_PLUGINS, "Could not activate %s.\n",
+ eom_plugin_engine_get_plugin_name (info));
+
+ res = FALSE;
+ }
+ } else {
+ /* Deactivate the plugin */
+ if (!eom_plugin_engine_deactivate_plugin (info)) {
+ eom_debug_message (DEBUG_PLUGINS, "Could not deactivate %s.\n",
+ eom_plugin_engine_get_plugin_name (info));
+
+ res = FALSE;
+ }
+ }
+
+ /* Set new value */
+ gtk_list_store_set (GTK_LIST_STORE (model),
+ iter,
+ ACTIVE_COLUMN, eom_plugin_engine_plugin_is_active (info),
+ AVAILABLE_COLUMN, eom_plugin_engine_plugin_is_available (info),
+ -1);
+
+ return res;
+}
+
+static void
+plugin_manager_toggle_active (GtkTreeIter *iter,
+ GtkTreeModel *model)
+{
+ gboolean active;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1);
+
+ active ^= 1;
+
+ plugin_manager_set_active (iter, model, active);
+}
+
+static EomPluginInfo *
+plugin_manager_get_selected_plugin (EomPluginManager *pm)
+{
+ EomPluginInfo *info = NULL;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_val_if_fail (model != NULL, NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_val_if_fail (selection != NULL, NULL);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1);
+ }
+
+ return info;
+}
+
+static void
+plugin_manager_set_active_all (EomPluginManager *pm,
+ gboolean active)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ gtk_tree_model_get_iter_first (model, &iter);
+
+ do {
+ plugin_manager_set_active (&iter, model, active);
+ } while (gtk_tree_model_iter_next (model, &iter));
+}
+
+/* Callback used as the interactive search comparison function */
+static gboolean
+name_search_cb (GtkTreeModel *model,
+ gint column,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ EomPluginInfo *info;
+ gchar *normalized_string;
+ gchar *normalized_key;
+ gchar *case_normalized_string;
+ gchar *case_normalized_key;
+ gint key_len;
+ gboolean retval;
+
+ gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+
+ if (!info)
+ return FALSE;
+
+ normalized_string = g_utf8_normalize (eom_plugin_engine_get_plugin_name (info), -1, G_NORMALIZE_ALL);
+ normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+ case_normalized_string = g_utf8_casefold (normalized_string, -1);
+ case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+ key_len = strlen (case_normalized_key);
+
+ /* Oddly enough, this callback must return whether to stop the search
+ * because we found a match, not whether we actually matched. */
+ retval = (strncmp (case_normalized_key, case_normalized_string, key_len) != 0);
+
+ g_free (normalized_key);
+ g_free (normalized_string);
+ g_free (case_normalized_key);
+ g_free (case_normalized_string);
+
+ return retval;
+}
+
+static void
+enable_plugin_menu_cb (GtkMenu *menu,
+ EomPluginManager *pm)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (selection != NULL);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ plugin_manager_toggle_active (&iter, model);
+}
+
+static void
+enable_all_menu_cb (GtkMenu *menu,
+ EomPluginManager *pm)
+{
+ plugin_manager_set_active_all (pm, TRUE);
+}
+
+static void
+disable_all_menu_cb (GtkMenu *menu,
+ EomPluginManager *pm)
+{
+ plugin_manager_set_active_all (pm, FALSE);
+}
+
+static GtkWidget *
+create_tree_popup_menu (EomPluginManager *pm)
+{
+ GtkWidget *menu;
+ GtkWidget *item;
+ GtkWidget *image;
+ EomPluginInfo *info;
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ if (info == NULL)
+ return NULL;
+
+ menu = gtk_menu_new ();
+
+ item = gtk_image_menu_item_new_with_mnemonic (_("_About"));
+ image = gtk_image_new_from_stock (GTK_STOCK_ABOUT,
+ GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (item, "activate",
+ G_CALLBACK (about_button_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_image_menu_item_new_with_mnemonic (_("C_onfigure"));
+ image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
+ GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (item, "activate",
+ G_CALLBACK (configure_button_cb), pm);
+ gtk_widget_set_sensitive (item,
+ eom_plugin_engine_plugin_is_configurable (info));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_check_menu_item_new_with_mnemonic (_("A_ctivate"));
+ gtk_widget_set_sensitive (item,
+ eom_plugin_engine_plugin_is_available (info));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
+ eom_plugin_engine_plugin_is_active (info));
+ g_signal_connect (item, "toggled",
+ G_CALLBACK (enable_plugin_menu_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Ac_tivate All"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (enable_all_menu_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Deactivate All"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (disable_all_menu_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ gtk_widget_show_all (menu);
+
+ return menu;
+}
+
+static void
+tree_popup_menu_detach (EomPluginManager *pm,
+ GtkMenu *menu)
+{
+ pm->priv->popup_menu = NULL;
+}
+
+static void
+menu_position_under_widget (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GtkWidget *w = GTK_WIDGET (user_data);
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+
+ gdk_window_get_origin (gtk_widget_get_window (w), x, y);
+ gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+ gtk_widget_get_allocation (w, &allocation);
+
+ if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL) {
+ *x += allocation.x + allocation.width - requisition.width;
+ } else {
+ *x += allocation.x;
+ }
+
+ *y += allocation.y + allocation.height;
+
+ *push_in = TRUE;
+}
+
+static void
+menu_position_under_tree_view (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GtkTreeView *tree = GTK_TREE_VIEW (user_data);
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (tree);
+
+ g_return_if_fail (model != NULL);
+
+ selection = gtk_tree_view_get_selection (tree);
+
+ g_return_if_fail (selection != NULL);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ GtkTreePath *path;
+ GdkRectangle rect;
+
+ gdk_window_get_origin (gtk_widget_get_window(GTK_WIDGET (tree)),
+ x, y);
+
+ path = gtk_tree_model_get_path (model, &iter);
+
+ gtk_tree_view_get_cell_area (tree,
+ path,
+ gtk_tree_view_get_column (tree, 0), /* FIXME 0 for RTL ? */
+ &rect);
+ gtk_tree_path_free (path);
+
+ *x += rect.x;
+ *y += rect.y + rect.height;
+
+ if (gtk_widget_get_direction (GTK_WIDGET (tree)) == GTK_TEXT_DIR_RTL) {
+ GtkRequisition requisition;
+
+ gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+
+ *x += rect.width - requisition.width;
+ }
+ } else {
+ /* No selection -> regular "under widget" positioning */
+ menu_position_under_widget (menu,
+ x, y, push_in,
+ tree);
+ }
+}
+static void
+show_tree_popup_menu (GtkTreeView *tree,
+ EomPluginManager *pm,
+ GdkEventButton *event)
+{
+ if (pm->priv->popup_menu)
+ gtk_widget_destroy (pm->priv->popup_menu);
+
+ pm->priv->popup_menu = create_tree_popup_menu (pm);
+
+ if (pm->priv->popup_menu == NULL)
+ return;
+
+ gtk_menu_attach_to_widget (GTK_MENU (pm->priv->popup_menu),
+ GTK_WIDGET (pm),
+ (GtkMenuDetachFunc) tree_popup_menu_detach);
+
+ if (event != NULL) {
+ gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
+ NULL, NULL,
+ event->button, event->time);
+ } else {
+ gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
+ menu_position_under_tree_view, tree,
+ 0, gtk_get_current_event_time ());
+
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (pm->priv->popup_menu),
+ FALSE);
+ }
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *tree,
+ GdkEventButton *event,
+ EomPluginManager *pm)
+{
+ /* We want the treeview selection to be updated before showing the menu.
+ * This code is evil, thanks to Federico Mena Quintero's black magic.
+ * See: http://mail.gnome.org/archives/gtk-devel-list/2006-February/msg00168.html
+ * FIXME: Let's remove it asap.
+ */
+ static gboolean in_press = FALSE;
+ gboolean handled;
+
+ if (in_press)
+ return FALSE; /* we re-entered */
+
+ if (GDK_BUTTON_PRESS != event->type || 3 != event->button)
+ return FALSE; /* let the normal handler run */
+
+ in_press = TRUE;
+ handled = gtk_widget_event (tree, (GdkEvent *) event);
+ in_press = FALSE;
+
+ if (!handled)
+ return FALSE;
+
+ /* The selection is fully updated by now */
+ show_tree_popup_menu (GTK_TREE_VIEW (tree), pm, event);
+
+ return TRUE;
+}
+
+static gboolean
+popup_menu_cb (GtkTreeView *tree,
+ EomPluginManager *pm)
+{
+ show_tree_popup_menu (tree, pm, NULL);
+
+ return TRUE;
+}
+
+static gint
+model_name_sort_func (GtkTreeModel *model,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2,
+ gpointer user_data)
+{
+ EomPluginInfo *info1, *info2;
+
+ gtk_tree_model_get (model, iter1, INFO_COLUMN, &info1, -1);
+ gtk_tree_model_get (model, iter2, INFO_COLUMN, &info2, -1);
+
+ return g_utf8_collate (eom_plugin_engine_get_plugin_name (info1),
+ eom_plugin_engine_get_plugin_name (info2));
+}
+
+static void
+plugin_manager_construct_tree (EomPluginManager *pm)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ GtkListStore *model;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ model = gtk_list_store_new (N_COLUMNS,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_POINTER);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree),
+ GTK_TREE_MODEL (model));
+
+ g_object_unref (model);
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pm->priv->tree), FALSE);
+
+ /* First column */
+ cell = gtk_cell_renderer_toggle_new ();
+ g_object_set (cell, "xpad", 6, NULL);
+ g_signal_connect (cell,
+ "toggled",
+ G_CALLBACK (active_toggled_cb),
+ pm);
+ column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE,
+ cell,
+ "active", ACTIVE_COLUMN,
+ "activatable", AVAILABLE_COLUMN,
+ "sensitive", AVAILABLE_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
+
+ /* Second column */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, PLUGIN_MANAGER_NAME_TITLE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ g_object_set (cell, "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
+ gtk_tree_view_column_set_cell_data_func (column, cell,
+ plugin_manager_view_icon_cell_cb,
+ pm, NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_set_cell_data_func (column, cell,
+ plugin_manager_view_info_cell_cb,
+ pm, NULL);
+
+ gtk_tree_view_column_set_spacing (column, 6);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
+
+ /* Sort on the plugin names */
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
+ model_name_sort_func,
+ NULL,
+ NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ /* Enable search for our non-string column */
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree),
+ INFO_COLUMN);
+ gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree),
+ name_search_cb,
+ NULL,
+ NULL);
+
+ g_signal_connect (pm->priv->tree,
+ "cursor_changed",
+ G_CALLBACK (cursor_changed_cb),
+ pm);
+
+ g_signal_connect (pm->priv->tree,
+ "row_activated",
+ G_CALLBACK (row_activated_cb),
+ pm);
+
+ g_signal_connect (pm->priv->tree,
+ "button-press-event",
+ G_CALLBACK (button_press_event_cb),
+ pm);
+
+ g_signal_connect (pm->priv->tree,
+ "popup-menu",
+ G_CALLBACK (popup_menu_cb),
+ pm);
+
+ gtk_widget_show (pm->priv->tree);
+}
+
+static void
+eom_plugin_manager_init (EomPluginManager *pm)
+{
+ GtkWidget *label;
+ GtkWidget *viewport;
+ GtkWidget *hbuttonbox;
+
+ eom_debug (DEBUG_PLUGINS);
+
+ pm->priv = EOM_PLUGIN_MANAGER_GET_PRIVATE (pm);
+
+ gtk_box_set_spacing (GTK_BOX (pm), 6);
+
+ label = gtk_label_new_with_mnemonic (_("Active _Plugins:"));
+
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+ gtk_box_pack_start (GTK_BOX (pm), label, FALSE, TRUE, 0);
+
+ viewport = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport),
+ GTK_SHADOW_IN);
+
+ gtk_box_pack_start (GTK_BOX (pm), viewport, TRUE, TRUE, 0);
+
+ pm->priv->tree = gtk_tree_view_new ();
+ gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), pm->priv->tree);
+
+ hbuttonbox = gtk_hbutton_box_new ();
+
+ gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0);
+
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing (GTK_BOX (hbuttonbox), 8);
+
+ pm->priv->about_button = gtk_button_new_with_mnemonic (_("_About Plugin"));
+ gtk_button_set_image (GTK_BUTTON (pm->priv->about_button),
+ gtk_image_new_from_stock (GTK_STOCK_ABOUT,
+ GTK_ICON_SIZE_BUTTON));
+
+ gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->about_button);
+
+ pm->priv->configure_button = gtk_button_new_with_mnemonic (_("C_onfigure Plugin"));
+ gtk_button_set_image (GTK_BUTTON (pm->priv->configure_button),
+ gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
+ GTK_ICON_SIZE_BUTTON));
+
+ gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button);
+
+ gtk_widget_set_size_request (GTK_WIDGET (viewport), 270, 100);
+
+ g_signal_connect (pm->priv->about_button,
+ "clicked",
+ G_CALLBACK (about_button_cb),
+ pm);
+
+ g_signal_connect (pm->priv->configure_button,
+ "clicked",
+ G_CALLBACK (configure_button_cb),
+ pm);
+
+ plugin_manager_construct_tree (pm);
+
+ /* Get the list of available plugins (or installed) */
+ pm->priv->plugins = eom_plugin_engine_get_plugins_list ();
+
+ if (pm->priv->plugins != NULL) {
+ plugin_manager_populate_lists (pm);
+ } else {
+ gtk_widget_set_sensitive (pm->priv->about_button, FALSE);
+ gtk_widget_set_sensitive (pm->priv->configure_button, FALSE);
+ }
+}
+
+static void
+eom_plugin_manager_finalize (GObject *object)
+{
+ EomPluginManager *pm = EOM_PLUGIN_MANAGER (object);
+
+ if (pm->priv->popup_menu)
+ gtk_widget_destroy (pm->priv->popup_menu);
+
+ G_OBJECT_CLASS (eom_plugin_manager_parent_class)->finalize (object);
+}
+
+GtkWidget *
+eom_plugin_manager_new (void)
+{
+ return g_object_new (EOM_TYPE_PLUGIN_MANAGER, NULL);
+}
diff --git a/src/eom-plugin-manager.h b/src/eom-plugin-manager.h
new file mode 100644
index 0000000..e35c817
--- /dev/null
+++ b/src/eom-plugin-manager.h
@@ -0,0 +1,61 @@
+/* Eye Of Mate - EOM Plugin Manager
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_PLUGIN_MANAGER_H__
+#define __EOM_PLUGIN_MANAGER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EomPluginManager EomPluginManager;
+typedef struct _EomPluginManagerClass EomPluginManagerClass;
+typedef struct _EomPluginManagerPrivate EomPluginManagerPrivate;
+
+#define EOM_TYPE_PLUGIN_MANAGER (eom_plugin_manager_get_type())
+#define EOM_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_PLUGIN_MANAGER, EomPluginManager))
+#define EOM_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_PLUGIN_MANAGER, EomPluginManagerClass))
+#define EOM_IS_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_PLUGIN_MANAGER))
+#define EOM_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_PLUGIN_MANAGER))
+#define EOM_PLUGIN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EOM_TYPE_PLUGIN_MANAGER, EomPluginManagerClass))
+
+struct _EomPluginManager {
+ GtkVBox vbox;
+
+ EomPluginManagerPrivate *priv;
+};
+
+struct _EomPluginManagerClass {
+ GtkVBoxClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType eom_plugin_manager_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkWidget *eom_plugin_manager_new (void);
+
+G_END_DECLS
+
+#endif /* __EOM_PLUGIN_MANAGER_H__ */
diff --git a/src/eom-plugin.c b/src/eom-plugin.c
new file mode 100644
index 0000000..7210128
--- /dev/null
+++ b/src/eom-plugin.c
@@ -0,0 +1,108 @@
+/* Eye Of Mate - EOM Plugin
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eom-plugin.h"
+
+G_DEFINE_TYPE (EomPlugin, eom_plugin, G_TYPE_OBJECT)
+
+static void
+dummy (EomPlugin *plugin, EomWindow *window)
+{
+}
+
+static GtkWidget *
+create_configure_dialog (EomPlugin *plugin)
+{
+ return NULL;
+}
+
+static gboolean
+is_configurable (EomPlugin *plugin)
+{
+ return (EOM_PLUGIN_GET_CLASS (plugin)->create_configure_dialog !=
+ create_configure_dialog);
+}
+
+static void
+eom_plugin_class_init (EomPluginClass *klass)
+{
+ klass->activate = dummy;
+ klass->deactivate = dummy;
+ klass->update_ui = dummy;
+
+ klass->create_configure_dialog = create_configure_dialog;
+ klass->is_configurable = is_configurable;
+}
+
+static void
+eom_plugin_init (EomPlugin *plugin)
+{
+}
+
+void
+eom_plugin_activate (EomPlugin *plugin, EomWindow *window)
+{
+ g_return_if_fail (EOM_IS_PLUGIN (plugin));
+ g_return_if_fail (EOM_IS_WINDOW (window));
+
+ EOM_PLUGIN_GET_CLASS (plugin)->activate (plugin, window);
+}
+
+void
+eom_plugin_deactivate (EomPlugin *plugin, EomWindow *window)
+{
+ g_return_if_fail (EOM_IS_PLUGIN (plugin));
+ g_return_if_fail (EOM_IS_WINDOW (window));
+
+ EOM_PLUGIN_GET_CLASS (plugin)->deactivate (plugin, window);
+}
+
+void
+eom_plugin_update_ui (EomPlugin *plugin, EomWindow *window)
+{
+ g_return_if_fail (EOM_IS_PLUGIN (plugin));
+ g_return_if_fail (EOM_IS_WINDOW (window));
+
+ EOM_PLUGIN_GET_CLASS (plugin)->update_ui (plugin, window);
+}
+
+gboolean
+eom_plugin_is_configurable (EomPlugin *plugin)
+{
+ g_return_val_if_fail (EOM_IS_PLUGIN (plugin), FALSE);
+
+ return EOM_PLUGIN_GET_CLASS (plugin)->is_configurable (plugin);
+}
+
+GtkWidget *
+eom_plugin_create_configure_dialog (EomPlugin *plugin)
+{
+ g_return_val_if_fail (EOM_IS_PLUGIN (plugin), NULL);
+
+ return EOM_PLUGIN_GET_CLASS (plugin)->create_configure_dialog (plugin);
+}
diff --git a/src/eom-plugin.h b/src/eom-plugin.h
new file mode 100644
index 0000000..83151e9
--- /dev/null
+++ b/src/eom-plugin.h
@@ -0,0 +1,222 @@
+/* Eye Of Mate - EOM Plugin
+ *
+ * Copyright (C) 2007 The Free Software Foundation
+ *
+ * Author: Lucas Rocha <[email protected]>
+ *
+ * Based on gedit code (gedit/gedit-module.c) by:
+ * - Paolo Maggi <[email protected]>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EOM_PLUGIN_H__
+#define __EOM_PLUGIN_H__
+
+#include "eom-window.h"
+#include "eom-debug.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EomPlugin EomPlugin;
+typedef struct _EomPluginClass EomPluginClass;
+typedef struct _EomPluginPrivate EomPluginPrivate;
+
+#define EOM_TYPE_PLUGIN (eom_plugin_get_type())
+#define EOM_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_PLUGIN, EomPlugin))
+#define EOM_PLUGIN_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EOM_TYPE_PLUGIN, EomPlugin const))
+#define EOM_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_PLUGIN, EomPluginClass))
+#define EOM_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EOM_TYPE_PLUGIN))
+#define EOM_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_PLUGIN))
+#define EOM_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EOM_TYPE_PLUGIN, EomPluginClass))
+
+struct _EomPlugin {
+ GObject parent;
+};
+
+struct _EomPluginClass {
+ GObjectClass parent_class;
+
+ void (*activate) (EomPlugin *plugin,
+ EomWindow *window);
+
+ void (*deactivate) (EomPlugin *plugin,
+ EomWi