Fri Nov 24 21:37:01 2006 John Ellis <johne@verizon.net>
authorJohn Ellis <johne@verizon.net>
Sat, 25 Nov 2006 03:00:33 +0000 (03:00 +0000)
committerJohn Ellis <johne@verizon.net>
Sat, 25 Nov 2006 03:00:33 +0000 (03:00 +0000)
        * configure.in: Add test for lcms (little cms).
        * Makefile.am: Add color-man.[ch]:
        * color-man.[ch]: New files for color management support.
        * globals.c, gqview.h, main.c, rcfile.c, typedefs.h: Add color profile
        variables and option saving.
        * image.[ch]: Add color profile functions.
        * layout.c, layout_image.[ch]: Add color profile icon, popup menu, and
        fix sort menu to use radio buttons.
        * menu.c: Use radio buttons for sort menu when appropriate.
        * preferences.c: Add color profile options to preferences.
        * ui_menu.[ch]: Add menu_item_add_radio() for radio item menus.
        * ui_misc.c: Fix gtk_table_attach() arg for vertical expansion.
        * view_file_icon.c, view_file_list.c: Check for active state in sort
        menu callbacks.
        * README: Add info about lcms, and how to disable.

24 files changed:
ChangeLog
README
TODO
configure.in
src/Makefile.am
src/color-man.c [new file with mode: 0644]
src/color-man.h [new file with mode: 0644]
src/globals.c
src/gqview.h
src/image.c
src/image.h
src/layout.c
src/layout_image.c
src/layout_image.h
src/main.c
src/menu.c
src/preferences.c
src/rcfile.c
src/typedefs.h
src/ui_menu.c
src/ui_menu.h
src/ui_misc.c
src/view_file_icon.c
src/view_file_list.c

index 56cdcf8..8c91a33 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Fri Nov 24 21:37:01 2006  John Ellis  <johne@verizon.net>
+
+       * configure.in: Add test for lcms (little cms).
+       * Makefile.am: Add color-man.[ch]:
+       * color-man.[ch]: New files for color management support.
+       * globals.c, gqview.h, main.c, rcfile.c, typedefs.h: Add color profile
+       variables and option saving.
+       * image.[ch]: Add color profile functions.
+       * layout.c, layout_image.[ch]: Add color profile icon, popup menu, and
+       fix sort menu to use radio buttons.
+       * menu.c: Use radio buttons for sort menu when appropriate.
+       * preferences.c: Add color profile options to preferences.
+       * ui_menu.[ch]: Add menu_item_add_radio() for radio item menus.
+       * ui_misc.c: Fix gtk_table_attach() arg for vertical expansion.
+       * view_file_icon.c, view_file_list.c: Check for active state in sort
+       menu callbacks.
+       * README: Add info about lcms, and how to disable.
+
 Fri Nov 17 19:06:19 2006  John Ellis  <johne@verizon.net>
 
        * ui_fileops.[ch]: Add path_list_lstat() to obtain a path listing that
 Fri Nov 17 19:06:19 2006  John Ellis  <johne@verizon.net>
 
        * ui_fileops.[ch]: Add path_list_lstat() to obtain a path listing that
diff --git a/README b/README
index df09b5e..8eb860b 100644 (file)
--- a/README
+++ b/README
@@ -38,7 +38,12 @@ homepage: http://gqview.sourceforge.net
 
 ======== Requirements
 
 
 ======== Requirements
 
-  GTK+ 2.4.x: ftp://ftp.gtk.org/pub/gtk
+  Required libraries:
+    GTK+ 2.4.x: ftp://ftp.gtk.org/pub/gtk
+
+  Optional libraries:
+    lcms, for color management support: http://www.littlecms.com
+        (disable with configure option: '--without-lcms')
 
 ======== Notes and changes for this release            [section:release_notes]
 
 
 ======== Notes and changes for this release            [section:release_notes]
 
@@ -81,6 +86,10 @@ homepage: http://gqview.sourceforge.net
 
     Version in perenthesis indicates first appearance of feature or change.
 
 
     Version in perenthesis indicates first appearance of feature or change.
 
+    (2.1.5) Add support for color profiles when lcms is installed. To
+    disable color profiles and use of lcms, run configure
+    with '--without-lcms'.
+
     (2.1.1) Add support for viewing jpeg images and EXIF embedded within
     raw files for Canon (.crw, .cr2) Fujifilm (.raf), and Nikon (.nef).
     Note that not all cameras that support a raw format will necessarily
     (2.1.1) Add support for viewing jpeg images and EXIF embedded within
     raw files for Canon (.crw, .cr2) Fujifilm (.raf), and Nikon (.nef).
     Note that not all cameras that support a raw format will necessarily
diff --git a/TODO b/TODO
index 71cf578..ded5ffb 100644 (file)
--- a/TODO
+++ b/TODO
@@ -21,6 +21,10 @@ d> figure out if crash when expanding a folder in the folder tree view when pess
  > cache-load.c:
    > should honor enable_thumbnails setting
 
  > cache-load.c:
    > should honor enable_thumbnails setting
 
+ > color profiles:
+   > support profiles embedded in images
+   > add support in img-view.c
+
   ---
 
  >raw + exif formats:
   ---
 
  >raw + exif formats:
@@ -101,6 +105,7 @@ d> figure out if crash when expanding a folder in the folder tree view when pess
    > [Control]+V now shows image in new window
    > [Shift]+P print shortcut added to collection and img-view windows.
      (fixme, forgot to add it to find dialog).
    > [Control]+V now shows image in new window
    > [Shift]+P print shortcut added to collection and img-view windows.
      (fixme, forgot to add it to find dialog).
+   > add color profile page
 
    > add blurb about moving images between collections with shift+drag
 
 
    > add blurb about moving images between collections with shift+drag
 
@@ -113,6 +118,8 @@ Minor (non blockers):
 
 d> update icon used for window to the (not so) new icon
 
 
 d> update icon used for window to the (not so) new icon
 
+ > fix gtk_table_attach use to not use FALSE for fill vertical arg.
+
  > xv and xpaint are hardly used or even installed by any distro anymore - time
    to remove these (and find alternates?) seems silly to only have gimp.
 
  > xv and xpaint are hardly used or even installed by any distro anymore - time
    to remove these (and find alternates?) seems silly to only have gimp.
 
