[gnome-color-manager] Add a new DBus method GetProfileForWindow which can return a profile for a supplied XID
- From: Richard Hughes <rhughes src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-color-manager] Add a new DBus method GetProfileForWindow which can return a profile for a supplied XID
- Date: Sat, 9 Jan 2010 17:48:26 +0000 (UTC)
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]