[gnome-color-manager] Add a new DBus method GetProfileForWindow which can return a profile for a supplied XID



commit eec8e329b8b13178219a823681be3db380c41910
Author: Richard Hughes <richard hughsie com>
Date:   Sat Jan 9 17:46:14 2010 +0000

    Add a new DBus method GetProfileForWindow which can return a profile for a supplied XID

 src/gcm-client.c               |  145 ++++++++++++++++++++++++++++++++++++++++
 src/gcm-client.h               |    3 +
 src/gcm-dbus.c                 |   53 +++++++++++++++
 src/gcm-dbus.h                 |    3 +
 src/gcm-inspect.c              |   65 +++++++++++++++++-
 src/org.gnome.ColorManager.xml |   32 +++++++++
 6 files changed, 298 insertions(+), 3 deletions(-)
---
diff --git a/src/gcm-client.c b/src/gcm-client.c
index 58eb50f..99e7d95 100644
--- a/src/gcm-client.c
+++ b/src/gcm-client.c
@@ -353,6 +353,7 @@ gcm_client_get_output_name (GcmClient *client, GnomeRROutput *output)
 	gboolean ret;
 	guint width = 0;
 	guint height = 0;
+	const guint8 *data;
 	GcmClientPrivate *priv = client->priv;
 
 	/* blank */
@@ -363,6 +364,19 @@ gcm_client_get_output_name (GcmClient *client, GnomeRROutput *output)
 	if (!ret)
 		goto out;
 
+	/* parse the EDID to get a crtc-specific name, not an output specific name */
+	data = gnome_rr_output_get_edid_data (output);
+	if (data != NULL) {
+		ret = gcm_edid_parse (priv->edid, data, NULL);
+		if (!ret) {
+			egg_warning ("failed to parse edid");
+			goto out;
+		}
+	} else {
+		/* reset, as not available */
+		gcm_edid_reset (priv->edid);
+	}
+
 	/* this is an internal panel, use the DMI data */
 	output_name = gnome_rr_output_get_name (output);
 	ret = gcm_utils_output_is_lcd_internal (output_name);
@@ -425,6 +439,7 @@ gcm_client_get_id_for_xrandr_device (GcmClient *client, GnomeRROutput *output)
 	gchar *vendor = NULL;
 	gchar *ascii = NULL;
 	gchar *serial = NULL;
+	const guint8 *data;
 	GString *string;
 	gboolean ret;
 	GcmClientPrivate *priv = client->priv;
@@ -437,6 +452,19 @@ gcm_client_get_id_for_xrandr_device (GcmClient *client, GnomeRROutput *output)
 	if (!ret)
 		goto out;
 