index eb4ba44..599099b 100644 (file)
@@ -25,6 +25,33 @@ AC_DEFINE_UNQUOTED(GQVIEW_HTMLDIR, "$prefix/share/doc/gqview-$VERSION/html", [Lo
 dnl checks for functions
 AC_CHECK_FUNCS(strverscmp)
 
 dnl checks for functions
 AC_CHECK_FUNCS(strverscmp)
 
+dnl check for little cms (lcms, this test pulled from gimp)
+AC_ARG_WITH(lcms, [  --without-lcms          build without lcms support])
+
+have_lcms=no
+if test "x$with_lcms" != "xno"; then
+  AC_CHECK_LIB(lcms, cmsCreate_sRGBProfile, [
+    AC_CHECK_HEADER(lcms.h,
+      have_lcms=yes, [
+      AC_CHECK_HEADER(lcms/lcms.h,
+        have_lcms=yes
+        AC_DEFINE(HAVE_LCMS_LCMS_H, 1,
+          [Define to 1 if the lcms header must be included as lcms/lcms.h]))
+      ])
+  ])
+  if test "$have_lcms" = "yes"; then
+    LCMS_LIBS="-llcms"
+    AC_DEFINE(HAVE_LCMS, 1, [define to enable use of color profiles with lcms])
+  else
+    have_lcms="no (lcms not found or unusable)"
+  fi
+else
+  have_lcms="no (lcms support disabled)"
+fi
+
+AC_SUBST(LCMS_LIBS)
+AM_CONDITIONAL(HAVE_LCMS, test "$have_lcms" = "yes")
+
 ALL_LINGUAS="ar be bg ca cs da de eo es et eu fi fr hu id it ja ko nl no pl pt_BR ro ru sk sl sv th tr uk vi zh_CN.GB2312 zh_TW"
 GETTEXT_PACKAGE=$PACKAGE
 AC_SUBST(GETTEXT_PACKAGE)
 ALL_LINGUAS="ar be bg ca cs da de eo es et eu fi fr hu id it ja ko nl no pl pt_BR ro ru sk sl sv th tr uk vi zh_CN.GB2312 zh_TW"
 GETTEXT_PACKAGE=$PACKAGE
 AC_SUBST(GETTEXT_PACKAGE)
index 9a86f6f..7ce4702 100644 (file)
@@ -74,6 +74,8 @@ gqview_SOURCES = \
        collect-io.h    \
        collect-table.c \
        collect-table.h \
        collect-io.h    \
        collect-table.c \
        collect-table.h \
+       color-man.c     \
+       color-man.h     \
        dnd.c           \
        dnd.h           \
        dupe.c          \
        dnd.c           \
        dnd.h           \
        dupe.c          \
@@ -164,7 +166,7 @@ gqview_SOURCES = \
        view_file_icon.c        \
        view_file_icon.h
 
        view_file_icon.c        \
        view_file_icon.h
 
-gqview_LDADD = $(GTK_LIBS) $(INTLLIBS)
+gqview_LDADD = $(GTK_LIBS) $(INTLLIBS) $(LCMS_LIBS)
 
 EXTRA_DIST = \
        $(extra_SLIK)
 
 EXTRA_DIST = \
        $(extra_SLIK)
diff --git a/src/color-man.c b/src/color-man.c
new file mode 100644 (file)
index 0000000..5c52457
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * GQview
+ * (C) 2006 John Ellis
+ *
+ * Author: John Ellis
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+
+#include "gqview.h"
+#include "color-man.h"
+
+#include "image.h"
+#include "ui_fileops.h"
+
+
+#ifdef HAVE_LCMS
+/*** color support enabled ***/
+
+#ifdef HAVE_LCMS_LCMS_H
+  #include <lcms/lcms.h>
+#else
+  #include <lcms.h>
+#endif
+
+
+typedef struct _ColorManCache ColorManCache;
+struct _ColorManCache {
+       cmsHPROFILE   profile_in;
+       cmsHPROFILE   profile_out;
+       cmsHTRANSFORM transform;
+
+       ColorManProfileType profile_in_type;
+       gchar *profile_in_file;
+
+       ColorManProfileType profile_out_type;
+       gchar *profile_out_file;
+
+       gint has_alpha;
+
+       gint refcount;
+};
+
+/* pixels to transform per idle call */
+#define COLOR_MAN_CHUNK_SIZE 81900
+
+
+static void color_man_lib_init(void)
+{
+       static gint init_done = FALSE;
+
+       if (init_done) return;
+       init_done = TRUE;
+
+       cmsErrorAction(LCMS_ERROR_IGNORE);
+}
+
+
+/*
+ *-------------------------------------------------------------------
+ * color transform cache
+ *-------------------------------------------------------------------
+ */
+
+static GList *cm_cache_list = NULL;
+
+
+static void color_man_cache_ref(ColorManCache *cc)
+{
+       if (!cc) return;
+
+       cc->refcount++;
+}
+
+static void color_man_cache_unref(ColorManCache *cc)
+{
+       if (!cc) return;
+
+       cc->refcount--;
+       if (cc->refcount < 1)
+               {
+               if (cc->transform) cmsDeleteTransform(cc->transform);
+               if (cc->profile_in) cmsCloseProfile(cc->profile_in);
+               if (cc->profile_out) cmsCloseProfile(cc->profile_out);
+
+               g_free(cc->profile_in_file);
+               g_free(cc->profile_out_file);
+
+               g_free(cc);
+               }
+}
+
+static cmsHPROFILE color_man_cache_load_profile(ColorManProfileType type, const gchar *file)
+{
+       cmsHPROFILE profile = NULL;
+
+       switch (type)
+               {
+               case COLOR_PROFILE_FILE:
+                       if (file)
+                               {
+                               gchar *pathl;
+
+                               pathl = path_from_utf8(file);
+                               profile = cmsOpenProfileFromFile(pathl, "r");
+                               g_free(pathl);
+                               }
+                       break;
+               case COLOR_PROFILE_SRGB:
+                       profile = cmsCreate_sRGBProfile();
+                       break;
+               case COLOR_PROFILE_NONE:
+               default:
+                       break;
+               }
+
+       return profile;
+}
+
+static ColorManCache *color_man_cache_new(ColorManProfileType in_type, const gchar *in_file,
+                                         ColorManProfileType out_type, const gchar *out_file,
+                                         gint has_alpha)
+{
+       ColorManCache *cc;
+
+       color_man_lib_init();
+
+       cc = g_new0(ColorManCache, 1);
+       cc->refcount = 1;
+
+       cc->profile_in_type = in_type;
+       cc->profile_in_file = g_strdup(in_file);
+
+       cc->profile_out_type = out_type;
+       cc->profile_out_file = g_strdup(out_file);
+
+       cc->has_alpha = has_alpha;
+
+       cc->profile_in = color_man_cache_load_profile(cc->profile_in_type, cc->profile_in_file);
+       cc->profile_out = color_man_cache_load_profile(cc->profile_out_type, cc->profile_out_file);
+
+       if (!cc->profile_in || !cc->profile_out)
+               {
+               if (debug) printf("failed to load color profile for %s: %d %s\n",
+                                 (!cc->profile_in) ? "input" : "screen",
+                                 (!cc->profile_in) ? cc->profile_in_type : cc->profile_out_type,
+                                 (!cc->profile_in) ? cc->profile_in_file : cc->profile_out_file);
+
+               color_man_cache_unref(cc);
+               return NULL;
+               }
+
+       cc->transform = cmsCreateTransform(cc->profile_in,
+                                          (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8,
+                                          cc->profile_out,
+                                          (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8,
+                                          INTENT_PERCEPTUAL, 0);
+
+       if (!cc->transform)
+               {
+               if (debug) printf("failed to create color profile transform\n");
+
+               color_man_cache_unref(cc);
+               return NULL;
+               }
+
+       cm_cache_list = g_list_append(cm_cache_list, cc);
+
+       return cc;
+}
+
+static void color_man_cache_free(ColorManCache *cc)
+{
+       if (!cc) return;
+
+       cm_cache_list = g_list_remove(cm_cache_list, cc);
+       color_man_cache_unref(cc);
+}
+
+static void color_man_cache_reset(void)
+{
+       while (cm_cache_list)
+               {
+               ColorManCache *cc;
+
+               cc = cm_cache_list->data;
+               color_man_cache_free(cc);
+               }
+}
+
+static ColorManCache *color_man_cache_find(ColorManProfileType in_type, const gchar *in_file,
+                                          ColorManProfileType out_type, const gchar *out_file,
+                                          gint has_alpha)
+{
+       GList *work;
+
+       work = cm_cache_list;
+       while (work)
+               {
+               ColorManCache *cc;
+               gint match = FALSE;
+
+               cc = work->data;
+               work = work->next;
+
+               if (cc->profile_in_type == in_type &&
+                   cc->profile_out_type == out_type &&
+                   cc->has_alpha == has_alpha)
+                       {
+                       match = TRUE;
+                       }
+
+               if (match && cc->profile_in_type == COLOR_PROFILE_FILE)
+                       {
+                       match = (cc->profile_in_file && in_file &&
+                                strcmp(cc->profile_in_file, in_file) == 0);
+                       }
+               if (match && cc->profile_out_type == COLOR_PROFILE_FILE)
+                       {
+                       match = (cc->profile_out_file && out_file &&
+                                strcmp(cc->profile_out_file, out_file) == 0);
+                       }
+
+               if (match) return cc;
+               }
+
+       return NULL;
+}
+
+static ColorManCache *color_man_cache_get(ColorManProfileType in_type, const gchar *in_file,
+                                         ColorManProfileType out_type, const gchar *out_file,
+                                         gint has_alpha)
+{
+       ColorManCache *cc;
+
+       cc = color_man_cache_find(in_type, in_file, out_type, out_file, has_alpha);
+
+       if (!cc)
+               {
+               cc = color_man_cache_new(in_type, in_file, out_type, out_file, has_alpha);
+               }
+
+       return cc;
+}
+
+
+/*
+ *-------------------------------------------------------------------
+ * color manager
+ *-------------------------------------------------------------------
+ */
+
+static void color_man_done(ColorMan *cm, ColorManReturnType type)
+{
+       if (cm->func_done)
+               {
+               cm->func_done(cm, type, cm->func_done_data);
+               }
+}
+
+static void color_man_correct_region(ColorMan *cm, gint x, gint y, gint w, gint h,
+                                    gint pixbuf_width, gint pixbuf_height)
+{
+       ColorManCache *cc;
+       guchar *pix;
+       gint rs;
+       gint i;
+
+       cc = cm->profile;
+
+       pix = gdk_pixbuf_get_pixels(cm->pixbuf);
+       rs = gdk_pixbuf_get_rowstride(cm->pixbuf);
+
+       w = MIN(w, pixbuf_width - x);
+       h = MIN(h, pixbuf_height - y);
+
+       pix += x * ((cc->has_alpha) ? 4 : 3);
+       for (i = 0; i < h; i++)
+               {
+               guchar *pbuf;
+
+               pbuf = pix + ((y + i) * rs);
+               cmsDoTransform(cc->transform, pbuf, pbuf, w);
+               }
+
+       image_area_changed(cm->imd, x, y, w, h);
+}
+
+static gint color_man_idle_cb(gpointer data)
+{
+       ColorMan *cm = data;
+       gint width, height;
+       gint rh;
+
+       if (cm->pixbuf != image_get_pixbuf(cm->imd))
+               {
+               cm->idle_id = -1;
+               color_man_done(cm, COLOR_RETURN_IMAGE_CHANGED);
+               return FALSE;
+               }
+
+       width = gdk_pixbuf_get_width(cm->pixbuf);
+       height = gdk_pixbuf_get_height(cm->pixbuf);
+
+       if (cm->row > height)
+               {
+               cm->idle_id = -1;
+               color_man_done(cm, COLOR_RETURN_SUCCESS);
+               return FALSE;
+               }
+
+       rh = COLOR_MAN_CHUNK_SIZE / width + 1;
+       color_man_correct_region(cm, 0, cm->row, width, rh, width, height);
+       cm->row += rh;
+
+       return TRUE;
+}
+
+ColorMan *color_man_new(ImageWindow *imd,
+                       ColorManProfileType input_type, const gchar *input_file,
+                       ColorManProfileType screen_type, const gchar *screen_file,
+                       ColorManDoneFunc done_func, gpointer done_data)
+{
+       ColorMan *cm;
+       GdkPixbuf *pixbuf;
+       gint has_alpha;
+
+       if (!imd) return NULL;
+       if (input_type == COLOR_PROFILE_NONE || screen_type == COLOR_PROFILE_NONE) return NULL;
+
+       pixbuf = image_get_pixbuf(imd);
+       if (!pixbuf) return NULL;
+
+       cm = g_new0(ColorMan, 1);
+       cm->imd = imd;
+       cm->pixbuf = pixbuf;
+       cm->row = 0;
+       cm->idle_id = -1;
+
+       cm->func_done = done_func;
+       cm->func_done_data = done_data;
+
+       has_alpha = gdk_pixbuf_get_has_alpha(pixbuf);
+       cm->profile = color_man_cache_get(input_type, input_file, screen_type, screen_file, has_alpha);
+       if (!cm->profile)
+               {
+               color_man_free(cm);
+               return NULL;
+               }
+
+       color_man_cache_ref(cm->profile);
+
+       cm->idle_id = g_idle_add(color_man_idle_cb, cm);
+
+       return cm;
+}
+
+void color_man_free(ColorMan *cm)
+{
+       if (!cm) return;
+
+       if (cm->idle_id != -1) g_source_remove(cm->idle_id);
+
+       color_man_cache_unref(cm->profile);
+
+       g_free(cm);
+}
+
+void color_man_update(void)
+{
+       color_man_cache_reset();
+}
+
+#else
+/*** color support not enabled ***/
+
+
+ColorMan *color_man_new(ImageWindow *imd,
+                       ColorManProfileType input_type, const gchar *input_file,
+                       ColorManProfileType screen_type, const gchar *screen_file,
+                       ColorManDoneFunc don_func, gpointer done_data)
+{
+       /* no op */
+       return NULL;
+}
+
+void color_man_free(ColorMan *cm)
+{
+       /* no op */
+}
+
+void color_man_update(void)
+{
+       /* no op */
+}
+
+
+#endif
+
+
diff --git a/src/color-man.h b/src/color-man.h
new file mode 100644 (file)
index 0000000..b5d3f7c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * GQview
+ * (C) 2006 John Ellis
+ *
+ * Author: John Ellis
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+
+#ifndef COLOR_MAN_H
+#define COLOR_MAN_H
+
+typedef enum {
+       COLOR_PROFILE_NONE = 0,
+       COLOR_PROFILE_FILE,
+       COLOR_PROFILE_SRGB,
+} ColorManProfileType;
+
+typedef enum {
+       COLOR_RETURN_SUCCESS = 0,
+       COLOR_RETURN_ERROR,
+       COLOR_RETURN_IMAGE_CHANGED
+} ColorManReturnType;
+
+typedef struct _ColorMan ColorMan;
+typedef void (* ColorManDoneFunc)(ColorMan *cm, ColorManReturnType success, gpointer data);
+
+
+struct _ColorMan {
+       ImageWindow *imd;
+       GdkPixbuf *pixbuf;
+       gint row;
+
+       gpointer profile;
+
+       gint idle_id;
+
+       ColorManDoneFunc func_done;
+       gpointer func_done_data;
+};
+
+
+ColorMan *color_man_new(ImageWindow *imd,
+                       ColorManProfileType input_type, const gchar *input_file,
+                       ColorManProfileType screen_type, const gchar *screen_file,
+                       ColorManDoneFunc done_func, gpointer done_data);
+void color_man_free(ColorMan *cm);
+
+void color_man_update(void);
+
+
+#endif
+
index caa40b9..b971b65 100644 (file)
@@ -117,3 +117,13 @@ gint lazy_image_sync = FALSE;
 gint update_on_time_change = TRUE;
 gint exif_rotate_enable = FALSE;
 
 gint update_on_time_change = TRUE;
 gint exif_rotate_enable = FALSE;
 
+/* color profiles */
+gint color_profile_enabled = FALSE;
+gint color_profile_input_type = 0;
+gchar *color_profile_input_file[COLOR_PROFILE_INPUTS];
+gchar *color_profile_input_name[COLOR_PROFILE_INPUTS];
+gint color_profile_screen_type = 0;
+gchar *color_profile_screen_file = NULL;
+gint color_profile_use_image = TRUE;
+
+
index 716bbdd..e6e6bc7 100644 (file)
@@ -79,6 +79,8 @@
 
 #define GQVIEW_EDITOR_SLOTS 10
 
 
 #define GQVIEW_EDITOR_SLOTS 10
 
+#define COLOR_PROFILE_INPUTS 4
+
 /*
  *----------------------------------------------------------------------------
  * globals
 /*
  *----------------------------------------------------------------------------
  * globals
@@ -194,6 +196,14 @@ extern gint lazy_image_sync;
 extern gint update_on_time_change;
 extern gint exif_rotate_enable;
 
 extern gint update_on_time_change;
 extern gint exif_rotate_enable;
 
+extern gint color_profile_enabled;
+extern gint color_profile_input_type;
+extern gchar *color_profile_input_file[];
+extern gchar *color_profile_input_name[];
+extern gint color_profile_screen_type;
+extern gchar *color_profile_screen_file;
+extern gint color_profile_use_image;
+
 /*
  *----------------------------------------------------------------------------
  * main.c
 /*
  *----------------------------------------------------------------------------
  * main.c
index bb5f8c1..086e2b0 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "image-load.h"
 #include "collect.h"
 
 #include "image-load.h"
 #include "collect.h"
+#include "color-man.h"
 #include "exif.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
 #include "exif.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
@@ -43,6 +44,7 @@ static GList *image_list = NULL;
 
 
 static void image_update_title(ImageWindow *imd);
 
 
 static void image_update_title(ImageWindow *imd);
+static void image_post_process(ImageWindow *imd, gint clamp);
 
 /*
  *-------------------------------------------------------------------
 
 /*
  *-------------------------------------------------------------------
@@ -247,10 +249,95 @@ static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp, gint
                }
 }
 
                }
 }
 
+static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
+{
+       ImageWindow *imd = data;
+
+       color_man_free((ColorMan *)imd->cm);
+       imd->cm = NULL;
+       imd->state |= IMAGE_STATE_COLOR_ADJ;
+
+       if (type != COLOR_RETURN_IMAGE_CHANGED)
+               {
+               image_post_process(imd, FALSE);
+               }
+}
+
+static gint image_post_process_color(ImageWindow *imd, gint start_row)
+{
+       ColorMan *cm;
+       ColorManProfileType input_type;
+       ColorManProfileType screen_type;
+       const gchar *input_file;
+       const gchar *screen_file;
+
+       if (imd->cm) return FALSE;
+
+       if (imd->color_profile_input >= 1 &&
+           imd->color_profile_input <= COLOR_PROFILE_INPUTS)
+               {
+               gint n;
+
+               n = imd->color_profile_input - 1;
+               if (!color_profile_input_file[n]) return FALSE;
+
+               input_type = COLOR_PROFILE_FILE;
+               input_file = color_profile_input_file[n];
+               }
+       else if (imd->color_profile_input == 0)
+               {
+               input_type = COLOR_PROFILE_SRGB;
+               input_file = NULL;
+               }
+       else
+               {
+               return FALSE;
+               }
+
+       if (imd->color_profile_screen == 1 &&
+           color_profile_screen_file)
+               {
+               screen_type = COLOR_PROFILE_FILE;
+               screen_file = color_profile_screen_file;
+               }
+       else if (imd->color_profile_screen == 0)
+               {
+               screen_type = COLOR_PROFILE_SRGB;
+               screen_file = NULL;
+               }
+       else
+               {
+               return FALSE;
+               }
+
+       cm = color_man_new(imd,
+                          input_type, input_file,
+                          screen_type, screen_file,
+                          image_post_process_color_cb, imd);
+       if (cm)
+               {
+               if (start_row > 0) cm->row = start_row;
+
+               imd->cm = (gpointer)cm;
+               return TRUE;
+               }
+
+       return FALSE;
+}
+
 static void image_post_process(ImageWindow *imd, gint clamp)
 {
        gint exif_rotated = FALSE;
 
 static void image_post_process(ImageWindow *imd, gint clamp)
 {
        gint exif_rotated = FALSE;
 
+       if (imd->color_profile_enable &&
+           !(imd->state & IMAGE_STATE_COLOR_ADJ))
+               {
+               if (image_post_process_color(imd, 0)) return;
+
+               /* fixme: note error to user */
+               imd->state |= IMAGE_STATE_COLOR_ADJ;
+               }
+
        if (exif_rotate_enable && image_get_pixbuf(imd))
                {
                ExifData *ed;
        if (exif_rotate_enable && image_get_pixbuf(imd))
                {
                ExifData *ed;
@@ -405,7 +492,7 @@ static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
  *-------------------------------------------------------------------
  */
 
  *-------------------------------------------------------------------
  */
 
-static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
+static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf, gint color_row)
 {
        g_free(imd->prev_path);
        if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
 {
        g_free(imd->prev_path);
        if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
@@ -416,11 +503,13 @@ static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf
                        
                g_object_ref(pixbuf);
                imd->prev_pixbuf = pixbuf;
                        
                g_object_ref(pixbuf);
                imd->prev_pixbuf = pixbuf;
+               imd->prev_color_row = color_row;
                }
        else
                {
                imd->prev_path = NULL;
                imd->prev_pixbuf = NULL;
                }
        else
                {
                imd->prev_path = NULL;
                imd->prev_pixbuf = NULL;
+               imd->prev_color_row = -1;
                }
 
        if (debug) printf("post buffer set: %s\n", path);
                }
 
        if (debug) printf("post buffer set: %s\n", path);
@@ -434,6 +523,10 @@ static gint image_post_buffer_get(ImageWindow *imd)
            imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
                {
                image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
            imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
                {
                image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
+               if (imd->prev_color_row >= 0)
+                       {
+                       image_post_process_color(imd, imd->prev_color_row);
+                       }
                success = TRUE;
                }
        else
                success = TRUE;
                }
        else
@@ -656,7 +749,12 @@ static void image_reset(ImageWindow *imd)
        image_loader_free(imd->il);
        imd->il = NULL;
 
        image_loader_free(imd->il);
        imd->il = NULL;
 
+       color_man_free((ColorMan *)imd->cm);
+       imd->cm = NULL;
+
        imd->delay_alter_type = ALTER_NONE;
        imd->delay_alter_type = ALTER_NONE;
+
+       imd->state = IMAGE_STATE_NONE;
 }
 
 /*
 }
 
 /*
@@ -723,6 +821,7 @@ static void image_change_real(ImageWindow *imd, const gchar *path,
        GdkPixbuf *prev_pixbuf = NULL;
        gchar *prev_path = NULL;
        gint prev_clear = FALSE;
        GdkPixbuf *prev_pixbuf = NULL;
        gchar *prev_path = NULL;
        gint prev_clear = FALSE;
+       gint prev_color_row = -1;
 
        imd->collection = cd;
        imd->collection_info = info;
 
        imd->collection = cd;
        imd->collection_info = info;
@@ -741,6 +840,14 @@ static void image_change_real(ImageWindow *imd, const gchar *path,
                        prev_path = g_strdup(imd->image_path);
                        prev_pixbuf = pixbuf;
                        g_object_ref(prev_pixbuf);
                        prev_path = g_strdup(imd->image_path);
                        prev_pixbuf = pixbuf;
                        g_object_ref(prev_pixbuf);
+
+                       if (imd->cm)
+                               {
+                               ColorMan *cm;
+
+                               cm = (ColorMan *)imd->cm;
+                               prev_color_row = cm->row;
+                               }
                        }
                }
 
                        }
                }
 
@@ -752,13 +859,13 @@ static void image_change_real(ImageWindow *imd, const gchar *path,
 
        if (prev_pixbuf)
                {
 
        if (prev_pixbuf)
                {
-               image_post_buffer_set(imd, prev_path, prev_pixbuf);
+               image_post_buffer_set(imd, prev_path, prev_pixbuf, prev_color_row);
                g_free(prev_path);
                g_object_unref(prev_pixbuf);
                }
        else if (prev_clear)
                {
                g_free(prev_path);
                g_object_unref(prev_pixbuf);
                }
        else if (prev_clear)
                {
-               image_post_buffer_set(imd, NULL, NULL);
+               image_post_buffer_set(imd, NULL, NULL, -1);
                }
 
        image_update_title(imd);
                }
 
        image_update_title(imd);
@@ -1040,6 +1147,24 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source)
                source->delay_alter_type = ALTER_NONE;
                }
 
                source->delay_alter_type = ALTER_NONE;
                }
 
+       imd->color_profile_enable = source->color_profile_enable;
+       imd->color_profile_input = source->color_profile_input;
+       imd->color_profile_screen = source->color_profile_screen;
+       imd->color_profile_use_image = source->color_profile_use_image;
+       color_man_free((ColorMan *)imd->cm);
+       imd->cm = NULL;
+       if (source->cm)
+               {
+               ColorMan *cm;
+
+               imd->cm = source->cm;
+               source->cm = NULL;
+
+               cm = (ColorMan *)imd->cm;
+               cm->imd = imd;
+               cm->func_done_data = imd;
+               }
+
        image_loader_free(imd->read_ahead_il);
        imd->read_ahead_il = source->read_ahead_il;
        source->read_ahead_il = NULL;
        image_loader_free(imd->read_ahead_il);
        imd->read_ahead_il = source->read_ahead_il;
        source->read_ahead_il = NULL;
@@ -1056,12 +1181,16 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source)
        if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
        imd->prev_pixbuf = source->prev_pixbuf;
        source->prev_pixbuf = NULL;
        if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
        imd->prev_pixbuf = source->prev_pixbuf;
        source->prev_pixbuf = NULL;
+       imd->prev_color_row = source->prev_color_row;
+       source->prev_color_row = -1;
 
        g_free(imd->prev_path);
        imd->prev_path = source->prev_path;
        source->prev_path = NULL;
 
        imd->completed = source->completed;
 
        g_free(imd->prev_path);
        imd->prev_path = source->prev_path;
        source->prev_path = NULL;
 
        imd->completed = source->completed;
+       imd->state = source->state;
+       source->state = IMAGE_STATE_NONE;
 
        pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
 }
 
        pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
 }
@@ -1095,7 +1224,7 @@ void image_alter(ImageWindow *imd, AlterType type)
 {
        if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
 
 {
        if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
 
-       if (imd->il)
+       if (imd->il || imd->cm)
                {
                /* still loading, wait till done */
                imd->delay_alter_type = type;
                {
                /* still loading, wait till done */
                imd->delay_alter_type = type;
@@ -1304,6 +1433,52 @@ void image_background_set_color(ImageWindow *imd, GdkColor *color)
        pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
 }
 
        pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
 }
 
+void image_color_profile_set(ImageWindow *imd,
+                            gint input_type, gint screen_type,
+                            gint use_image)
+{
+       if (!imd) return;
+
+       if (input_type < 0 || input_type > COLOR_PROFILE_INPUTS ||
+           screen_type < 0 || screen_type > 1)
+               {
+               return;
+               }
+
+       imd->color_profile_input = input_type;
+       imd->color_profile_screen = screen_type;
+       imd->color_profile_use_image = use_image;
+}
+
+gint image_color_profile_get(ImageWindow *imd,
+                            gint *input_type, gint *screen_type,
+                            gint *use_image)
+{
+       if (!imd) return FALSE;
+
+       if (input_type) *input_type = imd->color_profile_input;
+       if (screen_type) *screen_type = imd->color_profile_screen;
+       if (use_image) *use_image = imd->color_profile_use_image;
+
+       return TRUE;
+}
+
+void image_color_profile_set_use(ImageWindow *imd, gint enable)
+{
+       if (!imd) return;
+
+       if (imd->color_profile_enable == enable) return;
+
+       imd->color_profile_enable = enable;
+}
+
+gint image_color_profile_get_use(ImageWindow *imd)
+{
+       if (!imd) return FALSE;
+
+       return imd->color_profile_enable;
+}
+
 void image_set_delay_flip(ImageWindow *imd, gint delay)
 {
        if (!imd ||
 void image_set_delay_flip(ImageWindow *imd, gint delay)
 {
        if (!imd ||
@@ -1415,7 +1590,7 @@ static void image_free(ImageWindow *imd)
        image_reset(imd);
 
        image_read_ahead_cancel(imd);
        image_reset(imd);
 
        image_read_ahead_cancel(imd);
-       image_post_buffer_set(imd, NULL, NULL);
+       image_post_buffer_set(imd, NULL, NULL, -1);
        image_auto_refresh(imd, -1);
 
        g_free(imd->image_path);
        image_auto_refresh(imd, -1);
 
        g_free(imd->image_path);
@@ -1454,6 +1629,12 @@ ImageWindow *image_new(gint frame)
        imd->read_ahead_path = NULL;
 
        imd->completed = FALSE;
        imd->read_ahead_path = NULL;
 
        imd->completed = FALSE;
+       imd->state = IMAGE_STATE_NONE;
+
+       imd->color_profile_enable = FALSE;
+       imd->color_profile_input = 0;
+       imd->color_profile_screen = 0;
+       imd->color_profile_use_image = FALSE;
 
        imd->auto_refresh_id = -1;
        imd->auto_refresh_interval = -1;
 
        imd->auto_refresh_id = -1;
        imd->auto_refresh_interval = -1;
index 8222463..6f1574f 100644 (file)
@@ -86,6 +86,16 @@ void image_top_window_set_sync(ImageWindow *imd, gint allow_sync);
 void image_background_set_black(ImageWindow *imd, gint black);
 void image_background_set_color(ImageWindow *imd, GdkColor *color);
 
 void image_background_set_black(ImageWindow *imd, gint black);
 void image_background_set_color(ImageWindow *imd, GdkColor *color);
 
+/* color profiles */
+void image_color_profile_set(ImageWindow *imd,
+                            gint input_type, gint screen_type,
+                            gint use_embedded);
+gint image_color_profile_get(ImageWindow *imd,
+                            gint *input_type, gint *screen_type,
+                            gint *use_image);
+void image_color_profile_set_use(ImageWindow *imd, gint enable);
+gint image_color_profile_get_use(ImageWindow *imd);
+
 /* set delayed page flipping */
 void image_set_delay_flip(ImageWindow *imd, gint delay);
 
 /* set delayed page flipping */
 void image_set_delay_flip(ImageWindow *imd, gint delay);
 
index 169bea2..09980a0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GQview
 /*
  * GQview
- * (C) 2004 John Ellis
+ * (C) 2006 John Ellis
  *
  * Author: John Ellis
  *
  *
  * Author: John Ellis
  *
@@ -19,6 +19,7 @@
 #include "menu.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
 #include "menu.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
+#include "utilops.h"
 #include "view_dir_list.h"
 #include "view_dir_tree.h"
 #include "view_file_list.h"
 #include "view_dir_list.h"
 #include "view_dir_tree.h"
 #include "view_file_list.h"
@@ -226,6 +227,8 @@ static void layout_sort_menu_cb(GtkWidget *widget, gpointer data)
        LayoutWindow *lw;
        SortType type;
 
        LayoutWindow *lw;
        SortType type;
 
+       if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
+
        lw = submenu_item_get_data(widget);
        if (!lw) return;
 
        lw = submenu_item_get_data(widget);
        if (!lw) return;
 
@@ -299,6 +302,180 @@ static GtkWidget *layout_sort_button(LayoutWindow *lw)
         return button;
 }
 
         return button;
 }
 
+/*
+ *-----------------------------------------------------------------------------
+ * color profile button (and menu)
+ *-----------------------------------------------------------------------------
+ */
+
+static void layout_color_menu_enable_cb(GtkWidget *widget, gpointer data)
+{
+       LayoutWindow *lw = data;
+
+       layout_image_color_profile_set_use(lw, (!layout_image_color_profile_get_use(lw)));
+       layout_image_refresh(lw);
+}
+
+#define COLOR_MENU_KEY "color_menu_key"
+
+static void layout_color_menu_input_cb(GtkWidget *widget, gpointer data)
+{
+       LayoutWindow *lw = data;
+       gint type;
+       gint input, screen, use_image;
+
+       if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
+
+       type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), COLOR_MENU_KEY));
+       if (type < 0 || type > COLOR_PROFILE_INPUTS) return;
+
+       if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
+       if (type == input) return;
+
+       layout_image_color_profile_set(lw, type, screen, use_image);
+       layout_image_refresh(lw);
+}
+
+static void layout_color_menu_screen_cb(GtkWidget *widget, gpointer data)
+{
+       LayoutWindow *lw = data;
+       gint type;
+       gint input, screen, use_image;
+
+       if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
+
+       type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), COLOR_MENU_KEY));
+       if (type < 0 || type > 1) return;
+
+       if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
+       if (type == screen) return;
+
+       layout_image_color_profile_set(lw, input, type, use_image);
+       layout_image_refresh(lw);
+}
+
+static gchar *layout_color_name_parse(const gchar *name)
+{
+       gchar *result;
+       gchar *p;
+
+       if (!name) name = _("Empty");
+
+       result = g_strdup(name);
+       p = result;
+       while (*p != '\0')
+               {
+               if (*p == '_') *p = '-';
+               p++;
+               }
+       return result;
+}
+
+static void layout_color_button_press_cb(GtkWidget *widget, gpointer data)
+{
+       LayoutWindow *lw = data;
+       GtkWidget *menu;
+       GtkWidget *item;
+       gchar *buf;
+       gchar *front;
+       gchar *end;
+       gint active;
+       gint input = 0;
+       gint screen = 0;
+       gint use_image = 0;
+       gint i;
+
+#ifndef HAVE_LCMS
+       file_util_warning_dialog(_("Color profiles not supported"),
+                                _("This installation of GQview was not built with support for color profiles."),
+                                GTK_STOCK_DIALOG_INFO, widget);
+       return;
+#endif
+
+       active = layout_image_color_profile_get_use(lw);
+       if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
+
+       menu = popup_menu_short_lived();
+
+       menu_item_add_check(menu, _("Use _color profiles"), active,
+                           G_CALLBACK(layout_color_menu_enable_cb), lw);
+
+       menu_item_add_divider(menu);
+
+       front = g_strdup_printf(_("Input _%d:"), 0);
+       buf = g_strdup_printf("%s %s", front, "sRGB");
+       g_free(front);
+       item = menu_item_add_radio(menu, NULL,
+                                  buf, (color_profile_input_type == 0),
+                                  G_CALLBACK(layout_color_menu_input_cb), lw);
+       g_free(buf);
+       g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(0));
+       gtk_widget_set_sensitive(item, active);
+
+       for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
+               {
+               const gchar *name;
+
+               name = color_profile_input_name[i];
+               if (!name) name = filename_from_path(color_profile_input_file[i]);
+
+               front = g_strdup_printf(_("Input _%d:"), i + 1);
+               end = layout_color_name_parse(name);
+               buf = g_strdup_printf("%s %s", front, end);
+               g_free(front);
+               g_free(end);
+
+               item = menu_item_add_radio(menu, item,
+                                          buf, (i + 1 == input),
+                                          G_CALLBACK(layout_color_menu_input_cb), lw);
+               g_free(buf);
+               g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(i + 1));
+               gtk_widget_set_sensitive(item, active && color_profile_input_file[i]);
+               }
+
+       menu_item_add_divider(menu);
+
+       buf = g_strdup_printf("%s sRGB", _("Screen"));
+       item = menu_item_add_radio(menu, NULL,
+                                  buf, (screen == 0),
+                                  G_CALLBACK(layout_color_menu_screen_cb), lw);
+       g_free(buf);
+       g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(0));
+       gtk_widget_set_sensitive(item, active);
+
+       item = menu_item_add_radio(menu, item,
+                                  _("_Screen profile"), (screen == 1),
+                                  G_CALLBACK(layout_color_menu_screen_cb), lw);
+       g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(1));
+       gtk_widget_set_sensitive(item, active && color_profile_screen_file);
+
+       gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
+}
+
+static GtkWidget *layout_color_button(LayoutWindow *lw)
+{
+       GtkWidget *button;
+       GtkWidget *image;
+       gint enable;
+
+       button = gtk_button_new();
+       image = gtk_image_new_from_stock(GTK_STOCK_SELECT_COLOR, GTK_ICON_SIZE_MENU);
+       gtk_container_add(GTK_CONTAINER(button), image);
+       gtk_widget_show(image);
+       g_signal_connect(G_OBJECT(button), "clicked",
+                        G_CALLBACK(layout_color_button_press_cb), lw);
+        gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+
+       enable = (lw->image) ? lw->image->color_profile_enable : FALSE;
+#ifndef HAVE_LCMS
+       enable = FALSE;
+#endif
+       gtk_widget_set_sensitive(image, enable);
+
+       return button;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  * status bar
 /*
  *-----------------------------------------------------------------------------
  * status bar
@@ -486,6 +663,11 @@ static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gint small_for
        gtk_box_pack_start(GTK_BOX(hbox), lw->info_sort, FALSE, FALSE, 0);
        gtk_widget_show(lw->info_sort);
 
        gtk_box_pack_start(GTK_BOX(hbox), lw->info_sort, FALSE, FALSE, 0);
        gtk_widget_show(lw->info_sort);
 
+       lw->info_color = layout_color_button(lw);
+       gtk_widget_show(lw->info_color);
+
+       if (small_format) gtk_box_pack_end(GTK_BOX(hbox), lw->info_color, FALSE, FALSE, 0);
+
        lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format));
 
        if (small_format)
        lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format));
 
        if (small_format)
@@ -499,6 +681,7 @@ static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gint small_for
                hbox = lw->info_box;
                }
        lw->info_details = layout_status_label(NULL, hbox, TRUE, 0, TRUE);
                hbox = lw->info_box;
                }
        lw->info_details = layout_status_label(NULL, hbox, TRUE, 0, TRUE);
+       if (!small_format) gtk_box_pack_start(GTK_BOX(hbox), lw->info_color, FALSE, FALSE, 0);
        lw->info_zoom = layout_status_label(NULL, hbox, FALSE, ZOOM_LABEL_WIDTH, FALSE);
 }
 
        lw->info_zoom = layout_status_label(NULL, hbox, FALSE, ZOOM_LABEL_WIDTH, FALSE);
 }
 
@@ -1396,6 +1579,7 @@ void layout_style_set(LayoutWindow *lw, gint style, const gchar *order)
        lw->info_box = NULL;
        lw->info_progress_bar = NULL;
        lw->info_sort = NULL;
        lw->info_box = NULL;
        lw->info_progress_bar = NULL;
        lw->info_sort = NULL;
+       lw->info_color = NULL;
        lw->info_status = NULL;
        lw->info_details = NULL;
        lw->info_zoom = NULL;
        lw->info_status = NULL;
        lw->info_details = NULL;
        lw->info_zoom = NULL;
index b694523..e53b298 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GQview
 /*
  * GQview
- * (C) 2004 John Ellis
+ * (C) 2006 John Ellis
  *
  * Author: John Ellis
  *
  *
  * Author: John Ellis
  *
@@ -1140,6 +1140,46 @@ void layout_image_refresh(LayoutWindow *lw)
        image_reload(lw->image);
 }
 
        image_reload(lw->image);
 }
 
+void layout_image_color_profile_set(LayoutWindow *lw,
+                                   gint input_type, gint screen_type,
+                                   gint use_image)
+{
+       if (!layout_valid(&lw)) return;
+
+       image_color_profile_set(lw->image, input_type, screen_type, use_image);
+}
+
+gint layout_image_color_profile_get(LayoutWindow *lw,
+                                   gint *input_type, gint *screen_type,
+                                   gint *use_image)
+{
+       if (!layout_valid(&lw)) return FALSE;
+
+       return image_color_profile_get(lw->image, input_type, screen_type, use_image);
+}
+
+void layout_image_color_profile_set_use(LayoutWindow *lw, gint enable)
+{
+       if (!layout_valid(&lw)) return;
+
+       image_color_profile_set_use(lw->image, enable);
+
+       if (lw->info_color)
+               {
+#ifndef HAVE_LCMS
+               enable = FALSE;
+#endif
+               gtk_widget_set_sensitive(GTK_BIN(lw->info_color)->child, enable);
+               }
+}
+
+gint layout_image_color_profile_get_use(LayoutWindow *lw)
+{
+       if (!layout_valid(&lw)) return FALSE;
+
+       return image_color_profile_get_use(lw->image);
+}
+
 /*
  *----------------------------------------------------------------------------
  * list walkers
 /*
  *----------------------------------------------------------------------------
  * list walkers
@@ -1393,6 +1433,11 @@ GtkWidget *layout_image_new(LayoutWindow *lw, const gchar *path)
                image_attach_window(lw->image, lw->window, NULL, "GQview", FALSE);
 
                image_auto_refresh(lw->image, 0);
                image_attach_window(lw->image, lw->window, NULL, "GQview", FALSE);
 
                image_auto_refresh(lw->image, 0);
+
+               image_color_profile_set(lw->image,
+                                       color_profile_input_type, color_profile_screen_type,
+                                       color_profile_use_image);
+               image_color_profile_set_use(lw->image, color_profile_enabled);
                }
 
        return lw->image->widget;
                }
 
        return lw->image->widget;
index fbc8b45..8c37140 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GQview
 /*
  * GQview
- * (C) 2004 John Ellis
+ * (C) 2006 John Ellis
  *
  * Author: John Ellis
  *
  *
  * Author: John Ellis
  *
@@ -23,6 +23,15 @@ void layout_image_set_collection(LayoutWindow *lw, CollectionData *cd, CollectIn
 
 void layout_image_refresh(LayoutWindow *lw);
 
 
 void layout_image_refresh(LayoutWindow *lw);
 
+void layout_image_color_profile_set(LayoutWindow *lw,
+                                   gint input_type, gint screen_type,
+                                   gint use_image);
+gint layout_image_color_profile_get(LayoutWindow *lw,
+                                   gint *input_type, gint *screen_type,
+                                   gint *use_image);
+void layout_image_color_profile_set_use(LayoutWindow *lw, gint enable);
+gint layout_image_color_profile_get_use(LayoutWindow *lw);
+
 
 const gchar *layout_image_get_path(LayoutWindow *lw);
 const gchar *layout_image_get_name(LayoutWindow *lw);
 
 const gchar *layout_image_get_path(LayoutWindow *lw);
 const gchar *layout_image_get_name(LayoutWindow *lw);
index 38c36e0..c104aca 100644 (file)
@@ -1127,6 +1127,12 @@ static void setup_default_options(void)
 
        g_free(safe_delete_path);
        safe_delete_path = concat_dir_and_file(homedir(), GQVIEW_RC_DIR_TRASH);
 
        g_free(safe_delete_path);
        safe_delete_path = concat_dir_and_file(homedir(), GQVIEW_RC_DIR_TRASH);
+
+       for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
+               {
+               color_profile_input_file[i] = NULL;
+               color_profile_input_name[i] = NULL;
+               }
 }
 
 static void exit_gqview_final(void)
 }
 
 static void exit_gqview_final(void)
@@ -1161,6 +1167,11 @@ static void exit_gqview_final(void)
        layout_tools_float_get(NULL, &tools_float, &tools_hidden);
        toolbar_hidden = layout_toolbar_hidden(NULL);
 
        layout_tools_float_get(NULL, &tools_float, &tools_hidden);
        toolbar_hidden = layout_toolbar_hidden(NULL);
 
+       color_profile_enabled = layout_image_color_profile_get_use(NULL);
+       layout_image_color_profile_get(NULL,
+                                      &color_profile_input_type, &color_profile_screen_type,
+                                      &color_profile_use_image);
+
        save_options();
        keys_save();
 
        save_options();
        keys_save();
 
index 1803ba2..056dfa3 100644 (file)
@@ -135,19 +135,25 @@ gchar *sort_type_get_text(SortType method)
        return "";
 }
 
        return "";
 }
 
-static void submenu_add_sort_item(GtkWidget *menu, GCallback func, SortType type,
-                                 gint show_current, SortType show_type)
+static GtkWidget *submenu_add_sort_item(GtkWidget *menu, GtkWidget *parent,
+                                       GCallback func, SortType type,
+                                       gint show_current, SortType show_type)
 {
 {
+       GtkWidget *item;
+
        if (show_current)
                {
        if (show_current)
                {
-               menu_item_add_check(menu, sort_type_get_text(type), (type == show_type),
-                                   func, GINT_TO_POINTER((gint)type));
+               item = menu_item_add_radio(menu, parent,
+                                          sort_type_get_text(type), (type == show_type),
+                                          func, GINT_TO_POINTER((gint)type));
                }
        else
                {
                }
        else
                {
-               menu_item_add(menu, sort_type_get_text(type),
-                             func, GINT_TO_POINTER((gint)type));
+               item = menu_item_add(menu, sort_type_get_text(type),
+                                    func, GINT_TO_POINTER((gint)type));
                }
                }
+
+       return item;
 }
 
 GtkWidget *submenu_add_sort(GtkWidget *menu, GCallback func, gpointer data,
 }
 
 GtkWidget *submenu_add_sort(GtkWidget *menu, GCallback func, gpointer data,
@@ -155,18 +161,19 @@ GtkWidget *submenu_add_sort(GtkWidget *menu, GCallback func, gpointer data,
                            gint show_current, SortType type)
 {
        GtkWidget *submenu;
                            gint show_current, SortType type)
 {
        GtkWidget *submenu;
+       GtkWidget *parent;
 
        submenu = gtk_menu_new();
        g_object_set_data(G_OBJECT(submenu), "submenu_data", data);
 
 
        submenu = gtk_menu_new();
        g_object_set_data(G_OBJECT(submenu), "submenu_data", data);
 
-       submenu_add_sort_item(submenu, func, SORT_NAME, show_current, type);
+       parent = submenu_add_sort_item(submenu, NULL, func, SORT_NAME, show_current, type);
 #ifdef HAVE_STRVERSCMP
 #ifdef HAVE_STRVERSCMP
-       submenu_add_sort_item(submenu, func, SORT_NUMBER, show_current, type);
+       submenu_add_sort_item(submenu, parent, func, SORT_NUMBER, show_current, type);
 #endif
 #endif
-       submenu_add_sort_item(submenu, func, SORT_TIME, show_current, type);
-       submenu_add_sort_item(submenu, func, SORT_SIZE, show_current, type);
-       if (include_path) submenu_add_sort_item(submenu, func, SORT_PATH, show_current, type);
-       if (include_none) submenu_add_sort_item(submenu, func, SORT_NONE, show_current, type);
+       submenu_add_sort_item(submenu, parent, func, SORT_TIME, show_current, type);
+       submenu_add_sort_item(submenu, parent, func, SORT_SIZE, show_current, type);
+       if (include_path) submenu_add_sort_item(submenu, parent, func, SORT_PATH, show_current, type);
+       if (include_none) submenu_add_sort_item(submenu, parent, func, SORT_NONE, show_current, type);
 
        if (menu)
                {
 
        if (menu)
                {
index 69e8712..7c34416 100644 (file)
@@ -138,6 +138,10 @@ static gint tree_descend_subdirs_c;
 static gint update_on_time_change_c;
 static gint exif_rotate_enable_c;
 
 static gint update_on_time_change_c;
 static gint exif_rotate_enable_c;
 
+static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
+static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
+static GtkWidget *color_profile_screen_file_entry;
+
 
 /*
  *-----------------------------------------------------------------------------
 
 /*
  *-----------------------------------------------------------------------------
@@ -288,6 +292,25 @@ static void config_window_apply(void)
 
        tree_descend_subdirs = tree_descend_subdirs_c;
 
 
        tree_descend_subdirs = tree_descend_subdirs_c;
 
+#ifdef HAVE_LCMS
+       for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
+               {
+               g_free(color_profile_input_name[i]);
+               color_profile_input_name[i] = NULL;
+               buf = gtk_entry_get_text(GTK_ENTRY(color_profile_input_name_entry[i]));
+               if (buf && strlen(buf) > 0) color_profile_input_name[i] = g_strdup(buf);
+
+               g_free(color_profile_input_file[i]);
+               color_profile_input_file[i] = NULL;
+               buf = gtk_entry_get_text(GTK_ENTRY(color_profile_input_file_entry[i]));
+               if (buf && strlen(buf) > 0) color_profile_input_file[i] = g_strdup(buf);
+               }
+       g_free(color_profile_screen_file);
+       color_profile_screen_file = NULL;
+       buf = gtk_entry_get_text(GTK_ENTRY(color_profile_screen_file_entry));
+       if (buf && strlen(buf) > 0) color_profile_screen_file = g_strdup(buf);
+#endif
+
        l_conf = layout_config_get(layout_widget, &new_style);
 
        if (new_style != layout_style ||
        l_conf = layout_config_get(layout_widget, &new_style);
 
        if (new_style != layout_style ||
@@ -403,7 +426,7 @@ static void add_quality_menu(GtkWidget *table, gint column, gint row, const gcha
                         G_CALLBACK(quality_menu_cb), option_c);
 
        gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
                         G_CALLBACK(quality_menu_cb), option_c);
 
        gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
+                        GTK_EXPAND | GTK_FILL, 0, 0, 0);
        gtk_widget_show(combo);
 }
 
        gtk_widget_show(combo);
 }
 
@@ -514,7 +537,7 @@ static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *
                         G_CALLBACK(thumb_size_menu_cb), NULL);
 
        gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
                         G_CALLBACK(thumb_size_menu_cb), NULL);
 
        gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
+                        GTK_EXPAND | GTK_FILL, 0, 0, 0);
        gtk_widget_show(combo);
 }
 
        gtk_widget_show(combo);
 }
 
@@ -1103,7 +1126,7 @@ static void config_window_create(void)
                gtk_widget_set_size_request(editor_name_entry[i],80,-1);
                if (editor_name[i]) gtk_entry_set_text(GTK_ENTRY(editor_name_entry[i]),editor_name[i]);
                gtk_table_attach(GTK_TABLE (table),editor_name_entry[i],1,2,i+1,i+2,
                gtk_widget_set_size_request(editor_name_entry[i],80,-1);
                if (editor_name[i]) gtk_entry_set_text(GTK_ENTRY(editor_name_entry[i]),editor_name[i]);
                gtk_table_attach(GTK_TABLE (table),editor_name_entry[i],1,2,i+1,i+2,
-                                GTK_FILL | GTK_EXPAND, FALSE, 0, 0);
+                                GTK_FILL | GTK_EXPAND, 0, 0, 0);
                gtk_widget_show(editor_name_entry[i]);
 
                editor_command_entry[i] = gtk_entry_new();
                gtk_widget_show(editor_name_entry[i]);
 
                editor_command_entry[i] = gtk_entry_new();
@@ -1112,7 +1135,7 @@ static void config_window_create(void)
                tab_completion_add_to_entry(editor_command_entry[i], NULL, NULL);
                if (editor_command[i]) gtk_entry_set_text(GTK_ENTRY(editor_command_entry[i]), editor_command[i]);
                gtk_table_attach(GTK_TABLE (table),editor_command_entry[i],2,3,i+1,i+2,
                tab_completion_add_to_entry(editor_command_entry[i], NULL, NULL);
                if (editor_command[i]) gtk_entry_set_text(GTK_ENTRY(editor_command_entry[i]), editor_command[i]);
                gtk_table_attach(GTK_TABLE (table),editor_command_entry[i],2,3,i+1,i+2,
-                                GTK_FILL | GTK_EXPAND, FALSE, 0, 0);
+                                GTK_FILL | GTK_EXPAND, 0, 0, 0);
                gtk_widget_show(editor_command_entry[i]);
                }
 
                gtk_widget_show(editor_command_entry[i]);
                }
 
@@ -1227,6 +1250,60 @@ static void config_window_create(void)
        pref_spin_new_int(group, _("Offscreen cache size (Mb per image):"), NULL,
                          0, 128, 1, tile_cache_max, &tile_cache_max_c);
 
        pref_spin_new_int(group, _("Offscreen cache size (Mb per image):"), NULL,
                          0, 128, 1, tile_cache_max, &tile_cache_max_c);
 
+       group =  pref_group_new(vbox, FALSE, _("Color profiles"), GTK_ORIENTATION_VERTICAL);
+#ifndef HAVE_LCMS
+       gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
+#endif
+
+       table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 2, FALSE, FALSE);
+       gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
+
+       label = pref_table_label(table, 0, 0, _("Type"), 0.0);
+       pref_label_bold(label, TRUE, FALSE);
+
+       label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
+       pref_label_bold(label, TRUE, FALSE);
+
+       label = pref_table_label(table, 2, 0, _("File"), 0.0);
+       pref_label_bold(label, TRUE, FALSE);
+
+       for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
+               {
+               GtkWidget *entry;
+               gchar *buf;
+
+               buf = g_strdup_printf("Input %d:", i + 1);
+               pref_table_label(table, 0, i + 1, buf, 1.0);
+               g_free(buf);
+
+               entry = gtk_entry_new();
+               gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
+               gtk_widget_set_size_request(editor_name_entry[i], 30, -1);
+               if (color_profile_input_name[i]) gtk_entry_set_text(GTK_ENTRY(entry), color_profile_input_name[i]);
+               gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
+                                GTK_FILL | GTK_EXPAND, 0, 0, 0);
+               gtk_widget_show(entry);
+               color_profile_input_name_entry[i] = entry;
+
+               tabcomp = tab_completion_new(&entry, color_profile_input_file[i], NULL, NULL);
+               tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
+               gtk_widget_set_size_request(entry, 160, -1);
+               gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
+                                GTK_FILL | GTK_EXPAND, 0, 0, 0);
+               gtk_widget_show(tabcomp);
+               color_profile_input_file_entry[i] = entry;
+               }
+
+       pref_table_label(table, 0, COLOR_PROFILE_INPUTS + 1, _("Screen:"), 1.0);
+       tabcomp = tab_completion_new(&color_profile_screen_file_entry,
+                                    color_profile_screen_file, NULL, NULL);
+       tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
+       gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
+       gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3,
+                        COLOR_PROFILE_INPUTS + 1, COLOR_PROFILE_INPUTS + 2,
+                        GTK_FILL | GTK_EXPAND, 0, 0, 0);
+       gtk_widget_show(tabcomp);
+
        gtk_widget_show(notebook);
 
        gtk_widget_show(configwindow);
        gtk_widget_show(notebook);
 
        gtk_widget_show(configwindow);
index 368cb6d..a777ac5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GQview
 /*
  * GQview
- * (C) 2004 John Ellis
+ * (C) 2006 John Ellis
  *
  * Author: John Ellis
  *
  *
  * Author: John Ellis
  *
@@ -305,6 +305,32 @@ void save_options(void)
        write_bool_option(f, "disable_filtering", file_filter_disable);
        filter_write_list(f);
 
        write_bool_option(f, "disable_filtering", file_filter_disable);
        filter_write_list(f);
 
+       fprintf(f,"\n##### Color Profiles #####\n\n");
+
+#ifndef HAVE_LCMS
+       fprintf(f,"# NOTICE: GQview was not built with support for color profiles,\n"
+                 "#         color profile options will have no effect.\n\n");
+#endif
+
+       write_bool_option(f, "color_profile_enabled", color_profile_enabled);
+       write_bool_option(f, "color_profile_use_image", color_profile_use_image);
+       write_int_option(f, "color_profile_input_type", color_profile_input_type);
+       for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
+               {
+               gchar *buf;
+
+               buf = g_strdup_printf("color_profile_input_file_%d", i + 1);
+               write_char_option(f, buf, color_profile_input_file[i]);
+               g_free(buf);
+
+               buf = g_strdup_printf("color_profile_input_name_%d", i + 1);
+               write_char_option(f, buf, color_profile_input_name[i]);
+               g_free(buf);
+               }
+       fprintf(f,"\n");
+       write_int_option(f, "color_profile_screen_type", color_profile_screen_type);
+       write_char_option(f, "color_profile_screen_file_1", color_profile_screen_file);
+
        fprintf(f,"\n##### External Programs #####\n");
        fprintf(f,"# Maximum of 10 programs (external_1 through external_10)\n");
        fprintf(f,"# format: external_n: \"menu name\" \"command line\"\n\n");
        fprintf(f,"\n##### External Programs #####\n");
        fprintf(f,"# Maximum of 10 programs (external_1 through external_10)\n");
        fprintf(f,"# format: external_n: \"menu name\" \"command line\"\n\n");
@@ -555,6 +581,39 @@ void load_options(void)
                        filter_parse(value_all);
                        }
 
                        filter_parse(value_all);
                        }
 
+               /* Color Profiles */
+
+               color_profile_enabled = read_bool_option(f, option,
+                       "color_profile_enabled", value, color_profile_enabled);
+               color_profile_use_image = read_bool_option(f, option,
+                       "color_profile_use_image", value, color_profile_use_image);
+               color_profile_input_type = read_int_option(f, option,
+                       "color_profile_input_type", value, color_profile_input_type);
+
+               if (strncasecmp(option, "color_profile_input_file_", 25) == 0)
+                        {
+                        i = strtol(option + 25, NULL, 0) - 1;
+                       if (i >= 0 && i < COLOR_PROFILE_INPUTS)
+                               {
+                               color_profile_input_file[i] = read_char_option(f, option,
+                                       option, value, color_profile_input_file[i]);
+                               }
+                       }
+               if (strncasecmp(option, "color_profile_input_name_", 25) == 0)
+                        {
+                        i = strtol(option + 25, NULL, 0) - 1;
+                       if (i >= 0 && i < COLOR_PROFILE_INPUTS)
+                               {
+                               color_profile_input_name[i] = read_char_option(f, option,
+                                       option, value, color_profile_input_name[i]);
+                               }
+                       }
+
+               color_profile_screen_type = read_int_option(f, option,
+                       "color_profile_screen_type", value, color_profile_screen_type);
+               color_profile_screen_file = read_char_option(f, option,
+                       "color_profile_screen_file_1", value, color_profile_screen_file);
+
                /* External Programs */
 
                if (strncasecmp(option, "external_", 9) == 0)
                /* External Programs */
 
                if (strncasecmp(option, "external_", 9) == 0)
index d68a25a..cc049d6 100644 (file)
@@ -42,6 +42,17 @@ typedef enum {
 } LayoutLocation;
 
 
 } LayoutLocation;
 
 
