Commit 6693627d authored by Paolo Bacchilega's avatar Paolo Bacchilega
Browse files

use colord to get the monitor color profile

this makes color profiles work on wayland as well.
parent c7a808c0
...@@ -71,6 +71,7 @@ LIBWEBP_REQUIRED=0.2.0 ...@@ -71,6 +71,7 @@ LIBWEBP_REQUIRED=0.2.0
JSON_GLIB_REQUIRED=0.15.0 JSON_GLIB_REQUIRED=0.15.0
WEBKIT2_REQUIRED=1.10.0 WEBKIT2_REQUIRED=1.10.0
LCMS2_REQUIRED=2.6 LCMS2_REQUIRED=2.6
COLORD_REQUIRED=1.3
dnl =========================================================================== dnl ===========================================================================
...@@ -290,6 +291,26 @@ AM_CONDITIONAL(ENABLE_LCMS2, test "x$enable_lcms2" = xyes) ...@@ -290,6 +291,26 @@ AM_CONDITIONAL(ENABLE_LCMS2, test "x$enable_lcms2" = xyes)
dnl =========================================================================== dnl ===========================================================================
AC_ARG_ENABLE([colord],
[AS_HELP_STRING([--disable-colord],[do not compile code that uses the colord library])],,
[enable_colord=yes])
if test x$enable_colord = xyes ; then
PKG_CHECK_MODULES(COLORD,
colord >= $COLORD_REQUIRED,
[enable_colord=yes],
[enable_colord=no])
fi
if test x$enable_colord = xyes ; then
AC_DEFINE(HAVE_COLORD, 1, [Define to 1 if colord support is included])
fi
AC_SUBST(COLORD_LIBS)
AC_SUBST(COLORD_CFLAGS)
AM_CONDITIONAL(ENABLE_COLORD, test "x$enable_colord" = xyes)
dnl ===========================================================================
IT_PROG_INTLTOOL([0.50.1]) IT_PROG_INTLTOOL([0.50.1])
GETTEXT_PACKAGE=gthumb GETTEXT_PACKAGE=gthumb
AC_SUBST([GETTEXT_PACKAGE]) AC_SUBST([GETTEXT_PACKAGE])
...@@ -808,4 +829,5 @@ Configuration: ...@@ -808,4 +829,5 @@ Configuration:
SVG support : ${enable_librsvg} SVG support : ${enable_librsvg}
WebP support : ${enable_libwebp} WebP support : ${enable_libwebp}
LCMS2 support : ${enable_lcms2} LCMS2 support : ${enable_lcms2}
colord support : ${enable_colord}
" "
...@@ -208,8 +208,11 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream, ...@@ -208,8 +208,11 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
else else
orientation = GTH_TRANSFORM_NONE; orientation = GTH_TRANSFORM_NONE;
#if HAVE_LCMS2 #if HAVE_LCMS2
if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE) if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE) {
gth_image_set_icc_profile (image, cmsOpenProfileFromMem (jpeg_info.icc_data, jpeg_info.icc_data_size)); GthICCData *profile = gth_icc_data_new (NULL, cmsOpenProfileFromMem (jpeg_info.icc_data, jpeg_info.icc_data_size));
gth_image_set_icc_profile (image, profile);
g_object_unref (profile);
}
#endif #endif
_jpeg_info_data_dispose (&jpeg_info); _jpeg_info_data_dispose (&jpeg_info);
......
...@@ -203,20 +203,39 @@ _gth_image_preloader_get_requested_size_for_current_image (GthImageViewerPage *s ...@@ -203,20 +203,39 @@ _gth_image_preloader_get_requested_size_for_current_image (GthImageViewerPage *s
} }
/* -- _gth_image_viewer_page_load_with_preloader -- */
typedef struct {
GthImageViewerPage *self;
GthFileData *file_data;
int requested_size;
GCancellable *cancellable;
GAsyncReadyCallback callback;
gpointer user_data;
} ProfileData;
static void static void
_gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self, profile_data_free (ProfileData *profile_data)
{
_g_object_unref (profile_data->cancellable);
_g_object_unref (profile_data->file_data);
_g_object_unref (profile_data->self);
g_free (profile_data);
}
static void
_gth_image_viewer_page_load_with_preloader_step2 (GthImageViewerPage *self,
GthFileData *file_data, GthFileData *file_data,
int requested_size, int requested_size,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
if (self->priv->apply_icc_profile)
gth_image_preloader_set_out_profile (self->priv->preloader, gth_browser_get_screen_profile (self->priv->browser));
else
gth_image_preloader_set_out_profile (self->priv->preloader, NULL);
g_object_ref (self); g_object_ref (self);
gth_image_preloader_load (self->priv->preloader, gth_image_preloader_load (self->priv->preloader,
file_data, file_data,
requested_size, requested_size,
...@@ -231,6 +250,69 @@ _gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self, ...@@ -231,6 +250,69 @@ _gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self,
} }
static void
profile_ready_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
ProfileData *profile_data = user_data;
GthImageViewerPage *self = profile_data->self;
GthICCData *profile;
profile = gth_color_manager_get_profile_finish (GTH_COLOR_MANAGER (source_object), res, NULL);
if (profile == NULL)
profile = gth_browser_get_monitor_profile (self->priv->browser);
gth_image_preloader_set_out_profile (self->priv->preloader, profile);
_gth_image_viewer_page_load_with_preloader_step2 (profile_data->self,
profile_data->file_data,
profile_data->requested_size,
profile_data->cancellable,
profile_data->callback,
profile_data->user_data);
_g_object_unref (profile);
profile_data_free (profile_data);
}
static void
_gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self,
GthFileData *file_data,
int requested_size,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
if (self->priv->apply_icc_profile) {
char *monitor_name = NULL;
if (_gtk_window_get_monitor_info (GTK_WINDOW (self->priv->browser), NULL, NULL, &monitor_name)) {
ProfileData *profile_data;
profile_data = g_new (ProfileData, 1);
profile_data->self = g_object_ref (self);
profile_data->file_data = g_object_ref (file_data);
profile_data->requested_size = requested_size;
profile_data->cancellable = _g_object_ref (cancellable);
profile_data->callback = callback;
profile_data->user_data = user_data;
gth_color_manager_get_profile_async (gth_main_get_default_color_manager(),
monitor_name,
cancellable,
profile_ready_cb,
profile_data);
return;
}
}
gth_image_preloader_set_out_profile (self->priv->preloader, NULL);
_gth_image_viewer_page_load_with_preloader_step2 (self, file_data, requested_size, cancellable, callback, user_data);
}
static gboolean static gboolean
_gth_image_viewer_page_load_with_preloader_finish (GthImageViewerPage *self) _gth_image_viewer_page_load_with_preloader_finish (GthImageViewerPage *self)
{ {
......
...@@ -132,7 +132,7 @@ gth_browser_activate_slideshow (GSimpleAction *action, ...@@ -132,7 +132,7 @@ gth_browser_activate_slideshow (GSimpleAction *action,
GdkRectangle monitor_geometry; GdkRectangle monitor_geometry;
int monitor_num; int monitor_num;
if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), &monitor_geometry, &monitor_num)) { if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), &monitor_geometry, &monitor_num, NULL)) {
gtk_window_set_default_size (GTK_WINDOW (slideshow), monitor_geometry.width, monitor_geometry.height); gtk_window_set_default_size (GTK_WINDOW (slideshow), monitor_geometry.width, monitor_geometry.height);
gtk_window_fullscreen_on_monitor (GTK_WINDOW (slideshow), gtk_window_get_screen (GTK_WINDOW (browser)), monitor_num); gtk_window_fullscreen_on_monitor (GTK_WINDOW (slideshow), gtk_window_get_screen (GTK_WINDOW (browser)), monitor_num);
} }
......
...@@ -35,6 +35,7 @@ PUBLIC_HEADER_FILES = \ ...@@ -35,6 +35,7 @@ PUBLIC_HEADER_FILES = \
gth-async-task.h \ gth-async-task.h \
gth-buffer-data.h \ gth-buffer-data.h \
gth-browser.h \ gth-browser.h \
gth-color-manager.h \
gth-color-scale.h \ gth-color-scale.h \
gth-delete-task.h \ gth-delete-task.h \
gth-dumb-notebook.h \ gth-dumb-notebook.h \
...@@ -62,6 +63,7 @@ PUBLIC_HEADER_FILES = \ ...@@ -62,6 +63,7 @@ PUBLIC_HEADER_FILES = \
gth-histogram.h \ gth-histogram.h \
gth-histogram-view.h \ gth-histogram-view.h \
gth-hook.h \ gth-hook.h \
gth-icc-profile.h \
gth-icon-cache.h \ gth-icon-cache.h \
gth-image.h \ gth-image.h \
gth-image-dragger.h \ gth-image-dragger.h \
...@@ -179,6 +181,7 @@ gthumb_SOURCES = \ ...@@ -179,6 +181,7 @@ gthumb_SOURCES = \
gth-browser.c \ gth-browser.c \
gth-browser-actions-callbacks.c \ gth-browser-actions-callbacks.c \
gth-buffer-data.c \ gth-buffer-data.c \
gth-color-manager.c \
gth-color-scale.c \ gth-color-scale.c \
gth-delete-task.c \ gth-delete-task.c \
gth-dumb-notebook.c \ gth-dumb-notebook.c \
...@@ -207,6 +210,7 @@ gthumb_SOURCES = \ ...@@ -207,6 +210,7 @@ gthumb_SOURCES = \
gth-histogram.c \ gth-histogram.c \
gth-histogram-view.c \ gth-histogram-view.c \
gth-hook.c \ gth-hook.c \
gth-icc-profile.c \
gth-icon-cache.c \ gth-icon-cache.c \
gth-image.c \ gth-image.c \
gth-image-dragger.c \ gth-image-dragger.c \
...@@ -305,6 +309,7 @@ gthumb_LDADD = \ ...@@ -305,6 +309,7 @@ gthumb_LDADD = \
$(JSON_GLIB_LIBS) \ $(JSON_GLIB_LIBS) \
$(WEBKIT2_LIBS) \ $(WEBKIT2_LIBS) \
$(LCMS2_LIBS) \ $(LCMS2_LIBS) \
$(COLORD_LIBS) \
$(NULL) $(NULL)
if RUN_IN_PLACE if RUN_IN_PLACE
...@@ -336,6 +341,7 @@ gthumb_CFLAGS = \ ...@@ -336,6 +341,7 @@ gthumb_CFLAGS = \
$(LIBCHAMPLAIN_CFLAGS) \ $(LIBCHAMPLAIN_CFLAGS) \
$(SMCLIENT_CFLAGS) \ $(SMCLIENT_CFLAGS) \
$(LCMS2_CFLAGS) \ $(LCMS2_CFLAGS) \
$(COLORD_CFLAGS) \
-DGTHUMB_LOCALEDIR=\"$(localedir)\" \ -DGTHUMB_LOCALEDIR=\"$(localedir)\" \
-DGTHUMB_UI_DIR=\"$(ui_dir)\" \ -DGTHUMB_UI_DIR=\"$(ui_dir)\" \
-DGTHUMB_ICON_DIR=\"$(icon_dir)\" \ -DGTHUMB_ICON_DIR=\"$(icon_dir)\" \
......
...@@ -2599,7 +2599,7 @@ gth_browser_finalize (GObject *object) ...@@ -2599,7 +2599,7 @@ gth_browser_finalize (GObject *object)
g_free (browser->priv->list_attributes); g_free (browser->priv->list_attributes);
_g_object_unref (browser->priv->folder_popup_file_data); _g_object_unref (browser->priv->folder_popup_file_data);
_g_object_unref (browser->priv->history_menu); _g_object_unref (browser->priv->history_menu);
gth_icc_profile_free (browser->priv->screen_profile); _g_object_unref (browser->priv->screen_profile);
gtk_tree_path_free (browser->priv->folder_tree_last_dest_row); gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
G_OBJECT_CLASS (gth_browser_parent_class)->finalize (object); G_OBJECT_CLASS (gth_browser_parent_class)->finalize (object);
...@@ -6951,36 +6951,45 @@ gth_browser_apply_editor_changes (GthBrowser *browser) ...@@ -6951,36 +6951,45 @@ gth_browser_apply_editor_changes (GthBrowser *browser)
} }
GthICCProfile GthICCData *
gth_browser_get_screen_profile (GthBrowser *browser) gth_browser_get_monitor_profile (GthBrowser *browser)
{ {
#if HAVE_LCMS2 #if HAVE_LCMS2
if (browser->priv->screen_profile == NULL) { if (browser->priv->screen_profile == NULL) {
GdkScreen *screen; int monitor_num;
if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), NULL, &monitor_num, NULL)) {
char *atom_name; char *atom_name;
GdkAtom type = GDK_NONE; GdkAtom type = GDK_NONE;
int format = 0; int format = 0;
int nitems = 0; int nitems = 0;
guchar *data = NULL; guchar *data = NULL;
screen = gtk_widget_get_screen (GTK_WIDGET (browser)); if (monitor_num > 0)
if (gdk_screen_get_number (screen) > 0) atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor_num);
atom_name = g_strdup_printf ("_ICC_PROFILE_%d", gdk_screen_get_number (screen));
else else
atom_name = g_strdup ("_ICC_PROFILE"); atom_name = g_strdup ("_ICC_PROFILE");
if (gdk_property_get (gdk_screen_get_root_window (screen), if (gdk_property_get (gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (browser))),
gdk_atom_intern (atom_name, FALSE), gdk_atom_intern (atom_name, FALSE),
GDK_NONE, GDK_NONE,
0, 64 * 1024 * 1024, FALSE, 0, 64 * 1024 * 1024, FALSE,
&type, &format, &nitems, &data) && nitems > 0) &type, &format, &nitems, &data) && nitems > 0)
{ {
browser->priv->screen_profile = cmsOpenProfileFromMem (data, nitems); GthICCProfile profile;
profile = cmsOpenProfileFromMem (data, nitems);
if (profile != NULL) {
char *filename = g_strdup_printf ("icc-profile://%d", monitor_num);
browser->priv->screen_profile = gth_icc_data_new (filename, profile);
g_free (filename);
}
g_free (data); g_free (data);
} }
g_free (atom_name); g_free (atom_name);
}
} }
#endif #endif
return browser->priv->screen_profile; return browser->priv->screen_profile;
......
...@@ -272,7 +272,7 @@ void gth_browser_ask_whether_to_save (GthBrowser *browser, ...@@ -272,7 +272,7 @@ void gth_browser_ask_whether_to_save (GthBrowser *browser,
void gth_browser_save_state (GthBrowser *browser); void gth_browser_save_state (GthBrowser *browser);
gboolean gth_browser_restore_state (GthBrowser *browser); gboolean gth_browser_restore_state (GthBrowser *browser);
void gth_browser_apply_editor_changes (GthBrowser *browser); void gth_browser_apply_editor_changes (GthBrowser *browser);
GthICCProfile gth_browser_get_screen_profile (GthBrowser *browser); GthICCData * gth_browser_get_monitor_profile (GthBrowser *browser);
GtkWidget * gth_browser_get_fullscreen_headerbar GtkWidget * gth_browser_get_fullscreen_headerbar
(GthBrowser *browser); (GthBrowser *browser);
void gth_browser_keep_mouse_visible (GthBrowser *browser, void gth_browser_keep_mouse_visible (GthBrowser *browser,
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* GThumb
*
* Copyright (C) 2017 Free Software Foundation, Inc.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#ifdef HAVE_LCMS2
#include <lcms2.h>
#endif /* HAVE_LCMS2 */
#ifdef HAVE_COLORD
#include <colord.h>
#endif /* HAVE_COLORD */
#include "gio-utils.h"
#include "glib-utils.h"
#include "gth-color-manager.h"
typedef struct {
GthICCData *in_profile;
GthICCData *out_profile;
GthICCTransform transform;
} TransformData;
static TransformData *
transform_data_new (void)
{
TransformData *data;
data = g_new (TransformData, 1);
data->in_profile = NULL;
data->out_profile = NULL;
data->transform = NULL;
return data;
}
static void
transform_data_free (TransformData *data)
{
_g_object_unref (data->in_profile);
_g_object_unref (data->out_profile);
gth_icc_transform_free (data->transform);
g_free (data);
}
/* Signals */
enum {
CHANGED,
LAST_SIGNAL
};
struct _GthColorManagerPrivate {
GHashTable *profile_cache;
GHashTable *transform_cache;
#if HAVE_COLORD
CdClient *cd_client;
#else
GObject *cd_client;
#endif
};
static guint gth_color_manager_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GthColorManager, gth_color_manager, G_TYPE_OBJECT)
static void
gth_color_manager_finalize (GObject *object)
{
GthColorManager *self;
self = GTH_COLOR_MANAGER (object);
g_hash_table_unref (self->priv->profile_cache);
g_hash_table_unref (self->priv->transform_cache);
_g_object_unref (self->priv->cd_client);
G_OBJECT_CLASS (gth_color_manager_parent_class)->finalize (object);
}
static void
gth_color_manager_class_init (GthColorManagerClass *klass)
{
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (GthColorManagerPrivate));
object_class = (GObjectClass*) klass;
object_class->finalize = gth_color_manager_finalize;
/* signals */
gth_color_manager_signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GthColorManagerClass, changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
gth_color_manager_init (GthColorManager *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_COLOR_MANAGER, GthColorManagerPrivate);
self->priv->profile_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
self->priv->transform_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) transform_data_free);
self->priv->cd_client = NULL;
}
GthColorManager *
gth_color_manager_new (void)
{
return (GthColorManager*) g_object_new (GTH_TYPE_COLOR_MANAGER, NULL);
}
#if HAVE_LCMS2 && HAVE_COLORD
typedef struct {
GthColorManager *color_manager;
char *monitor_name;
char *cache_id;
GFile *icc_file;
} ProfilesData;
static void
profiles_data_free (ProfilesData *data)
{
_g_object_unref (data->color_manager);
_g_object_unref (data->icc_file);
g_free (data->monitor_name);
g_free (data->cache_id);
g_slice_free (ProfilesData, data);
}
static void
profile_buffer_ready_cb (void **buffer,
gsize count,
GError *error,
gpointer user_data)
{
GTask *task = user_data;
if (error != NULL) {
g_task_return_error (task, g_error_copy (error));
}
else {
ProfilesData *data = g_task_get_task_data (task);
char *filename;
GthICCData *icc_data;
filename = g_file_get_path (data->icc_file);
icc_data = gth_icc_data_new (filename, (GthICCProfile) cmsOpenProfileFromMem (*buffer, count));
gth_color_manager_add_profile (data->color_manager, data->cache_id, icc_data);
g_task_return_pointer (task, g_object_ref (icc_data), g_object_unref);
g_object_unref (icc_data);
g_free (filename);
}
g_object_unref (task);
}
static void
cd_profile_connected_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
CdProfile *profile = CD_PROFILE (source_object);
GTask *task = user_data;
ProfilesData *data = g_task_get_task_data (task);
if (! cd_profile_connect_finish (profile, res, NULL)) {
g_task_return_pointer (task, NULL, NULL);
g_object_unref (task);
}
else {
data->icc_file = g_file_new_for_path (cd_profile_get_filename (profile));
_g_file_load_async (data->icc_file,
G_PRIORITY_DEFAULT,
g_task_get_cancellable (task),
profile_buffer_ready_cb,
task);
}
g_object_unref (profile);
}
static void
cd_device_connected_cb (GObject *source_object,