+	/* parse the EDID to get a crtc-specific name, not an output specific name */
+	data = gnome_rr_output_get_edid_data (output);
+	if (data != NULL) {
+		ret = gcm_edid_parse (priv->edid, data, NULL);
+		if (!ret) {
+			egg_warning ("failed to parse edid");
+			goto out;
+		}
+	} else {
+		/* reset, as not available */
+		gcm_edid_reset (priv->edid);
+	}
+
 	/* find the best option */
 	g_object_get (priv->edid,
 		      "monitor-name", &name,
@@ -475,6 +503,123 @@ out:
 }
 
 /**
+ * gcm_client_get_device_by_window_covered:
+ **/
+static gfloat
+gcm_client_get_device_by_window_covered (gint x, gint y, gint width, gint height,
+				         gint window_x, gint window_y, gint window_width, gint window_height)
+{
+	gfloat covered = 0.0f;
+	gint overlap_x;
+	gint overlap_y;
+
+	/* to the right of the window */
+	if (window_x > x + width)
+		goto out;
+	if (window_y > y + height)
+		goto out;
+
+	/* to the left of the window */
+	if (window_x + window_width < x)
+		goto out;
+	if (window_y + window_height < y)
+		goto out;
+
+	/* get the overlaps */
+	overlap_x = MIN((window_x + window_width - x), width) - MAX(window_x - x, 0);
+	overlap_y = MIN((window_y + window_height - y), height) - MAX(window_y - y, 0);
+
+	/* not in this window */
+	if (overlap_x <= 0)
+		goto out;
+	if (overlap_y <= 0)
+		goto out;
+
+	/* get the coverage */
+	covered = (gfloat) (overlap_x * overlap_y) / (gfloat) (window_width * window_height);
+	egg_debug ("overlap_x=%i,overlap_y=%i,covered=%f", overlap_x, overlap_y, covered);
+out:
+	return covered;
+}
+
+/**
+ * gcm_client_get_device_by_window:
+ **/
+GcmDevice *
+gcm_client_get_device_by_window (GcmClient *client, GdkWindow *window)
+{
+	gfloat covered;
+	gfloat covered_max = 0.0f;
+	gint window_width, window_height;
+	gint window_x, window_y;
+	gint x, y;
+	guint i;
+	guint len = 0;
+	guint width, height;
+	GnomeRRMode *mode;
+	GnomeRROutput *output_best = NULL;
+	GnomeRROutput **outputs;
+	GcmDevice *device = NULL;
+	gchar *id = NULL;
+
+	/* get the window parameters, in root co-ordinates */
+	gdk_window_get_origin (window, &window_x, &window_y);
+	gdk_drawable_get_size (GDK_DRAWABLE(window), &window_width, &window_height);
+
+	/* get list of updates */
+	outputs = gnome_rr_screen_list_outputs (client->priv->rr_screen);
+
+	/* find length */
+	for (i=0; outputs[i] != NULL; i++)
+		len++;
+
+	/* go through each option */
+	for (i=0; i<len; i++) {
+
+		/* not interesting */
+		if (!gnome_rr_output_is_connected (outputs[i]))
+			continue;
+
+		/* get details about the output */
+		gnome_rr_output_get_position (outputs[i], &x, &y);
+		mode = gnome_rr_output_get_current_mode (outputs[i]);
+		width = gnome_rr_mode_get_width (mode);
+		height = gnome_rr_mode_get_height (mode);
+		egg_debug ("%s: %ix%i -> %ix%i (%ix%i -> %ix%i)", gnome_rr_output_get_name (outputs[i]),
+			   x, y, x+width, y+height,
+			   window_x, window_y, window_x+window_width, window_y+window_height);
+
+		/* get the fraction of how much the window is covered */
+		covered = gcm_client_get_device_by_window_covered (x, y, width, height,
+								   window_x, window_y, window_width, window_height);
+
+		/* keep a running total of which one is best */
+		if (covered > 0.01f && covered > covered_max) {
+			output_best = outputs[i];
+
+			/* optimize */
+			if (covered > 0.99) {
+				egg_debug ("all in one window, no need to search other windows");
+				goto out;
+			}
+
+			/* keep looking */
+			covered_max = covered;
+			egg_debug ("personal best of %f for %s", covered, gnome_rr_output_get_name (output_best));
+		}
+	}
+out:
+	/* if we found an output, get the device */
+	if (output_best != NULL) {
+		id = gcm_client_get_id_for_xrandr_device (client, output_best);
+		egg_debug ("id: %s", id);
+		device = gcm_client_get_device_by_id (client, id);
+	}
+	g_free (id);
+	return device;
+}
+
+/**
  * gcm_client_xrandr_add:
  **/
 static void
diff --git a/src/gcm-client.h b/src/gcm-client.h
index 4e28c23..f3f1752 100644
--- a/src/gcm-client.h
+++ b/src/gcm-client.h
@@ -23,6 +23,7 @@
 #define __GCM_CLIENT_H
 
 #include <glib-object.h>
+#include <gdk/gdk.h>
 
 #include "gcm-device.h"
 
@@ -63,6 +64,8 @@ GcmClient	*gcm_client_new					(void);
 
 GcmDevice	*gcm_client_get_device_by_id			(GcmClient		*client,
 								 const gchar		*id);