+typedef enum {
+       IMAGE_STATE_NONE        = 0,
+       IMAGE_STATE_IMAGE       = 1 << 0,
+       IMAGE_STATE_LOADING     = 1 << 1,
+       IMAGE_STATE_ERROR       = 1 << 2,
+       IMAGE_STATE_COLOR_ADJ   = 1 << 3,
+       IMAGE_STATE_ROTATE_AUTO = 1 << 4,
+       IMAGE_STATE_ROTATE_USER = 1 << 5,
+       IMAGE_STATE_DELAY_FLIP  = 1 << 6
+} ImageState;
+
 typedef struct _ImageLoader ImageLoader;
 typedef struct _ThumbLoader ThumbLoader;
 
 typedef struct _ImageLoader ImageLoader;
 typedef struct _ThumbLoader ThumbLoader;
 
@@ -242,6 +253,7 @@ struct _ImageWindow
        gint title_show_zoom;   /* option to include zoom in window title */
 
        gint completed;
        gint title_show_zoom;   /* option to include zoom in window title */
 
        gint completed;
+       ImageState state;       /* mask of IMAGE_STATE_* flags about current image */
 
        void (*func_update)(ImageWindow *, gpointer);
        void (*func_complete)(ImageWindow *, gint preload, gpointer);
 
        void (*func_update)(ImageWindow *, gpointer);
        void (*func_complete)(ImageWindow *, gint preload, gpointer);
