summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2012-05-03 10:27:41 +0100
committerRichard Hughes <richard@hughsie.com>2012-05-03 16:12:31 +0100
commit257d03d5e39f63ba7a2409ed1a3a3deecd6d5d91 (patch)
treee06fbe9b77ab7994cea79ea79d01e49111dfaad1
parentdc65fc9e88e775bf4a838ed6bca8e11e40581d11 (diff)
downloadcolord-257d03d5e39f63ba7a2409ed1a3a3deecd6d5d91.tar.gz
Add CdWindow which allows us to get the color profile for a GtkWidget
This commit adds a gtk-3.0 dep to the new libcolord-gtk. You can split this out into a seporate subpackage if this makes things easier to install on headless things like print servers.
-rw-r--r--Makefile.am7
-rw-r--r--configure.ac20
-rw-r--r--contrib/colord.spec.in30
-rw-r--r--examples/cd-gtk-demo.c86
-rw-r--r--libcolord-gtk/Makefile.am119
-rw-r--r--libcolord-gtk/cd-self-test.c101
-rw-r--r--libcolord-gtk/cd-window.c584
-rw-r--r--libcolord-gtk/cd-window.h103
-rw-r--r--libcolord-gtk/colord-gtk.h44
-rw-r--r--libcolord-gtk/colord-gtk.pc.in9
10 files changed, 1101 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 6818189..2e39cb8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,12 +18,19 @@ SUBDIRS = \
src \
po
+if HAVE_GTK
+SUBDIRS += \
+ libcolord-gtk
+endif
+
snapshot:
$(MAKE) dist distdir=$(PACKAGE)-$(VERSION)-`date +"%Y%m%d"`
DISTCHECK_CONFIGURE_FLAGS = \
--enable-introspection \
--enable-fd-fallback \
+ --enable-gtk \
+ --enable-gtk-doc \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
EXTRA_DIST = \
diff --git a/configure.ac b/configure.ac
index 19d915e..21b3e20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -272,6 +272,23 @@ else
fi
AC_SUBST(slashlibdir)
+dnl **** Check for GTK ****
+AC_ARG_ENABLE(gtk, AS_HELP_STRING([--enable-gtk],[Enable GTK support]),
+ enable_gtk=$enableval)
+has_gtk=no
+if test x$enable_gtk != xno; then
+ PKG_CHECK_MODULES(GTK, gtk+-3.0, has_gtk=yes, has_gtk=no)
+ if test $has_gtk = "no"; then
+ if test x$enable_gtk = xyes -a $has_gtk = "no"; then
+ AC_MSG_ERROR([--enable-gtk was specified and GTK was not found])
+ fi
+ fi
+fi
+AM_CONDITIONAL(HAVE_GTK, test x$has_gtk = xyes)
+if test x$has_gtk = xyes; then
+ AC_DEFINE(HAVE_GTK,1,[Use GTK support])
+fi
+
# per-machine directory
AC_SUBST(CD_SYSTEM_PROFILES_DIR, "\$(localstatedir)/lib/colord/icc")
@@ -303,6 +320,8 @@ client/Makefile
libcolord/cd-version.h
libcolord/colord.pc
libcolord/Makefile
+libcolord-gtk/colord-gtk.pc
+libcolord-gtk/Makefile
])
AC_OUTPUT
@@ -322,6 +341,7 @@ echo "
File descriptor fallback: ${enable_fd_fallback}
External volume searching: ${enable_volume_search}
SANE support: ${has_sane}
+ GTK support: ${has_gtk}
GUDEV support: ${enable_gudev}
Vala API generator: ${has_vapigen}
Daemon user: ${daemon_user}
diff --git a/contrib/colord.spec.in b/contrib/colord.spec.in
index 09ef22a..0e2696b 100644
--- a/contrib/colord.spec.in
+++ b/contrib/colord.spec.in
@@ -21,6 +21,7 @@ BuildRequires: sqlite-devel
BuildRequires: gobject-introspection-devel
BuildRequires: vala-tools
BuildRequires: libgusb-devel
+BuildRequires: gtk3-devel
Requires: shared-color-profiles
Requires: colord-sane
@@ -39,6 +40,13 @@ Requires: %{name} = %{version}-%{release}
%description devel
Files for development with %{name}.
+%package gtk-devel
+Summary: GTK development package for %{name}
+Requires: %{name} = %{version}-%{release}
+
+%description gtk-devel
+Files for development with %{name} using GTK.
+
%package sane
Summary: SANE helper package for %{name}
Requires: %{name} = %{version}-%{release}
@@ -48,6 +56,14 @@ SANE helper package for %{name} that monitors scanners that are added
and removed. This is a seporate process as libsane is craptastic, but
useful.
+%package gtk
+Summary: GTK helper library for %{name}
+Requires: %{name} = %{version}-%{release}
+
+%description gtk
+This package contains extra functionality for %{name} that can be used
+when running GTK applications.
+
%prep
%setup -q
@@ -113,11 +129,17 @@ exit 0
%{_includedir}/colord-1
%{_libdir}/libcolord.so
%{_libdir}/pkgconfig/colord.pc
-%{_datadir}/gir-1.0/*.gir
-%{_datadir}/vala/vapi/*.vapi
+%{_datadir}/gir-1.0/Colord-1.0.gir
+%{_datadir}/vala/vapi/colord.vapi
%dir %{_datadir}/gtk-doc/html/colord
%{_datadir}/gtk-doc/html/colord/*
+%files gtk-devel
+%defattr(-,root,root,-)
+%{_libdir}/libcolord-gtk.so
+%{_libdir}/pkgconfig/colord-gtk.pc
+%{_datadir}/gir-1.0/ColordGtk-1.0.gir
+
%files sane
%defattr(-,root,root,-)
%{_datadir}/dbus-1/interfaces/org.freedesktop.colord.sane.xml
@@ -126,6 +148,10 @@ exit 0
%{_libexecdir}/colord-sane
%{_sysconfdir}/dbus-1/system.d/org.freedesktop.colord-sane.conf
+%files gtk
+%defattr(-,root,root,-)
+%{_libdir}/libcolord-gtk.so.*
+
%changelog
* #LONGDATE# Richard Hughes <richard@hughsie.com> #VERSION#-0.#BUILD##ALPHATAG#
- Update from git
diff --git a/examples/cd-gtk-demo.c b/examples/cd-gtk-demo.c
new file mode 100644
index 0000000..e54e737
--- /dev/null
+++ b/examples/cd-gtk-demo.c
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011-2012 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+//gcc -o cd-gtk-demo cd-gtk-demo.c `pkg-config --cflags --libs colord-gtk` -Wall
+
+#include <stdlib.h>
+#include <colord-gtk.h>
+#include <gtk/gtk.h>
+
+static void
+cd_window_set_widget_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdProfile *profile;
+ CdWindow *window = CD_WINDOW (source);
+ GError *error = NULL;
+
+ profile = cd_window_set_widget_finish (window,
+ res,
+ &error);
+ if (profile == NULL) {
+ g_warning ("failed to get output profile: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_debug ("screen profile to use %s", cd_profile_get_filename (profile));
+ g_object_unref (profile);
+}
+
+static void
+map_cb (GtkWidget *this_widget, gpointer user_data)
+{
+ CdWindow *window = CD_WINDOW (user_data);
+
+ /* get the profile for this widget */
+ cd_window_set_widget (window,
+ this_widget,
+ NULL,
+ cd_window_set_widget_cb,
+ this_widget);
+}
+
+int
+main (int argc, char *argv[])
+{
+ CdWindow *window;
+ gint retval = EXIT_FAILURE;
+ GtkWidget *dialog;
+
+ gtk_init (&argc, &argv);
+ window = cd_window_new ();
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "%s", "Hello world");
+ g_signal_connect (dialog, "map",
+ G_CALLBACK (map_cb),
+ window);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_object_unref (window);
+
+ retval = EXIT_SUCCESS;
+ return retval;
+}
diff --git a/libcolord-gtk/Makefile.am b/libcolord-gtk/Makefile.am
new file mode 100644
index 0000000..44bca5b
--- /dev/null
+++ b/libcolord-gtk/Makefile.am
@@ -0,0 +1,119 @@
+if HAVE_INTROSPECTION
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS =
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+endif
+
+INCLUDES = \
+ $(GLIB_CFLAGS) \
+ $(GTK_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libcolord \
+ -DCD_COMPILATION \
+ -DG_LOG_DOMAIN=\"libcolord-gtk\" \
+ -DTESTDATADIR=\""$(top_srcdir)/data/tests"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\"
+
+lib_LTLIBRARIES = \
+ libcolord-gtk.la
+
+libcolord_includedir = $(includedir)/colord-1
+libcolord_include_HEADERS = \
+ colord-gtk.h
+
+libcolordgtkbase_includedir = $(libcolord_includedir)/colord-gtk
+libcolordgtkbase_include_HEADERS = \
+ cd-window.h
+
+libcolord_gtk_la_SOURCES = \
+ cd-window.c
+
+libcolord_gtk_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(top_builddir)/libcolord/libcolord.la \
+ $(GLIB_LIBS)
+
+libcolord_gtk_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -export-dynamic \
+ -no-undefined \
+ -export-symbols-regex '^cd_.*'
+
+libcolord_gtk_la_CFLAGS = \
+ $(WARNINGFLAGS_C)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = colord-gtk.pc
+
+check_PROGRAMS = \
+ cd-self-test
+
+cd_self_test_SOURCES = \
+ cd-self-test.c
+
+cd_self_test_LDADD = \
+ $(GLIB_LIBS) \
+ $(GTK_LIBS) \
+ $(lib_LTLIBRARIES)
+
+cd_self_test_CFLAGS = $(WARNINGFLAGS_C)
+
+TESTS = cd-self-test
+
+EXTRA_DIST = \
+ colord-gtk.pc.in
+
+MAINTAINERCLEANFILES = \
+ $(noinst_LIBRARIES)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+if HAVE_INTROSPECTION
+introspection_sources = \
+ $(libcolordgtk_la_SOURCES) \
+ $(libcolordgtkbase_include_HEADERS)
+
+ColordGtk-1.0.gir: libcolord-gtk.la
+ColordGtk_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 Colord-1.0
+ColordGtk_1_0_gir_CFLAGS = $(INCLUDES)
+ColordGtk_1_0_gir_SCANNERFLAGS = --identifier-prefix=Cd \
+ --symbol-prefix=cd_ \
+ --warn-all \
+ --add-include-path=$(srcdir) \
+ --c-include="colord-gtk.h"
+ColordGtk_1_0_gir_EXPORT_PACKAGES = colord-gtk
+ColordGtk_1_0_gir_LIBS = libcolord-gtk.la
+ColordGtk_1_0_gir_FILES = $(introspection_sources)
+INTROSPECTION_GIRS += ColordGtk-1.0.gir
+
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+
+if FALSE
+if HAVE_VAPIGEN
+colord-gtk.vapi: ColordGtk-1.0.gir
+ $(MAKE) $(AM_MAKEFLAGS) ColordGtk-1.0.gir
+ $(AM_V_GEN)$(VAPIGEN) $(VAPIGENFLAGS) \
+ --library colord-gtk \
+ --pkg gio-2.0 \
+ ColordGtk-1.0.gir
+ touch $@
+vapidir = $(datadir)/vala/vapi
+dist_vapi_DATA = \
+ colord-gtk.vapi
+CLEANFILES += $(dist_vapi_DATA)
+endif
+endif
+
+endif
+
+clean-local:
+ rm -f *~
+
+-include $(top_srcdir)/git.mk
diff --git a/libcolord-gtk/cd-self-test.c b/libcolord-gtk/cd-self-test.c
new file mode 100644
index 0000000..570ff76
--- /dev/null
+++ b/libcolord-gtk/cd-self-test.c
@@ -0,0 +1,101 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "../libcolord/cd-profile.h"
+#include "cd-window.h"
+
+static void
+cd_window_set_widget_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdWindow *window = CD_WINDOW (source);
+ GtkWidget *widget = GTK_WIDGET (user_data);
+ GError *error = NULL;
+ CdProfile *profile;
+
+ profile = cd_window_set_widget_finish (window,
+ res,
+ &error);
+ g_assert_no_error (error);
+ g_assert (profile != NULL);
+ g_assert (cd_profile_get_has_vcgt (profile));
+
+ g_debug ("profile was %s", cd_profile_get_filename (profile));
+ g_object_unref (profile);
+
+ /* kill the dialog */
+ gtk_widget_destroy (widget);
+}
+
+static void
+map_cb (GtkWidget *this_widget, gpointer user_data)
+{
+ CdWindow *window = CD_WINDOW (user_data);
+
+ /* get the profile for this widget */
+ cd_window_set_widget (window,
+ this_widget,
+ NULL,
+ cd_window_set_widget_cb,
+ this_widget);
+}
+
+static void
+colord_window_func (void)
+{
+ CdWindow *window;
+ GtkWidget *dialog;
+
+ window = cd_window_new ();
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "%s", "Hello world");
+ g_signal_connect (dialog, "map",
+ G_CALLBACK (map_cb),
+ window);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ g_object_unref (window);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+ gtk_init (&argc, &argv);
+
+ /* only critical and error are fatal */
+ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+
+ /* tests go here */
+ g_test_add_func ("/colord/window", colord_window_func);
+ return g_test_run ();
+}
+
diff --git a/libcolord-gtk/cd-window.c b/libcolord-gtk/cd-window.c
new file mode 100644
index 0000000..0cbcdf0
--- /dev/null
+++ b/libcolord-gtk/cd-window.c
@@ -0,0 +1,584 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2012 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:cd-window
+ * @short_description: Additional helper classes for working with GTK
+ *
+ * These functions are useful when GTK is being used alongside colord and
+ * are just provided for convenience.
+ *
+ * See also: #CdDevice
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include "cd-client.h"
+#include "cd-window.h"
+#include "cd-device.h"
+#include "cd-profile.h"
+
+static void cd_window_class_init (CdWindowClass *klass);
+static void cd_window_init (CdWindow *window);
+static void cd_window_finalize (GObject *object);
+
+#define CD_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CD_TYPE_WINDOW, CdWindowPrivate))
+
+/**
+ * CdWindowPrivate:
+ *
+ * Private #CdWindow data
+ **/
+struct _CdWindowPrivate
+{
+ CdClient *client;
+ CdDevice *device;
+ CdProfile *profile;
+ gchar *plug_name;
+ GtkWidget *widget;
+ guint device_changed_id;
+};
+
+enum {
+ SIGNAL_CHANGED,
+ SIGNAL_LAST
+};
+
+enum {
+ PROP_0,
+ PROP_PROFILE,
+ PROP_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+G_DEFINE_TYPE (CdWindow, cd_window, G_TYPE_OBJECT)
+
+/**
+ * cd_window_error_quark:
+ *
+ * Return value: An error quark.
+ *
+ * Since: 0.1.20
+ **/
+GQuark
+cd_window_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark) {
+ quark = g_quark_from_static_string ("cd_window_error");
+ }
+ return quark;
+}
+
+/**
+ * cd_window_get_profile:
+ * @window: a #CdWindow instance.
+ *
+ * Gets the color profile to use for this widget.
+ *
+ * Return value: (transfer none): a #CdProfile
+ *
+ * Since: 0.1.20
+ **/
+CdProfile *
+cd_window_get_profile (CdWindow *window)
+{
+ g_return_val_if_fail (CD_IS_WINDOW (window), NULL);
+ return window->priv->profile;
+}
+
+typedef struct {
+ CdWindow *window;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *res;
+} CdWindowSetWidgetHelper;
+
+/**
+ * cd_window_set_widget_finish:
+ * @window: a #CdWindow instance.
+ * @res: the #GAsyncResult
+ * @error: A #GError or %NULL
+ *
+ * Gets the result from the asynchronous function.
+ *
+ * Return value: (transfer full): a #CdProfile or %NULL
+ *
+ * Since: 0.1.20
+ **/
+CdProfile *
+cd_window_set_widget_finish (CdWindow *window,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (CD_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+static void
+cd_window_import_free_helper (CdWindowSetWidgetHelper *helper)
+{
+ if (helper->cancellable != NULL)
+ g_object_unref (helper->cancellable);
+ g_object_unref (helper->window);
+ g_object_unref (helper->res);
+ g_free (helper);
+}
+
+static void cd_window_set_widget_new_data (CdWindowSetWidgetHelper *helper);
+
+static void
+cd_window_set_widget_client_connect_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdClient *client = CD_CLIENT (source);
+ CdWindowSetWidgetHelper *helper = (CdWindowSetWidgetHelper *) user_data;
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = cd_client_connect_finish (client, res, &error);
+ if (!ret) {
+ g_simple_async_result_set_error (helper->res,
+ CD_WINDOW_ERROR,
+ CD_WINDOW_ERROR_FAILED,
+ "failed to connect to colord: %s",
+ error->message);
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+ g_error_free (error);
+ return;
+ }
+ cd_window_set_widget_new_data (helper);
+}
+
+static void
+cd_window_set_widget_device_connect_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdDevice *device = CD_DEVICE (source);
+ CdWindowSetWidgetHelper *helper = (CdWindowSetWidgetHelper *) user_data;
+ CdWindowPrivate *priv = helper->window->priv;
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = cd_device_connect_finish (device, res, &error);
+ if (!ret) {
+ g_simple_async_result_set_error (helper->res,
+ CD_WINDOW_ERROR,
+ CD_WINDOW_ERROR_FAILED,
+ "failed to connect to device: %s",
+ error->message);
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the default profile for the device */
+ priv->profile = cd_device_get_default_profile (priv->device);
+ if (priv->profile == NULL) {
+ g_simple_async_result_set_error (helper->res,
+ CD_WINDOW_ERROR,
+ CD_WINDOW_ERROR_FAILED,
+ "no default profile for device: %s",
+ priv->plug_name);
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+ return;
+ }
+
+ cd_window_set_widget_new_data (helper);
+}
+
+static void
+cd_window_set_widget_profile_connect_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdProfile *profile = CD_PROFILE (source);
+ CdWindowSetWidgetHelper *helper = (CdWindowSetWidgetHelper *) user_data;
+ CdWindowPrivate *priv = helper->window->priv;
+ const gchar *filename;
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = cd_profile_connect_finish (profile, res, &error);
+ if (!ret) {
+ g_simple_async_result_set_error (helper->res,
+ CD_WINDOW_ERROR,
+ CD_WINDOW_ERROR_FAILED,
+ "failed to connect to profile: %s",
+ error->message);
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the filename of the profile */
+ filename = cd_profile_get_filename (priv->profile);
+ if (filename == NULL) {
+ g_simple_async_result_set_error (helper->res,
+ CD_WINDOW_ERROR,
+ CD_WINDOW_ERROR_FAILED,
+ "profile has no physical file, must be virtual");
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+ return;
+ }
+
+ /* SUCCESS! */
+ g_simple_async_result_set_op_res_gpointer (helper->res,
+ g_object_ref (priv->profile),
+ (GDestroyNotify) g_object_unref);
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+}
+
+static void
+cd_window_set_widget_device_find_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdClient *client = CD_CLIENT (source);
+ CdWindowSetWidgetHelper *helper = (CdWindowSetWidgetHelper *) user_data;
+ CdWindowPrivate *priv = helper->window->priv;
+ GError *error = NULL;
+
+ priv->device = cd_client_find_device_by_property_finish (client,
+ res,
+ &error);
+ if (priv->device == NULL) {
+ g_simple_async_result_set_error (helper->res,
+ CD_WINDOW_ERROR,
+ CD_WINDOW_ERROR_FAILED,
+ "no device with that property: %s",
+ error->message);
+ g_simple_async_result_complete_in_idle (helper->res);
+ cd_window_import_free_helper (helper);
+ g_error_free (error);
+ return;
+ }
+ cd_window_set_widget_new_data (helper);
+}
+
+static void
+cd_window_device_changed_cb (CdDevice *device, CdWindow *window)
+{
+ CdProfile *profile;
+
+ /* no device set yet */
+ if (window->priv->device == NULL)
+ return;
+
+ /* the same device */
+ if (!cd_device_equal (device, window->priv->device))
+ return;
+
+ /* get new default profile */
+ profile = cd_device_get_default_profile (window->priv->device);
+ if (cd_profile_equal (profile, window->priv->profile))
+ return;
+
+ /* replace profile instance and emit if changed */
+ if (window->priv->profile != NULL)
+ g_object_unref (window->priv->profile);
+ window->priv->profile = g_object_ref (profile);
+ g_signal_emit (window, signals[SIGNAL_CHANGED], 0,
+ window->priv->profile);
+}
+
+static void
+cd_window_set_widget_new_data (CdWindowSetWidgetHelper *helper)
+{
+ CdWindowPrivate *priv = helper->window->priv;
+
+ /* connect to the daemon */
+ if (priv->client == NULL) {
+ priv->client = cd_client_new ();
+ priv->device_changed_id =
+ g_signal_connect (priv->client, "device-changed",
+ G_CALLBACK (cd_window_device_changed_cb),
+ helper->window);
+ cd_client_connect (priv->client,
+ helper->cancellable,
+ cd_window_set_widget_client_connect_cb,
+ helper);
+ goto out;
+ }
+
+ /* find the new device */
+ if (priv->device == NULL && priv->plug_name != NULL) {
+ cd_client_find_device_by_property (priv->client,
+ CD_DEVICE_METADATA_XRANDR_NAME,
+ priv->plug_name,
+ helper->cancellable,
+ cd_window_set_widget_device_find_cb,
+ helper);
+ goto out;
+ }
+
+ /* connect to the device */
+ if (priv->device != NULL && !cd_device_get_connected (priv->device)) {
+ cd_device_connect (priv->device,
+ helper->cancellable,
+ cd_window_set_widget_device_connect_cb,
+ helper);
+ goto out;
+ }
+
+ /* connect to the profile */
+ if (priv->profile != NULL && !cd_profile_get_connected (priv->profile)) {
+ cd_profile_connect (priv->profile,
+ helper->cancellable,
+ cd_window_set_widget_profile_connect_cb,
+ helper);
+ goto out;
+ }
+out:
+ return;
+}
+
+static void
+cd_window_update_widget_plug_name (CdWindow *window,
+ GtkWidget *widget)
+{
+ CdWindowPrivate *priv = window->priv;
+ const gchar *plug_name;
+ GdkRectangle rect;
+ GdkScreen *screen;
+ GdkWindow *gdk_window;
+ gint monitor_num;
+
+ /* get xid */
+ gdk_window = gtk_widget_get_window (widget);
+ screen = gdk_window_get_screen (gdk_window);
+
+ gdk_window_get_frame_extents (gdk_window, &rect);
+
+ /* the monitor where the center of the window is */
+ monitor_num = gdk_screen_get_monitor_at_point (screen,
+ rect.x + (rect.width / 2),
+ rect.y + (rect.height / 2));
+ plug_name = gdk_screen_get_monitor_plug_name (screen, monitor_num);
+
+ /* ignoring MAP as plug_name has not changed */
+ if (g_strcmp0 (plug_name, priv->plug_name) == 0)
+ return;
+
+ /* refresh data */
+ g_free (priv->plug_name);
+ priv->plug_name = g_strdup (plug_name);
+ if (priv->device != NULL) {
+ g_object_unref (priv->device);
+ priv->device = NULL;
+ }
+ if (priv->profile != NULL) {
+ g_object_unref (priv->profile);
+ priv->profile = NULL;
+ }
+}
+
+/**
+ * cd_window_set_widget:
+ * @window: a #CdWindow instance.
+ * @widget: a #GtkWidget
+ * @cancellable: a #GCancellable or %NULL
+ * @callback: the function to run on completion
+ * @user_data: the data to pass to @callback
+ *
+ * Gets the screen profile that should be used for the widget,
+ * which corresponds to the screen output under the center of the widget.
+ *
+ * This method should be called when the widget has mapped, i.e.
+ * g_signal_connect (dialog, "map", G_CALLBACK (map_cb), priv);
+ *
+ * Note, the returned profile from cd_client_get_profile_for_widget_finish()
+ * has already been connected to, as is ready to use.
+ *
+ * Since: 0.1.20
+ **/
+void
+cd_window_set_widget (CdWindow *window,
+ GtkWidget *widget,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ CdWindowSetWidgetHelper *helper;
+
+ g_return_if_fail (CD_IS_WINDOW (window));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ helper = g_new0 (CdWindowSetWidgetHelper, 1);
+ helper->window = g_object_ref (window);
+ helper->res = g_simple_async_result_new (G_OBJECT (window),
+ callback,
+ user_data,
+ cd_window_set_widget);
+ if (cancellable != NULL)
+ helper->cancellable = g_object_ref (cancellable);
+
+ /* intially set the plug name */
+ window->priv->widget = g_object_ref (widget);
+ cd_window_update_widget_plug_name (window, widget);
+ cd_window_set_widget_new_data (helper);
+}
+
+/**********************************************************************/
+
+/*
+ * cd_window_get_property:
+ */
+static void
+cd_window_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CdWindow *window = CD_WINDOW (object);
+
+ switch (prop_id) {
+ case PROP_PROFILE:
+ g_value_set_object (value, window->priv->profile);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*
+ * cd_window_class_init:
+ */
+static void
+cd_window_class_init (CdWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = cd_window_get_property;
+ object_class->finalize = cd_window_finalize;
+
+ /**
+ * CdWindow:profile:
+ *
+ * The window profile.
+ *
+ * Since: 0.1.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_PROFILE,
+ g_param_spec_string ("Profile",
+ "Color profile",
+ NULL,
+ NULL,
+ G_PARAM_READABLE));
+
+ /**
+ * CdWindow::changed:
+ * @window: the #CdDevice instance that emitted the signal
+ *
+ * The ::changed signal is emitted when the device profile has
+ * changed. The #CdProfile that is referenced in the callback
+ * has not been connected to, and you will need to call
+ * cd_profile_connect() if the ICC filename is required.
+ *
+ * Since: 0.1.20
+ **/
+ signals [SIGNAL_CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CdWindowClass, changed),
+ NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, CD_TYPE_PROFILE);
+
+ g_type_class_add_private (klass, sizeof (CdWindowPrivate));
+}
+
+/*
+ * cd_window_init:
+ */
+static void
+cd_window_init (CdWindow *window)
+{
+ window->priv = CD_WINDOW_GET_PRIVATE (window);
+
+ /* ensure the remote errors are registered */
+ cd_window_error_quark ();
+}
+
+/*
+ * cd_window_finalize:
+ */
+static void
+cd_window_finalize (GObject *object)
+{
+ CdWindow *window = CD_WINDOW (object);
+
+ g_return_if_fail (CD_IS_WINDOW (object));
+
+ if (window->priv->client != NULL) {
+ g_signal_handler_disconnect (window->priv->client,
+ window->priv->device_changed_id);
+ g_object_unref (window->priv->client);
+ }
+ if (window->priv->device != NULL)
+ g_object_unref (window->priv->device);
+ if (window->priv->profile != NULL)
+ g_object_unref (window->priv->profile);
+ g_free (window->priv->plug_name);
+
+ G_OBJECT_CLASS (cd_window_parent_class)->finalize (object);
+}
+
+/**
+ * cd_window_new:
+ *
+ * Creates a new #CdWindow object.
+ *
+ * Return value: a new CdWindow object.
+ *
+ * Since: 0.1.20
+ **/
+CdWindow *
+cd_window_new (void)
+{
+ CdWindow *window;
+ window = g_object_new (CD_TYPE_WINDOW, NULL);
+ return CD_WINDOW (window);
+}
diff --git a/libcolord-gtk/cd-window.h b/libcolord-gtk/cd-window.h
new file mode 100644
index 0000000..15b334b
--- /dev/null
+++ b/libcolord-gtk/cd-window.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2012 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if !defined (__COLORD_H_INSIDE__) && !defined (CD_COMPILATION)
+#error "Only <colord-gtk.h> can be included directly."
+#endif
+
+#ifndef __CD_WINDOW_H
+#define __CD_WINDOW_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include "cd-window.h"
+
+G_BEGIN_DECLS
+
+#define CD_TYPE_WINDOW (cd_window_get_type ())
+#define CD_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CD_TYPE_WINDOW, CdWindow))
+#define CD_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CD_TYPE_WINDOW, CdWindowClass))
+#define CD_IS_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CD_TYPE_WINDOW))
+#define CD_IS_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CD_TYPE_WINDOW))
+#define CD_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CD_TYPE_WINDOW, CdWindowClass))
+#define CD_WINDOW_ERROR (cd_window_error_quark ())
+#define CD_WINDOW_TYPE_ERROR (cd_window_error_get_type ())
+
+typedef struct _CdWindowPrivate CdWindowPrivate;
+
+typedef struct
+{
+ GObject parent;
+ CdWindowPrivate *priv;
+} CdWindow;
+
+typedef struct
+{
+ GObjectClass parent_class;
+ void (*changed) (CdWindow *window,
+ CdProfile *profile);
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_cd_window_reserved1) (void);
+ void (*_cd_window_reserved2) (void);
+ void (*_cd_window_reserved3) (void);
+ void (*_cd_window_reserved4) (void);
+ void (*_cd_window_reserved5) (void);
+ void (*_cd_window_reserved6) (void);
+ void (*_cd_window_reserved7) (void);
+ void (*_cd_window_reserved8) (void);
+} CdWindowClass;
+
+/**
+ * CdWindowError:
+ * @CD_WINDOW_ERROR_FAILED: the transaction failed for an unknown reason
+ *
+ * Errors that can be thrown
+ */
+typedef enum
+{
+ CD_WINDOW_ERROR_FAILED,
+ CD_WINDOW_ERROR_LAST
+} CdWindowError;
+
+GType cd_window_get_type (void);
+GQuark cd_window_error_quark (void);
+CdWindow *cd_window_new (void);
+
+/* async */
+void cd_window_set_widget (CdWindow *window,
+ GtkWidget *widget,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+CdProfile *cd_window_set_widget_finish (CdWindow *window,
+ GAsyncResult *res,
+ GError **error);
+
+/* getters */
+CdProfile *cd_window_get_profile (CdWindow *window);
+
+G_END_DECLS
+
+#endif /* __CD_WINDOW_H */
+
diff --git a/libcolord-gtk/colord-gtk.h b/libcolord-gtk/colord-gtk.h
new file mode 100644
index 0000000..2d50286
--- /dev/null
+++ b/libcolord-gtk/colord-gtk.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010-2011 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:colord
+ * @short_description: Client objects for accessing colord with GTK
+ *
+ * These objects allow client programs to get access to profiles.
+ *
+ * See also: #CdClient, #CdDevice
+ */
+
+#ifndef __COLORD_GTK_H__
+#define __COLORD_GTK_H__
+
+#define __COLORD_H_INSIDE__
+
+#include <colord/cd-client.h>
+#include <colord/cd-device.h>
+#include <colord/cd-profile.h>
+#include <colord-gtk/cd-window.h>
+
+#undef __COLORD_H_INSIDE__
+
+#endif /* __COLORD_GTK_H__ */
+
diff --git a/libcolord-gtk/colord-gtk.pc.in b/libcolord-gtk/colord-gtk.pc.in
new file mode 100644
index 0000000..906fbe6
--- /dev/null
+++ b/libcolord-gtk/colord-gtk.pc.in
@@ -0,0 +1,9 @@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: colord-gtk
+Description: colord-gtk is GTK integration for libcolord
+Version: @VERSION@
+Requires: colord, gtk+-3.0
+Libs: -L${libdir} -lcolord-gtk
+Cflags: -I${includedir}/colord-1