+GcmDevice	*gcm_client_get_device_by_window		(GcmClient		*client,
+								 GdkWindow		*window);
 gboolean	 gcm_client_delete_device			(GcmClient		*client,
 								 GcmDevice		*device,
 								 GError			**error);
diff --git a/src/gcm-dbus.c b/src/gcm-dbus.c
index 2f456a3..a8f0dd9 100644
--- a/src/gcm-dbus.c
+++ b/src/gcm-dbus.c
@@ -361,6 +361,59 @@ gcm_dbus_get_profiles_for_type (GcmDbus *dbus, const gchar *type, const gchar *o
 }
 
 /**
+ * gcm_dbus_get_profile_for_window:
+ **/
+void
+gcm_dbus_get_profile_for_window (GcmDbus *dbus, guint xid, DBusGMethodInvocation *context)
+{
+	GError *error;
+	GcmDevice *device;
+	GdkWindow *window;
+	gchar *filename = NULL;
+
+	egg_debug ("getting profile for %i", xid);
+
+	/* get window for xid */
+	window = gdk_window_foreign_new (xid);
+	if (window == NULL) {
+		error = g_error_new (1, 0, "failed to find window with xid %i", xid);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get device for this window */
+	device = gcm_client_get_device_by_window (dbus->priv->client, window);
+	if (device == NULL) {
+		error = g_error_new (1, 0, "no device found for xid %i", xid);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get the data */
+	g_object_get (device,
+		      "profile-filename", &filename,
+		      NULL);
+	if (filename == NULL) {
+		error = g_error_new (1, 0, "no profiles found for xid %i", xid);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* return profiles */
+	dbus_g_method_return (context, filename);
+
+out:
+	/* reset time */
+	g_timer_reset (dbus->priv->timer);
+	if (window != NULL)
+		g_object_unref (window);
+	g_free (filename);
+}
+
+/**
  * gcm_dbus_class_init:
  * @klass: The GcmDbusClass
  **/
diff --git a/src/gcm-dbus.h b/src/gcm-dbus.h
index 2413071..9c7f5e7 100644
--- a/src/gcm-dbus.h
+++ b/src/gcm-dbus.h
@@ -72,6 +72,9 @@ void		 gcm_dbus_get_profiles_for_type		(GcmDbus	*dbus,
 							 const gchar	*type,
 							 const gchar	*options,
 							 DBusGMethodInvocation *context);
+void		 gcm_dbus_get_profile_for_window	(GcmDbus	*dbus,
+							 guint		 xid,
+							 DBusGMethodInvocation *context);
 
 G_END_DECLS
 
diff --git a/src/gcm-inspect.c b/src/gcm-inspect.c
index ac2e257..333d2c6 100644
--- a/src/gcm-inspect.c
+++ b/src/gcm-inspect.c
@@ -193,7 +193,8 @@ gcm_inspect_show_profiles_for_device (const gchar *sysfs_path)
 				 custom_g_type_string_string, &profile_data_array,
 				 G_TYPE_INVALID);
 	if (!ret) {
-		egg_warning ("failed: %s", error->message);
+		/* TRANSLATORS: the DBus method failed */
+		g_print ("%s: %s\n", _("The request failed"), error->message);
 		g_error_free (error);
 		goto out;
 	}
@@ -234,6 +235,56 @@ out:
 }
 
 /**
+ * gcm_inspect_show_profile_for_window:
+ **/
+static gboolean
+gcm_inspect_show_profile_for_window (guint xid)
+{
+	gboolean ret;
+	DBusGConnection *connection;
+	DBusGProxy *proxy;
+	GError *error = NULL;
+	gchar *profile = NULL;
+
+	/* get a session bus connection */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+
+	/* connect to the interface */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.gnome.ColorManager",
+					   "/org/gnome/ColorManager",
+					   "org.gnome.ColorManager");
+
+	/* execute sync method */
+	ret = dbus_g_proxy_call (proxy, "GetProfileForWindow", &error,
+				 G_TYPE_UINT, xid,
+				 G_TYPE_INVALID,
+				 G_TYPE_STRING, &profile,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		/* TRANSLATORS: the DBus method failed */
+		g_print ("%s: %s\n", _("The request failed"), error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* no data */
+	if (profile == NULL) {
+		/* TRANSLATORS: no profile has been asigned to this window */
+		g_print ("%s\n", _("There are no ICC profiles for this window"));
+		goto out;
+	}
+
+	/* TRANSLATORS: this is a list of profiles suitable for the device */
+	g_print ("%s %i\n", _("Suitable profiles for:"), xid);
+	g_print ("1.\t%s\n\t%s\n", "this is a title", profile);
+out:
+	g_object_unref (proxy);
+	g_free (profile);
+	return ret;
+}
+
+/**
  * gcm_inspect_show_profiles_for_type:
  **/
 static gboolean
@@ -275,7 +326,8 @@ gcm_inspect_show_profiles_for_type (const gchar *type)
 				 custom_g_type_string_string, &profile_data_array,
 				 G_TYPE_INVALID);
 	if (!ret) {
-		egg_warning ("failed: %s", error->message);
+		/* TRANSLATORS: the DBus method failed */
+		g_print ("%s: %s\n", _("The request failed"), error->message);
 		g_error_free (error);
 		goto out;
 	}
@@ -367,7 +419,8 @@ gcm_inspect_get_properties (void)
 				 dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &hash,
 				 G_TYPE_INVALID);
 	if (!ret) {
-		egg_warning ("failed: %s", error->message);
+		/* TRANSLATORS: the DBus method failed */
+		g_print ("%s: %s\n", _("The request failed"), error->message);
 		g_error_free (error);
 		goto out;
 	}