@@ -272,6 +284,13 @@ struct _ImageWindow
        CollectionData *collection;
        CollectInfo *collection_info;
 
        CollectionData *collection;
        CollectInfo *collection_info;
 
+       /* color profiles */
+       gint color_profile_enable;
+       gint color_profile_input;
+       gint color_profile_screen;
+       gint color_profile_use_image;
+       gpointer *cm;
+
        AlterType delay_alter_type;
 
        ImageLoader *read_ahead_il;
        AlterType delay_alter_type;
 
        ImageLoader *read_ahead_il;
@@ -280,6 +299,7 @@ struct _ImageWindow
 
        GdkPixbuf *prev_pixbuf;
        gchar *prev_path;
 
        GdkPixbuf *prev_pixbuf;
        gchar *prev_path;
+       gint prev_color_row;
 
        gint auto_refresh_id;
        gint auto_refresh_interval;
 
        gint auto_refresh_id;
        gint auto_refresh_interval;
@@ -366,6 +386,7 @@ struct _LayoutWindow
        GtkWidget *info_box;
        GtkWidget *info_progress_bar;
        GtkWidget *info_sort;
        GtkWidget *info_box;
        GtkWidget *info_progress_bar;
        GtkWidget *info_sort;
+       GtkWidget *info_color;
        GtkWidget *info_status;
        GtkWidget *info_details;
        GtkWidget *info_zoom;
        GtkWidget *info_status;
        GtkWidget *info_details;
        GtkWidget *info_zoom;
