[gnome-color-manager] Set _ICC_PROFILE on each Xrandr output, as well as on the root window



commit 062f0b088018dc4876b9860cf25ad35e8523401a
Author: Richard Hughes <richard hughsie com>
Date:   Wed Nov 4 13:08:51 2009 +0000

    Set _ICC_PROFILE on each Xrandr output, as well as on the root window

 src/gcm-inspect.c |  103 +++++++++++++++++++++++-------
 src/gcm-utils.c   |   10 +++-
 src/gcm-xserver.c |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gcm-xserver.h |    4 +-
 4 files changed, 275 insertions(+), 25 deletions(-)
---
diff --git a/src/gcm-inspect.c b/src/gcm-inspect.c
index 33d2432..65dff45 100644
--- a/src/gcm-inspect.c
+++ b/src/gcm-inspect.c
@@ -29,6 +29,49 @@
 #include "gcm-xserver.h"
 
 /**
+ * gcm_inspect_print_data_info:
+ **/
+static gboolean
+gcm_inspect_print_data_info (const gchar *title, const guint8 *data, gsize length)
+{
+	gchar *description = NULL;
+	gchar *copyright = NULL;
+	GcmProfile *profile = NULL;
+	GError *error = NULL;
+	gboolean ret;
+
+	/* parse the data */
+	profile = gcm_profile_new ();
+	ret = gcm_profile_parse_data (profile, (const gchar *) data, length, &error);
+	if (!ret) {
+		egg_warning ("failed to parse data: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* print some interesting facts about the profile */
+	g_object_get (profile,
+		      "description", &description,
+		      "copyright", &copyright,
+		      NULL);
+
+	/* print title */
+	g_print ("%s\n", title);
+
+	/* TRANSLATORS: this is the ICC profile description stored in an atom in the XServer */
+	g_print (" - %s %s\n", _("Description:"), description);
+
+	/* TRANSLATORS: this is the ICC profile copyright */
+	g_print (" - %s %s\n", _("Copyright:"), copyright);
+out:
+	g_free (copyright);
+	g_free (description);
+	if (profile != NULL)
+		g_object_unref (profile);
+	return ret;
+}
+
+/**
  * main:
  **/
 int
@@ -40,11 +83,14 @@ main (int argc, char **argv)
 	GError *error = NULL;
 	GOptionContext *context;
 	guint8 *data = NULL;
+	guint8 *data_tmp;
 	gsize length;
-	GcmProfile *profile = NULL;
 	GcmXserver *xserver = NULL;
-	gchar *description = NULL;
-	gchar *copyright = NULL;
+	GnomeRROutput **outputs;
+	guint i;
+	GnomeRRScreen *rr_screen = NULL;
+	const gchar *output_name;
+	gchar *title;
 
 	const GOptionEntry options[] = {
 		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
@@ -72,32 +118,45 @@ main (int argc, char **argv)
 		goto out;
 	}
 
-	/* parse the data */
-	profile = gcm_profile_new ();
-	ret = gcm_profile_parse_data (profile, (const gchar *) data, length, &error);
-	if (!ret) {
-		egg_warning ("failed to parse data: %s", error->message);
-		g_error_free (error);
+	/* TRANSLATORS: the root window of all the screens */
+	gcm_inspect_print_data_info (_("Root window profile (deprecated):"), data, length);
+
+	/* get screen */
+	rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), NULL, NULL, &error);
+	if (rr_screen == NULL) {
+		egg_warning ("failed to get rr screen: %s", error->message);
 		goto out;
 	}
 
-	/* print some interesting facts about the profile */
-	g_object_get (profile,
-		      "description", &description,
-		      "copyright", &copyright,
-		      NULL);
+	/* coldplug devices */
+	outputs = gnome_rr_screen_list_outputs (rr_screen);
+	for (i=0; outputs[i] != NULL; i++) {
 
-	/* TRANSLATORS: this is the ICC profile description stored in an atom in the XServer */
-	g_print ("%s %s\n", _("Profile description:"), description);
+		/* get output name */
+		output_name = gnome_rr_output_get_name (outputs[i]);
+		title = g_strdup_printf (_("Output profile '%s':"), output_name);
+
+		/* get profile from XServer */
+		ret = gcm_xserver_get_output_profile_data (xserver, output_name, &data_tmp, &length, &error);
+		if (!ret) {
+			egg_warning ("failed to get output profile data: %s", error->message);
+			/* TRANSLATORS: this is when the profile has not been set */
+			g_print ("%s %s\n", title, _("not set"));
+			g_error_free (error);
+			/* non-fatal */
+			error = NULL;
+		} else {
+			/* TRANSLATORS: the output, i.e. the flat panel */
+			gcm_inspect_print_data_info (title, data_tmp, length);
+			g_free (data_tmp);
+		}
+		g_free (title);
+	}
 
-	/* TRANSLATORS: this is the ICC profile copyright */
-	g_print ("%s %s\n", _("Profile copyright:"), copyright);
 out:
 	g_free (data);
-	g_free (copyright);
-	g_free (description);
-	if (profile != NULL)
-		g_object_unref (profile);
+	if (rr_screen != NULL)
+		gnome_rr_screen_destroy (rr_screen);
 	if (xserver != NULL)
 		g_object_unref (xserver);
 	return retval;
diff --git a/src/gcm-utils.c b/src/gcm-utils.c
index 4819851..f439b41 100644
--- a/src/gcm-utils.c
+++ b/src/gcm-utils.c
@@ -273,6 +273,7 @@ gcm_utils_set_output_gamma (GnomeRROutput *output, GError **error)
 	GnomeRRCrtc *crtc;
 	gint x, y;
 	gchar *filename;
+	const gchar *output_name;
 
 	/* get CLUT */
 	clut = gcm_utils_get_clut_for_output (output, error);
@@ -292,11 +293,16 @@ gcm_utils_set_output_gamma (GnomeRROutput *output, GError **error)
 	if (!ret)
 		goto out;
 
+	/* set the per-output profile atoms */
+	xserver = gcm_xserver_new ();
+	output_name = gnome_rr_output_get_name (output);
+	ret = gcm_xserver_set_output_profile (xserver, output_name, filename, error);
+	if (!ret)
+		goto out;
+
 	/* is the monitor our primary monitor */
 	gnome_rr_output_get_position (output, &x, &y);
 	if (x == 0 && y == 0 && filename != NULL) {
-		egg_debug ("setting main ICC profile atom from %s", filename);
-		xserver = gcm_xserver_new ();
 		ret = gcm_xserver_set_root_window_profile (xserver, filename, error);
 		if (!ret)
 			goto out;
diff --git a/src/gcm-xserver.c b/src/gcm-xserver.c
index b7e4d90..54f3508 100644
--- a/src/gcm-xserver.c
+++ b/src/gcm-xserver.c
@@ -36,6 +36,7 @@
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
 
 #include "gcm-xserver.h"
 
@@ -70,6 +71,7 @@ G_DEFINE_TYPE (GcmXserver, gcm_xserver, G_TYPE_OBJECT)
 /**
  * gcm_xserver_get_root_window_profile_data:
  *
+ * @xserver: a valid %GcmXserver instance
  * @data: the data that is returned from the XServer. Free with g_free()
  * @length: the size of the returned data, or %NULL if you don't care
  * @error: a %GError that is set in the result of an error, or %NULL
@@ -136,6 +138,7 @@ out:
 
 /**
  * gcm_xserver_set_root_window_profile:
+ * @xserver: a valid %GcmXserver instance
  * @filename: the filename of the ICC profile
  * @error: a %GError that is set in the result of an error, or %NULL
  * Return value: %TRUE for success.
@@ -152,6 +155,8 @@ gcm_xserver_set_root_window_profile (GcmXserver *xserver, const gchar *filename,
 	g_return_val_if_fail (GCM_IS_XSERVER (xserver), FALSE);
 	g_return_val_if_fail (filename != NULL, FALSE);
 
+	egg_debug ("setting root window ICC profile atom from %s", filename);
+
 	/* get contents of file */
 	ret = g_file_get_contents (filename, &data, &length, error);
 	if (!ret)
@@ -168,6 +173,7 @@ out:
 
 /**
  * gcm_xserver_set_root_window_profile_data:
+ * @xserver: a valid %GcmXserver instance
  * @data: the data that is to be set to the XServer
  * @length: the size of the data
  * @error: a %GError that is set in the result of an error, or %NULL
@@ -215,6 +221,183 @@ out:
 }
 
 /**
+ * gcm_xserver_get_output_profile_data:
+ *
+ * @xserver: a valid %GcmXserver instance
+ * @output_name: the output name, e.g. "LVDS1"
+ * @data: the data that is returned from the XServer. Free with g_free()
+ * @length: the size of the returned data, or %NULL if you don't care
+ * @error: a %GError that is set in the result of an error, or %NULL
+ * Return value: %TRUE for success.
+ *
+ * Gets the ICC profile data from the specified output.
+ **/
+gboolean
+gcm_xserver_get_output_profile_data (GcmXserver *xserver, const gchar *output_name, guint8 **data, gsize *length, GError **error)
+{
+	gboolean ret = FALSE;
+	const gchar *atom_name;
+	gchar *data_tmp = NULL;
+	gint format;
+	gint rc = Success;
+	gulong bytes_after;
+	gulong nitems;
+	Atom atom = None;
+	Atom type;
+	gint i;
+	XRROutputInfo *output;
+	XRRScreenResources *resources = NULL;
+	GcmXserverPrivate *priv = xserver->priv;
+
+	g_return_val_if_fail (GCM_IS_XSERVER (xserver), FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	/* get the atom name */
+	atom_name = "_ICC_PROFILE";
+
+	/* get the value */
+	gdk_error_trap_push ();
+	atom = gdk_x11_get_xatom_by_name_for_display (priv->display_gdk, atom_name);
+	resources = XRRGetScreenResources (priv->display, priv->window);
+	for (i = 0; i < resources->noutput; ++i) {
+		output = XRRGetOutputInfo (priv->display, resources, resources->outputs[i]);
+		if (g_strcmp0 (output->name, output_name) == 0) {
+			rc = XRRGetOutputProperty (priv->display, resources->outputs[i],
+						   atom, 0, ~0, False, False, AnyPropertyType, &type, &format, &nitems, &bytes_after, (unsigned char **) &data_tmp);
+			egg_debug ("found %s, got %i bytes", output_name, (guint) nitems);
+		}
+		XRRFreeOutputInfo (output);
+	}
+	gdk_error_trap_pop ();
+
+	/* did the call fail */
+	if (rc != Success) {
+		if (error != NULL)
+			*error = g_error_new (1, 0, "failed to get %s atom with rc %i", atom_name, rc);
+		goto out;
+	}
+
+	/* was nothing found */
+	if (nitems == 0) {
+		if (error != NULL)
+			*error = g_error_new (1, 0, "%s atom has not been set", atom_name);
+		goto out;
+	}
+
+	/* allocate the data using Glib, rather than asking the user to use XFree */
+	*data = g_new0 (guint8, nitems);
+	memcpy (*data, data_tmp, nitems);
+
+	/* copy the length */
+	if (length != NULL)
+		*length = nitems;
+
+	/* success */
+	ret = TRUE;
+out:
+	if (resources != NULL)
+		XRRFreeScreenResources (resources);
+	if (data_tmp != NULL)
+		XFree (data_tmp);
+	return ret;
+}
+
+/**
+ * gcm_xserver_set_output_profile:
+ * @xserver: a valid %GcmXserver instance
+ * @output_name: the output name, e.g. "LVDS1"
+ * @filename: the filename of the ICC profile
+ * @error: a %GError that is set in the result of an error, or %NULL
+ * Return value: %TRUE for success.
+ *
+ * Sets the ICC profile data to the specified output.
+ **/
+gboolean
+gcm_xserver_set_output_profile (GcmXserver *xserver, const gchar *output_name, const gchar *filename, GError **error)
+{
+	gboolean ret;
+	gchar *data = NULL;
+	gsize length;
+
+	g_return_val_if_fail (GCM_IS_XSERVER (xserver), FALSE);
+	g_return_val_if_fail (filename != NULL, FALSE);
+
+	egg_debug ("setting output '%s' ICC profile atom from %s", output_name, filename);
+
+	/* get contents of file */
+	ret = g_file_get_contents (filename, &data, &length, error);
+	if (!ret)
+		goto out;
+
+	/* send to the XServer */
+	ret = gcm_xserver_set_output_profile_data (xserver, output_name, (const guint8 *) data, length, error);
+	if (!ret)
+		goto out;
+out:
+	g_free (data);
+	return ret;
+}
+
+/**
+ * gcm_xserver_set_output_profile_data:
+ * @xserver: a valid %GcmXserver instance
+ * @output_name: the output name, e.g. "LVDS1"
+ * @data: the data that is to be set to the XServer
+ * @length: the size of the data
+ * @error: a %GError that is set in the result of an error, or %NULL
+ * Return value: %TRUE for success.
+ *
+ * Sets the ICC profile data to the specified output.
+ **/
+gboolean
+gcm_xserver_set_output_profile_data (GcmXserver *xserver, const gchar *output_name, const guint8 *data, gsize length, GError **error)
+{
+	gboolean ret = FALSE;
+	const gchar *atom_name;
+	gint rc;
+	gint i;
+	Atom atom = None;
+	XRROutputInfo *output;
+	XRRScreenResources *resources = NULL;
+	GcmXserverPrivate *priv = xserver->priv;
+
+	g_return_val_if_fail (GCM_IS_XSERVER (xserver), FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (length != 0, FALSE);
+
+	/* get the atom name */
+	atom_name = "_ICC_PROFILE";
+
+	/* get the value */
+	gdk_error_trap_push ();
+	atom = gdk_x11_get_xatom_by_name_for_display (priv->display_gdk, atom_name);
+	resources = XRRGetScreenResources (priv->display, priv->window);
+	for (i = 0; i < resources->noutput; ++i) {
+		output = XRRGetOutputInfo (priv->display, resources, resources->outputs[i]);
+		if (g_strcmp0 (output->name, output_name) == 0) {
+			egg_debug ("found %s, setting %i bytes", output_name, length);
+			XRRChangeOutputProperty (priv->display, resources->outputs[i], atom, XA_CARDINAL, 8, PropModeReplace, (unsigned char*) data, (gint)length);
+		}
+		XRRFreeOutputInfo (output);
+	}
+	rc = gdk_error_trap_pop ();
+
+	/* did the call fail */
+	if (rc != Success) {
+		if (error != NULL)
+			*error = g_error_new (1, 0, "failed to set output %s atom with rc %i", atom_name, rc);
+		goto out;
+	}
+
+	/* success */
+	ret = TRUE;
+out:
+	if (resources != NULL)
+		XRRFreeScreenResources (resources);
+	return ret;
+}
+
+/**
  * gcm_xserver_get_property:
  **/
 static void
diff --git a/src/gcm-xserver.h b/src/gcm-xserver.h
index 9f97472..807e2d5 100644
--- a/src/gcm-xserver.h
+++ b/src/gcm-xserver.h
@@ -56,6 +56,8 @@ struct _GcmXserverClass
 
 GType		 gcm_xserver_get_type		  		(void);
 GcmXserver	*gcm_xserver_new				(void);
+
+/* per screen */
 gboolean	 gcm_xserver_get_root_window_profile_data	(GcmXserver		*xserver,
 								 guint8			**data,
 								 gsize			*length,
@@ -68,7 +70,7 @@ gboolean	 gcm_xserver_set_root_window_profile		(GcmXserver		*xserver,
 								 const gchar		*filename,
 								 GError			**error);
 
-/* TODO: implement */
+/* per output */
 gboolean	 gcm_xserver_get_output_profile_data		(GcmXserver		*xserver,
 								 const gchar		*output_name,
 								 guint8			**data,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]