@@ -391,6 +444,7 @@ main (int argc, char **argv)
 {
 	gboolean x11 = FALSE;
 	gboolean dump = FALSE;
+	guint xid = 0;
 	gchar *sysfs_path = NULL;
 	gchar *type = NULL;
 	GcmDeviceType type_enum;
@@ -404,6 +458,9 @@ main (int argc, char **argv)
 		{ "device", '\0', 0, G_OPTION_ARG_STRING, &sysfs_path,
 			/* TRANSLATORS: command line option */
 			_("Get the profiles for a specific device"), NULL },
+		{ "xid", '\0', 0, G_OPTION_ARG_INT, &xid,
+			/* TRANSLATORS: command line option */
+			_("Get the profile for a specific window"), NULL },
 		{ "type", '\0', 0, G_OPTION_ARG_STRING, &type,
 			/* TRANSLATORS: command line option */
 			_("Get the profiles for a specific device type"), NULL },
@@ -433,6 +490,8 @@ main (int argc, char **argv)
 		gcm_inspect_show_x11_atoms ();
 	if (sysfs_path != NULL)
 		gcm_inspect_show_profiles_for_device (sysfs_path);
+	if (xid != 0)
+		gcm_inspect_show_profile_for_window (xid);
 	if (type != NULL) {
 		type_enum = gcm_device_type_from_text (type);
 		if (type_enum == GCM_DEVICE_TYPE_UNKNOWN) {
diff --git a/src/org.gnome.ColorManager.xml b/src/org.gnome.ColorManager.xml
index 7e36f1f..81e246e 100644
--- a/src/org.gnome.ColorManager.xml
+++ b/src/org.gnome.ColorManager.xml
@@ -150,6 +150,38 @@
       </arg>
     </method>
 
+    <!--*****************************************************************************************-->
+    <method name="GetProfileForWindow">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Gets the profile for a window. In the case where the window overlaps
+            two different outputs, then the profile with the greatest percentage
+            area is used.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              A window XID.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="profile" direction="out">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              A profile filename that is should be used for the display.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
     <!-- ************************************************************ -->
     <signal name="Changed">
       <doc:doc>



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