index 198a9b7..f08b5d3 100644 (file)
@@ -96,6 +96,22 @@ GtkWidget *menu_item_add_check(GtkWidget *menu, const gchar *label, gint active,
        return item;
 }
 
        return item;
 }
 
+GtkWidget *menu_item_add_radio(GtkWidget *menu, GtkWidget *parent,
+                              const gchar *label, gint active,
+                              GCallback func, gpointer data)
+{
+       GtkWidget *item;
+       GSList *group = NULL;
+
+       if (parent) group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(parent));
+
+       item = gtk_radio_menu_item_new_with_mnemonic(group, label);
+       if (active) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active);
+       menu_item_finish(menu, item, func, data);
+
+       return item;
+}
+
 void menu_item_add_divider(GtkWidget *menu)
 {
        GtkWidget *item = gtk_menu_item_new();
 void menu_item_add_divider(GtkWidget *menu)
 {
        GtkWidget *item = gtk_menu_item_new();
index 2ab7c44..90a2df3 100644 (file)
@@ -24,6 +24,9 @@ GtkWidget *menu_item_add_stock_sensitive(GtkWidget *menu, const gchar *label, co
                                         GCallback func, gpointer data);
 GtkWidget *menu_item_add_check(GtkWidget *menu, const gchar *label, gint active,
                               GCallback func, gpointer data);
                                         GCallback func, gpointer data);
 GtkWidget *menu_item_add_check(GtkWidget *menu, const gchar *label, gint active,
                               GCallback func, gpointer data);
+GtkWidget *menu_item_add_radio(GtkWidget *menu, GtkWidget *parent,
+                              const gchar *label, gint active,
+                              GCallback func, gpointer data);
 void menu_item_add_divider(GtkWidget *menu);
 
 /* use to avoid mnemonics, for example filenames */
 void menu_item_add_divider(GtkWidget *menu);
 
 /* use to avoid mnemonics, for example filenames */
index ce510e2..618df29 100644 (file)
@@ -613,7 +613,7 @@ GtkWidget *pref_table_box(GtkWidget *table, gint column, gint row,
                }
 
        gtk_table_attach(GTK_TABLE(table), shell, column, column + 1, row, row + 1,
                }
 
        gtk_table_attach(GTK_TABLE(table), shell, column, column + 1, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
+                        GTK_EXPAND | GTK_FILL, 0, 0, 0);
 
        gtk_widget_show(shell);
 
 
        gtk_widget_show(shell);
 
@@ -628,7 +628,7 @@ GtkWidget *pref_table_label(GtkWidget *table, gint column, gint row,
 
        align = gtk_alignment_new(alignment, 0.50, 0.0, 0.0);
        gtk_table_attach(GTK_TABLE(table), align, column, column + 1, row, row + 1,
 
        align = gtk_alignment_new(alignment, 0.50, 0.0, 0.0);
        gtk_table_attach(GTK_TABLE(table), align, column, column + 1, row, row + 1,
-                        GTK_FILL, FALSE, 0, 0);
+                        GTK_FILL, 0, 0, 0);
        gtk_widget_show(align);
        label = gtk_label_new(text);
        gtk_container_add(GTK_CONTAINER(align), label);
        gtk_widget_show(align);
        label = gtk_label_new(text);
        gtk_container_add(GTK_CONTAINER(align), label);
@@ -645,7 +645,7 @@ GtkWidget *pref_table_button(GtkWidget *table, gint column, gint row,
 
        button = pref_button_new(NULL, stock_id, text, hide_stock_text, func, data);
        gtk_table_attach(GTK_TABLE(table), button, column, column + 1, row, row + 1,
 
        button = pref_button_new(NULL, stock_id, text, hide_stock_text, func, data);
        gtk_table_attach(GTK_TABLE(table), button, column, column + 1, row, row + 1,
-                        GTK_FILL, FALSE, 0, 0);
+                        GTK_FILL, 0, 0, 0);
        gtk_widget_show(button);
 
        return button;
        gtk_widget_show(button);
 
        return button;
index a1d02f2..7894629 100644 (file)
@@ -206,6 +206,8 @@ static void vficon_pop_menu_sort_cb(GtkWidget *widget, gpointer data)
 {
        ViewFileIcon *vfi;
        SortType type;
 {
        ViewFileIcon *vfi;
        SortType type;
+
+       if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
        
        vfi = submenu_item_get_data(widget);
        if (!vfi) return;
        
        vfi = submenu_item_get_data(widget);
        if (!vfi) return;
index 4169171..651b8d1 100644 (file)
@@ -306,6 +306,8 @@ static void vflist_pop_menu_sort_cb(GtkWidget *widget, gpointer data)
 {
        ViewFileList *vfl;
        SortType type;
 {
        ViewFileList *vfl;
        SortType type;
+
+       if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
        
        vfl = submenu_item_get_data(widget);
        if (!vfl) return;
        
        vfl = submenu_item_get_data(widget);
        if (!vfl) return;