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

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
JSON_GLIB_REQUIRED=0.15.0
WEBKIT2_REQUIRED=1.10.0
LCMS2_REQUIRED=2.6
COLORD_REQUIRED=1.3
dnl ===========================================================================
......@@ -290,6 +291,26 @@ AM_CONDITIONAL(ENABLE_LCMS2, test "x$enable_lcms2" = xyes)
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])
GETTEXT_PACKAGE=gthumb
AC_SUBST([GETTEXT_PACKAGE])
......@@ -808,4 +829,5 @@ Configuration:
SVG support : ${enable_librsvg}
WebP support : ${enable_libwebp}
LCMS2 support : ${enable_lcms2}
colord support : ${enable_colord}
"
......@@ -208,8 +208,11 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
else
orientation = GTH_TRANSFORM_NONE;
#if HAVE_LCMS2
if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE)
gth_image_set_icc_profile (image, cmsOpenProfileFromMem (jpeg_info.icc_data, jpeg_info.icc_data_size));
if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE) {
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
_jpeg_info_data_dispose (&jpeg_info);
......
......@@ -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
_gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self,
GthFileData *file_data,
int requested_size,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
profile_data_free (ProfileData *profile_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_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,
int requested_size,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_object_ref (self);
gth_image_preloader_load (self->priv->preloader,
file_data,
requested_size,
......@@ -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
_gth_image_viewer_page_load_with_preloader_finish (GthImageViewerPage *self)
{
......
......@@ -132,7 +132,7 @@ gth_browser_activate_slideshow (GSimpleAction *action,
GdkRectangle monitor_geometry;
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_fullscreen_on_monitor (GTK_WINDOW (slideshow), gtk_window_get_screen (GTK_WINDOW (browser)), monitor_num);
}
......
......@@ -35,6 +35,7 @@ PUBLIC_HEADER_FILES = \
gth-async-task.h \
gth-buffer-data.h \
gth-browser.h \
gth-color-manager.h \
gth-color-scale.h \
gth-delete-task.h \
gth-dumb-notebook.h \
......@@ -62,6 +63,7 @@ PUBLIC_HEADER_FILES = \
gth-histogram.h \
gth-histogram-view.h \
gth-hook.h \
gth-icc-profile.h \
gth-icon-cache.h \
gth-image.h \
gth-image-dragger.h \
......@@ -179,6 +181,7 @@ gthumb_SOURCES = \
gth-browser.c \
gth-browser-actions-callbacks.c \
gth-buffer-data.c \
gth-color-manager.c \
gth-color-scale.c \
gth-delete-task.c \
gth-dumb-notebook.c \
......@@ -207,6 +210,7 @@ gthumb_SOURCES = \
gth-histogram.c \
gth-histogram-view.c \
gth-hook.c \
gth-icc-profile.c \
gth-icon-cache.c \
gth-image.c \
gth-image-dragger.c \
......@@ -305,6 +309,7 @@ gthumb_LDADD = \
$(JSON_GLIB_LIBS) \
$(WEBKIT2_LIBS) \
$(LCMS2_LIBS) \
$(COLORD_LIBS) \
$(NULL)
if RUN_IN_PLACE
......@@ -336,6 +341,7 @@ gthumb_CFLAGS = \
$(LIBCHAMPLAIN_CFLAGS) \
$(SMCLIENT_CFLAGS) \
$(LCMS2_CFLAGS) \
$(COLORD_CFLAGS) \
-DGTHUMB_LOCALEDIR=\"$(localedir)\" \
-DGTHUMB_UI_DIR=\"$(ui_dir)\" \
-DGTHUMB_ICON_DIR=\"$(icon_dir)\" \
......
......@@ -2599,7 +2599,7 @@ gth_browser_finalize (GObject *object)
g_free (browser->priv->list_attributes);
_g_object_unref (browser->priv->folder_popup_file_data);
_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);
G_OBJECT_CLASS (gth_browser_parent_class)->finalize (object);
......@@ -6951,36 +6951,45 @@ gth_browser_apply_editor_changes (GthBrowser *browser)
}
GthICCProfile
gth_browser_get_screen_profile (GthBrowser *browser)
GthICCData *
gth_browser_get_monitor_profile (GthBrowser *browser)
{
#if HAVE_LCMS2
if (browser->priv->screen_profile == NULL) {
GdkScreen *screen;
char *atom_name;
GdkAtom type = GDK_NONE;
int format = 0;
int nitems = 0;
guchar *data = NULL;
int monitor_num;
screen = gtk_widget_get_screen (GTK_WIDGET (browser));
if (gdk_screen_get_number (screen) > 0)
atom_name = g_strdup_printf ("_ICC_PROFILE_%d", gdk_screen_get_number (screen));
else
atom_name = g_strdup ("_ICC_PROFILE");
if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), NULL, &monitor_num, NULL)) {
char *atom_name;
GdkAtom type = GDK_NONE;
int format = 0;
int nitems = 0;
guchar *data = NULL;
if (gdk_property_get (gdk_screen_get_root_window (screen),
gdk_atom_intern (atom_name, FALSE),
GDK_NONE,
0, 64 * 1024 * 1024, FALSE,
&type, &format, &nitems, &data) && nitems > 0)
{
browser->priv->screen_profile = cmsOpenProfileFromMem (data, nitems);
g_free (data);
}
if (monitor_num > 0)
atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor_num);
else
atom_name = g_strdup ("_ICC_PROFILE");
g_free (atom_name);
if (gdk_property_get (gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (browser))),
gdk_atom_intern (atom_name, FALSE),
GDK_NONE,
0, 64 * 1024 * 1024, FALSE,
&type, &format, &nitems, &data) && nitems > 0)
{
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 (atom_name);
}
}
#endif
return browser->priv->screen_profile;
......
......@@ -272,7 +272,7 @@ void gth_browser_ask_whether_to_save (GthBrowser *browser,
void gth_browser_save_state (GthBrowser *browser);
gboolean gth_browser_restore_state (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
(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,
GAsyncResult *res,
gpointer user_data)
{
CdDevice *device = CD_DEVICE (source_object);
GTask *task = user_data;
if (! cd_device_connect_finish (device, res, NULL)) {
g_task_return_pointer (task, NULL, NULL);
g_object_unref (task);
}
else {
CdProfile *profile = cd_device_get_default_profile (device);
if (profile != NULL) {
cd_profile_connect (profile,
g_task_get_cancellable (task),
cd_profile_connected_cb,
task);
}
else {
g_task_return_pointer (task, NULL, NULL);
g_object_unref (task);
}
}
g_object_unref (device);
}
static void
find_device_by_property_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GTask *task = user_data;
CdDevice *device;
device = cd_client_find_device_by_property_finish (CD_CLIENT (source_object), res, NULL);
if (device == NULL) {
g_task_return_pointer (task, NULL, NULL);
g_object_unref (task);
return;
}
cd_device_connect (device,
g_task_get_cancellable (task),
cd_device_connected_cb,
task);
}
static void
_cd_client_find_device_for_task (CdClient *cd_client,
GTask *task)
{
ProfilesData *data = g_task_get_task_data (task);
cd_client_find_device_by_property (cd_client,
CD_DEVICE_METADATA_XRANDR_NAME,
data->monitor_name,
g_task_get_cancellable (task),
find_device_by_property_cb,
task);
}
static void
cd_client_connected_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
CdClient *cd_client = CD_CLIENT (source_object);
GTask *task = user_data;
if (! cd_client_connect_finish (cd_client, res, NULL)) {
g_task_return_pointer (task, NULL, NULL);
g_object_unref (task);