[Xfce4-commits] <xfce4-settings:master> Display the screen vendor in the ui

Nick Schermer noreply at xfce.org
Sat Aug 28 23:04:16 CEST 2010


Updating branch refs/heads/master
         to cd7010ebf8c4e2288df8211079d1ee74bc86d9ab (commit)
       from c8fbe1f90850f5d34df1640318813c0c0d3a3865 (commit)

commit cd7010ebf8c4e2288df8211079d1ee74bc86d9ab
Author: Lionel Le Folgoc <mrpouit at gmail.com>
Date:   Sat Jun 12 23:43:04 2010 +0200

    Display the screen vendor in the ui
    
    Drop the code that tried to read the ConnectorType property, it is not
    supported by any driver (although it is marked as mandatory by the xrandr 1.3
    spec). Instead, read the screen's EDID data to find its vendor name. It should
    be easier to identify a screen in the ui now…

 configure.ac.in                         |   11 +
 dialogs/display-settings/Makefile.am    |    6 +-
 dialogs/display-settings/display-name.c |  303 +++++++++++++++++
 dialogs/display-settings/edid-parse.c   |  544 +++++++++++++++++++++++++++++++
 dialogs/display-settings/edid.h         |  197 +++++++++++
 dialogs/display-settings/main.c         |    8 +-
 dialogs/display-settings/xfce-randr.c   |  111 ++++---
 dialogs/display-settings/xfce-randr.h   |   26 +-
 po/POTFILES.in                          |    1 +
 9 files changed, 1138 insertions(+), 69 deletions(-)

diff --git a/configure.ac.in b/configure.ac.in
index 87c0d9c..7cfd27d 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -118,6 +118,17 @@ dnl ***********************************
 XDT_CHECK_OPTIONAL_PACKAGE([XRANDR], [xrandr], [1.1.0],
                            [xrandr], [Xrandr support])
 
+dnl ***********************************
+dnl *** Optional support for hwdata ***
+dnl ***********************************
+AC_ARG_WITH([pnp-ids-path],
+            [AC_HELP_STRING([--with-pnp-ids-path],
+                            [Specify the path to pnp.ids (default=\${datadir}/hwdata/pnp.ids)])],
+            [with_pnp_ids_path=$withval],
+            [with_pnp_ids_path="\${datadir}/hwdata/pnp.ids"])
+PNP_IDS=$with_pnp_ids_path
+AC_SUBST(PNP_IDS)
+
 dnl **************************************
 dnl *** Optional support for Libnotify ***
 dnl **************************************
diff --git a/dialogs/display-settings/Makefile.am b/dialogs/display-settings/Makefile.am
index 856cb9c..724688a 100644
--- a/dialogs/display-settings/Makefile.am
+++ b/dialogs/display-settings/Makefile.am
@@ -6,6 +6,7 @@ INCLUDES = \
 	-DSRCDIR=\"$(top_srcdir)\" \
 	-DLOCALEDIR=\"$(localedir)\" \
 	-DG_LOG_DOMAIN=\"xfce4-display-settings\" \
+	-DPNP_IDS=\"$(PNP_IDS)\" \
 	$(PLATFORM_CPPFLAGS)
 
 bin_PROGRAMS = \
@@ -18,7 +19,10 @@ xfce4_display_settings_SOURCES = \
 	xfce-randr-legacy.c \
 	xfce-randr-legacy.h \
 	display-dialog_ui.h \
-	display-dialog-xrandr1.2_ui.h
+	display-dialog-xrandr1.2_ui.h \
+	display-name.c \
+	edid-parse.c \
+	edid.h
 
 xfce4_display_settings_CFLAGS = \
 	$(GTK_CFLAGS) \
diff --git a/dialogs/display-settings/display-name.c b/dialogs/display-settings/display-name.c
new file mode 100644
index 0000000..6005585
--- /dev/null
+++ b/dialogs/display-settings/display-name.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2007 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Author: Soren Sandmann <sandmann at redhat.com> */
+
+/* Downloaded from <http://git.gnome.org/browse/gnome-desktop/tree/libgnome-desktop>
+   (git commit 60f318f3d5a890c267160562f54a048d862def18)
+   Slightly modified by Lionel Le Folgoc <mrpouit at gmail.com> to build with full debug */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include "edid.h"
+
+typedef struct Vendor Vendor;
+struct Vendor
+{
+    const char vendor_id[4];
+    const char vendor_name[28];
+};
+
+/* This list of vendor codes derived from lshw
+ * 
+ * http://ezix.org/project/wiki/HardwareLiSter
+ *
+ * Note: we now prefer to use data coming from hwdata (and shipped with
+ * gnome-desktop). See
+ * http://git.fedorahosted.org/git/?p=hwdata.git;a=blob_plain;f=pnp.ids;hb=HEAD
+ * All contributions to the list of vendors should go there.
+ */
+static const struct Vendor vendors[] = 
+{
+    { "AIC", "AG Neovo" },
+    { "ACR", "Acer" },
+    { "DEL", "DELL" },
+    { "SAM", "SAMSUNG" },
+    { "SNY", "SONY" },
+    { "SEC", "Epson" },
+    { "WAC", "Wacom" },
+    { "NEC", "NEC" },
+    { "CMO", "CMO" },	/* Chi Mei */
+    { "BNQ", "BenQ" },
+
+    { "ABP", "Advansys" },
+    { "ACC", "Accton" },
+    { "ACE", "Accton" },
+    { "ADP", "Adaptec" },
+    { "ADV", "AMD" },
+    { "AIR", "AIR" },
+    { "AMI", "AMI" },
+    { "ASU", "ASUS" },
+    { "ATI", "ATI" },
+    { "ATK", "Allied Telesyn" },
+    { "AZT", "Aztech" },
+    { "BAN", "Banya" },
+    { "BRI", "Boca Research" },
+    { "BUS", "Buslogic" },
+    { "CCI", "Cache Computers Inc." },
+    { "CHA", "Chase" },
+    { "CMD", "CMD Technology, Inc." },
+    { "COG", "Cogent" },
+    { "CPQ", "Compaq" },
+    { "CRS", "Crescendo" },
+    { "CSC", "Crystal" },
+    { "CSI", "CSI" },
+    { "CTL", "Creative Labs" },
+    { "DBI", "Digi" },
+    { "DEC", "Digital Equipment" },
+    { "DBK", "Databook" },
+    { "EGL", "Eagle Technology" },
+    { "ELS", "ELSA" },
+    { "ESS", "ESS" },
+    { "FAR", "Farallon" },
+    { "FDC", "Future Domain" },
+    { "HWP", "Hewlett-Packard" },
+    { "IBM", "IBM" },
+    { "INT", "Intel" },
+    { "ISA", "Iomega" },
+    { "LEN", "Lenovo" },
+    { "MDG", "Madge" },
+    { "MDY", "Microdyne" },
+    { "MET", "Metheus" },
+    { "MIC", "Micronics" },
+    { "MLX", "Mylex" },
+    { "NVL", "Novell" },
+    { "OLC", "Olicom" },
+    { "PRO", "Proteon" },
+    { "RII", "Racal" },
+    { "RTL", "Realtek" },
+    { "SCM", "SCM" },
+    { "SKD", "SysKonnect" },
+    { "SGI", "SGI" },
+    { "SMC", "SMC" },
+    { "SNI", "Siemens Nixdorf" },
+    { "STL", "Stallion Technologies" },
+    { "SUN", "Sun" },
+    { "SUP", "SupraExpress" },
+    { "SVE", "SVEC" },
+    { "TCC", "Thomas-Conrad" },
+    { "TCI", "Tulip" },
+    { "TCM", "3Com" },
+    { "TCO", "Thomas-Conrad" },
+    { "TEC", "Tecmar" },
+    { "TRU", "Truevision" },
+    { "TOS", "Toshiba" },
+    { "TYN", "Tyan" },
+    { "UBI", "Ungermann-Bass" },
+    { "USC", "UltraStor" },
+    { "VDM", "Vadem" },
+    { "VMI", "Vermont" },
+    { "WDC", "Western Digital" },
+    { "ZDS", "Zeos" },
+
+    /* From http://faydoc.tripod.com/structures/01/0136.htm */
+    { "ACT", "Targa" },
+    { "ADI", "ADI" },
+    { "AOC", "AOC Intl" },
+    { "API", "Acer America" },
+    { "APP", "Apple Computer" },
+    { "ART", "ArtMedia" },
+    { "AST", "AST Research" },
+    { "CPL", "Compal" },
+    { "CTX", "Chuntex Electronic Co." },
+    { "DPC", "Delta Electronics" },
+    { "DWE", "Daewoo" },
+    { "ECS", "ELITEGROUP" },
+    { "EIZ", "EIZO" },
+    { "FCM", "Funai" },
+    { "GSM", "LG Electronics" },
+    { "GWY", "Gateway 2000" },
+    { "HEI", "Hyundai" },
+    { "HIT", "Hitachi" },
+    { "HSL", "Hansol" },
+    { "HTC", "Hitachi" },
+    { "ICL", "Fujitsu ICL" },
+    { "IVM", "Idek Iiyama" },
+    { "KFC", "KFC Computek" },
+    { "LKM", "ADLAS" },
+    { "LNK", "LINK Tech" },
+    { "LTN", "Lite-On" },
+    { "MAG", "MAG InnoVision" },
+    { "MAX", "Maxdata" },
+    { "MEI", "Panasonic" },
+    { "MEL", "Mitsubishi" },
+    { "MIR", "miro" },
+    { "MTC", "MITAC" },
+    { "NAN", "NANAO" },
+    { "NEC", "NEC Tech" },
+    { "NOK", "Nokia" },
+    { "OQI", "OPTIQUEST" },
+    { "PBN", "Packard Bell" },
+    { "PGS", "Princeton" },
+    { "PHL", "Philips" },
+    { "REL", "Relisys" },
+    { "SDI", "Samtron" },
+    { "SMI", "Smile" },
+    { "SPT", "Sceptre" },
+    { "SRC", "Shamrock Technology" },
+    { "STP", "Sceptre" },
+    { "TAT", "Tatung" },
+    { "TRL", "Royal Information Company" },
+    { "TSB", "Toshiba, Inc." },
+    { "UNM", "Unisys" },
+    { "VSC", "ViewSonic" },
+    { "WTC", "Wen Tech" },
+    { "ZCM", "Zenith Data Systems" },
+
+    { "???", "Unknown" },
+};
+
+static GHashTable *pnp_ids = NULL;
+
+static void
+read_pnp_ids (void)
+{
+    gchar *contents;
+    gchar **lines;
+    gchar *line;
+    gchar *code, *name;
+    gint i;
+
+    if (pnp_ids)
+        return;
+
+    pnp_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+    if (g_file_get_contents (PNP_IDS, &contents, NULL, NULL))
+    {
+        lines = g_strsplit (contents, "\n", -1);
+        for (i = 0; lines[i]; i++)
+        {
+             line = lines[i];
+             if (line[3] == '\t')
+             {
+                 code = line;
+                 line[3] = '\0';
+                 name = line + 4;
+                 g_hash_table_insert (pnp_ids, code, name);
+             }
+        }
+        g_free (lines);
+        g_free (contents);
+    }
+}
+
+
+static const char *
+find_vendor (const char *code)
+{
+    const char *vendor_name;
+    unsigned int i;
+
+    read_pnp_ids ();
+
+    vendor_name = g_hash_table_lookup (pnp_ids, code);
+
+    if (vendor_name)
+        return vendor_name;
+
+    for (i = 0; i < sizeof (vendors) / sizeof (vendors[0]); ++i)
+    {
+	const Vendor *v = &(vendors[i]);
+
+	if (strcmp (v->vendor_id, code) == 0)
+	    return v->vendor_name;
+    }
+
+    return code;
+};
+
+char *
+make_display_name (const MonitorInfo *info)
+{
+    const char *vendor;
+    int width_mm, height_mm, inches;
+
+    if (info)
+    {
+	vendor = find_vendor (info->manufacturer_code);
+    }
+    else
+    {
+        /* Translators: "Unknown" here is used to identify a monitor for which
+         * we don't know the vendor. When a vendor is known, the name of the
+         * vendor is used. */
+	vendor = C_("Monitor vendor", "Unknown");
+    }
+
+    if (info && info->width_mm != -1 && info->height_mm)
+    {
+	width_mm = info->width_mm;
+	height_mm = info->height_mm;
+    }
+    else if (info && info->n_detailed_timings)
+    {
+	width_mm = info->detailed_timings[0].width_mm;
+	height_mm = info->detailed_timings[0].height_mm;
+    }
+    else
+    {
+	width_mm = -1;
+	height_mm = -1;
+    }
+    
+    if (width_mm != -1 && height_mm != -1)
+    {
+	double d = sqrt (width_mm * width_mm + height_mm * height_mm);
+
+	inches = (int)(d / 25.4 + 0.5);
+    }
+    else
+    {
+	inches = -1;
+    }
+
+    if (inches > 0)
+	return g_strdup_printf ("%s %d\"", vendor, inches);
+    else
+	return g_strdup (vendor);
+}
diff --git a/dialogs/display-settings/edid-parse.c b/dialogs/display-settings/edid-parse.c
new file mode 100644
index 0000000..709e82a
--- /dev/null
+++ b/dialogs/display-settings/edid-parse.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2007 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Author: Soren Sandmann <sandmann at redhat.com> */
+
+/* Downloaded from <http://git.gnome.org/browse/gnome-desktop/tree/libgnome-desktop>
+   (git commit 42452cada8cf1c4d7a81aded0a3ddbb5e97441de)
+   Slightly modified by Lionel Le Folgoc <mrpouit at gmail.com> to build with full debug */
+
+#include "edid.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+
+static int
+get_bit (int in, int bit)
+{
+    return (in & (1 << bit)) >> bit;
+}
+
+static int
+get_bits (int in, int begin, int end)
+{
+    int mask = (1 << (end - begin + 1)) - 1;
+    
+    return (in >> begin) & mask;
+}
+
+static int
+decode_header (const uchar *edid)
+{
+    if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
+	return TRUE;
+    return FALSE;
+}
+
+static int
+decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
+{
+    int is_model_year;
+    
+    /* Manufacturer Code */
+    info->manufacturer_code[0]  = get_bits (edid[0x08], 2, 6);
+    info->manufacturer_code[1]  = get_bits (edid[0x08], 0, 1) << 3;
+    info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
+    info->manufacturer_code[2]  = get_bits (edid[0x09], 0, 4);
+    info->manufacturer_code[3]  = '\0';
+    
+    info->manufacturer_code[0] += 'A' - 1;
+    info->manufacturer_code[1] += 'A' - 1;
+    info->manufacturer_code[2] += 'A' - 1;
+
+    /* Product Code */
+    info->product_code = edid[0x0b] << 8 | edid[0x0a];
+
+    /* Serial Number */
+    info->serial_number =
+	edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
+
+    /* Week and Year */
+    is_model_year = FALSE;
+    switch (edid[0x10])
+    {
+    case 0x00:
+	info->production_week = -1;
+	break;
+
+    case 0xff:
+	info->production_week = -1;
+	is_model_year = TRUE;
+	break;
+
+    default:
+	info->production_week = edid[0x10];
+	break;
+    }
+
+    if (is_model_year)
+    {
+	info->production_year = -1;
+	info->model_year = 1990 + edid[0x11];
+    }
+    else
+    {
+	info->production_year = 1990 + edid[0x11];
+	info->model_year = -1;
+    }
+
+    return TRUE;
+}
+
+static int
+decode_edid_version (const uchar *edid, MonitorInfo *info)
+{
+    info->major_version = edid[0x12];
+    info->minor_version = edid[0x13];
+
+    return TRUE;
+}
+
+static int
+decode_display_parameters (const uchar *edid, MonitorInfo *info)
+{
+    /* Digital vs Analog */
+    info->is_digital = get_bit (edid[0x14], 7);
+
+    if (info->is_digital)
+    {
+	int bits;
+	
+	static const int bit_depth[8] =
+	{
+	    -1, 6, 8, 10, 12, 14, 16, -1
+	};
+
+	static const Interface interfaces[6] =
+	{
+	    UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
+	};
+
+	bits = get_bits (edid[0x14], 4, 6);
+	info->connector.digital.bits_per_primary = bit_depth[bits];
+
+	bits = get_bits (edid[0x14], 0, 3);
+	
+	if (bits <= 5)
+	    info->connector.digital.interface = interfaces[bits];
+	else
+	    info->connector.digital.interface = UNDEFINED;
+    }
+    else
+    {
+	int bits = get_bits (edid[0x14], 5, 6);
+	
+	static const double levels[][3] =
+	{
+	    { 0.7,   0.3,    1.0 },
+	    { 0.714, 0.286,  1.0 },
+	    { 1.0,   0.4,    1.4 },
+	    { 0.7,   0.0,    0.7 },
+	};
+
+	info->connector.analog.video_signal_level = levels[bits][0];
+	info->connector.analog.sync_signal_level = levels[bits][1];
+	info->connector.analog.total_signal_level = levels[bits][2];
+
+	info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
+
+	info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
+	info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
+	info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
+
+	info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
+    }
+
+    /* Screen Size / Aspect Ratio */
+    if (edid[0x15] == 0 && edid[0x16] == 0)
+    {
+	info->width_mm = -1;
+	info->height_mm = -1;
+	info->aspect_ratio = -1.0;
+    }
+    else if (edid[0x16] == 0)
+    {
+	info->width_mm = -1;
+	info->height_mm = -1; 
+	info->aspect_ratio = 100.0 / (edid[0x15] + 99);
+    }
+    else if (edid[0x15] == 0)
+    {
+	info->width_mm = -1;
+	info->height_mm = -1;
+	info->aspect_ratio = 100.0 / (edid[0x16] + 99);
+	info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
+    }
+    else
+    {
+	info->width_mm = 10 * edid[0x15];
+	info->height_mm = 10 * edid[0x16];
+    }
+
+    /* Gamma */
+    if (edid[0x17] == 0xFF)
+	info->gamma = -1.0;
+    else
+	info->gamma = (edid[0x17] + 100.0) / 100.0;
+
+    /* Features */
+    info->standby = get_bit (edid[0x18], 7);
+    info->suspend = get_bit (edid[0x18], 6);
+    info->active_off = get_bit (edid[0x18], 5);
+
+    if (info->is_digital)
+    {
+	info->connector.digital.rgb444 = TRUE;
+	if (get_bit (edid[0x18], 3))
+	    info->connector.digital.ycrcb444 = 1;
+	if (get_bit (edid[0x18], 4))
+	    info->connector.digital.ycrcb422 = 1;
+    }
+    else
+    {
+	int bits = get_bits (edid[0x18], 3, 4);
+	ColorType color_type[4] =
+	{
+	    MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
+	};
+
+	info->connector.analog.color_type = color_type[bits];
+    }
+
+    info->srgb_is_standard = get_bit (edid[0x18], 2);
+
+    /* In 1.3 this is called "has preferred timing" */
+    info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
+
+    /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
+    info->continuous_frequency = get_bit (edid[0x18], 0);
+    return TRUE;
+}
+
+static double
+decode_fraction (int high, int low)
+{
+    double result = 0.0;
+    int i;
+
+    high = (high << 2) | low;
+
+    for (i = 0; i < 10; ++i)
+	result += get_bit (high, i) * pow (2, i - 10);
+
+    return result;
+}
+
+static int
+decode_color_characteristics (const uchar *edid, MonitorInfo *info)
+{
+    info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
+    info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
+    info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
+    info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
+    info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
+    info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
+    info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
+    info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
+
+    return TRUE;
+}
+
+static int
+decode_established_timings (const uchar *edid, MonitorInfo *info)
+{
+    static const Timing established[][8] = 
+    {
+	{
+	    { 800, 600, 60 },
+	    { 800, 600, 56 },
+	    { 640, 480, 75 },
+	    { 640, 480, 72 },
+	    { 640, 480, 67 },
+	    { 640, 480, 60 },
+	    { 720, 400, 88 },
+	    { 720, 400, 70 }
+	},
+	{
+	    { 1280, 1024, 75 },
+	    { 1024, 768, 75 },
+	    { 1024, 768, 70 },
+	    { 1024, 768, 60 },
+	    { 1024, 768, 87 },
+	    { 832, 624, 75 },
+	    { 800, 600, 75 },
+	    { 800, 600, 72 }
+	},
+	{
+	    { 0, 0, 0 },
+	    { 0, 0, 0 },
+	    { 0, 0, 0 },
+	    { 0, 0, 0 },
+	    { 0, 0, 0 },
+	    { 0, 0, 0 },
+	    { 0, 0, 0 },
+	    { 1152, 870, 75 }
+	},
+    };
+
+    int i, j, idx;
+
+    idx = 0;
+    for (i = 0; i < 3; ++i)
+    {
+	for (j = 0; j < 8; ++j)
+	{
+	    int byte = edid[0x23 + i];
+
+	    if (get_bit (byte, j) && established[i][j].frequency != 0)
+		info->established[idx++] = established[i][j];
+	}
+    }
+    return TRUE;
+}
+
+static int
+decode_standard_timings (const uchar *edid, MonitorInfo *info)
+{
+    int i;
+    
+    for (i = 0; i < 8; i++)
+    {
+	int first = edid[0x26 + 2 * i];
+	int second = edid[0x27 + 2 * i];
+
+	if (first != 0x01 && second != 0x01)
+	{
+	    int w = 8 * (first + 31);
+	    int h;
+
+	    switch (get_bits (second, 6, 7))
+	    {
+	    case 0x00: h = (w / 16) * 10; break;
+	    case 0x01: h = (w / 4) * 3; break;
+	    case 0x02: h = (w / 5) * 4; break;
+	    case 0x03: h = (w / 16) * 9; break;
+	    }
+
+	    info->standard[i].width = w;
+	    info->standard[i].height = h;
+	    info->standard[i].frequency = get_bits (second, 0, 5) + 60;
+	}
+    }
+    
+    return TRUE;
+}
+
+static void
+decode_lf_string (const uchar *s, int n_chars, char *result)
+{
+    int i;
+    for (i = 0; i < n_chars; ++i)
+    {
+	if (s[i] == 0x0a)
+	{
+	    *result++ = '\0';
+	    break;
+	}
+	else if (s[i] == 0x00)
+	{
+	    /* Convert embedded 0's to spaces */
+	    *result++ = ' ';
+	}
+	else
+	{
+	    *result++ = s[i];
+	}
+    }
+}
+
+static void
+decode_display_descriptor (const uchar *desc,
+			   MonitorInfo *info)
+{
+    switch (desc[0x03])
+    {
+    case 0xFC:
+	decode_lf_string (desc + 5, 13, info->dsc_product_name);
+	break;
+    case 0xFF:
+	decode_lf_string (desc + 5, 13, info->dsc_serial_number);
+	break;
+    case 0xFE:
+	decode_lf_string (desc + 5, 13, info->dsc_string);
+	break;
+    case 0xFD:
+	/* Range Limits */
+	break;
+    case 0xFB:
+	/* Color Point */
+	break;
+    case 0xFA:
+	/* Timing Identifications */
+	break;
+    case 0xF9:
+	/* Color Management */
+	break;
+    case 0xF8:
+	/* Timing Codes */
+	break;
+    case 0xF7:
+	/* Established Timings */
+	break;
+    case 0x10:
+	break;
+    }
+}
+
+static void
+decode_detailed_timing (const uchar *timing,
+			DetailedTiming *detailed)
+{
+    int bits;
+    StereoType stereo[] =
+    {
+	NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
+	TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
+	FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
+    };
+    
+    detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
+    detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
+    detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
+    detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
+    detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
+    detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
+    detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
+    detailed->v_front_porch =
+	get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
+    detailed->v_sync =
+	get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
+    detailed->width_mm =  timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
+    detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
+    detailed->right_border = timing[0x0f];
+    detailed->top_border = timing[0x10];
+
+    detailed->interlaced = get_bit (timing[0x11], 7);
+
+    /* Stereo */
+    bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
+    detailed->stereo = stereo[bits];
+
+    /* Sync */
+    bits = timing[0x11];
+
+    detailed->digital_sync = get_bit (bits, 4);
+    if (detailed->digital_sync)
+    {
+	detailed->connector.digital.composite = !get_bit (bits, 3);
+
+	if (detailed->connector.digital.composite)
+	{
+	    detailed->connector.digital.serrations = get_bit (bits, 2);
+	    detailed->connector.digital.negative_vsync = FALSE;
+	}
+	else
+	{
+	    detailed->connector.digital.serrations = FALSE;
+	    detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
+	}
+
+	detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
+    }
+    else
+    {
+	detailed->connector.analog.bipolar = get_bit (bits, 3);
+	detailed->connector.analog.serrations = get_bit (bits, 2);
+	detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
+    }
+}
+
+static int
+decode_descriptors (const uchar *edid, MonitorInfo *info)
+{
+    int i;
+    int timing_idx;
+    
+    timing_idx = 0;
+    
+    for (i = 0; i < 4; ++i)
+    {
+	int idx = 0x36 + i * 18;
+
+	if (edid[idx + 0] == 0x00 && edid[idx + 1] == 0x00)
+	{
+	    decode_display_descriptor (edid + idx, info);
+	}
+	else
+	{
+	    decode_detailed_timing (
+		edid + idx, &(info->detailed_timings[timing_idx++]));
+	}
+    }
+
+    info->n_detailed_timings = timing_idx;
+
+    return TRUE;
+}
+
+static void
+decode_check_sum (const uchar *edid,
+		  MonitorInfo *info)
+{
+    int i;
+    uchar check = 0;
+
+    for (i = 0; i < 128; ++i)
+	check += edid[i];
+
+    info->checksum = check;
+}
+
+MonitorInfo *
+decode_edid (const uchar *edid)
+{
+    MonitorInfo *info = g_new0 (MonitorInfo, 1);
+
+    decode_check_sum (edid, info);
+    
+    if (decode_header (edid)
+	&& decode_vendor_and_product_identification (edid, info)
+	&& decode_edid_version (edid, info)
+	&& decode_display_parameters (edid, info)
+	&& decode_color_characteristics (edid, info)
+	&& decode_established_timings (edid, info)
+	&& decode_standard_timings (edid, info)
+	&& decode_descriptors (edid, info))
+    {
+	return info;
+    }
+    else
+    {
+	g_free (info);
+	return NULL;
+    }
+}
diff --git a/dialogs/display-settings/edid.h b/dialogs/display-settings/edid.h
new file mode 100644
index 0000000..d9cbb5d
--- /dev/null
+++ b/dialogs/display-settings/edid.h
@@ -0,0 +1,197 @@
+/* edid.h
+ *
+ * Copyright 2007, 2008, Red Hat, Inc.
+ * 
+ * This file is part of the Gnome Library.
+ * 
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome 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
+ * Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * 
+ * Author: Soren Sandmann <sandmann at redhat.com>
+ */
+
+/* Downloaded from <http://git.gnome.org/browse/gnome-desktop/tree/libgnome-desktop>
+   (git commit 42452cada8cf1c4d7a81aded0a3ddbb5e97441de) */
+
+#ifndef EDID_H
+#define EDID_H
+
+typedef unsigned char uchar;
+typedef struct MonitorInfo MonitorInfo;
+typedef struct Timing Timing;
+typedef struct DetailedTiming DetailedTiming;
+
+typedef enum
+{
+    UNDEFINED,
+    DVI,
+    HDMI_A,
+    HDMI_B,
+    MDDI,
+    DISPLAY_PORT
+} Interface;
+
+typedef enum
+{
+    UNDEFINED_COLOR,
+    MONOCHROME,
+    RGB,
+    OTHER_COLOR
+} ColorType;
+
+typedef enum
+{
+    NO_STEREO,
+    FIELD_RIGHT,
+    FIELD_LEFT,
+    TWO_WAY_RIGHT_ON_EVEN,
+    TWO_WAY_LEFT_ON_EVEN,
+    FOUR_WAY_INTERLEAVED,
+    SIDE_BY_SIDE
+} StereoType;
+
+struct Timing
+{
+    int width;
+    int height;
+    int frequency;
+};
+
+struct DetailedTiming
+{
+    int		pixel_clock;
+    int		h_addr;
+    int		h_blank;
+    int		h_sync;
+    int		h_front_porch;
+    int		v_addr;
+    int		v_blank;
+    int		v_sync;
+    int		v_front_porch;
+    int		width_mm;
+    int		height_mm;
+    int		right_border;
+    int		top_border;
+    int		interlaced;
+    StereoType	stereo;
+
+    int		digital_sync;
+    union
+    {
+	struct
+	{
+	    int bipolar;
+	    int serrations;
+	    int sync_on_green;
+	} analog;
+
+	struct
+	{
+	    int composite;
+	    int serrations;
+	    int negative_vsync;
+	    int negative_hsync;
+	} digital;
+    } connector;
+};
+
+struct MonitorInfo
+{
+    int			checksum;
+    char		manufacturer_code[4];
+    int			product_code;
+    unsigned int	serial_number;
+    
+    int			production_week;	/* -1 if not specified */
+    int			production_year;	/* -1 if not specified */
+    int			model_year;		/* -1 if not specified */
+
+    int			major_version;
+    int			minor_version;
+
+    int			is_digital;
+    
+    union
+    {
+	struct
+	{
+	    int		bits_per_primary;
+	    Interface	interface;
+	    int		rgb444;
+	    int		ycrcb444;
+	    int		ycrcb422;
+	} digital;
+
+	struct
+	{
+	    double	video_signal_level;
+	    double	sync_signal_level;
+	    double	total_signal_level;
+
+	    int		blank_to_black;
+
+	    int		separate_hv_sync;
+	    int		composite_sync_on_h;
+	    int		composite_sync_on_green;
+	    int		serration_on_vsync;
+	    ColorType	color_type;
+	} analog;
+    } connector;
+
+    int			width_mm;		/* -1 if not specified */
+    int			height_mm;		/* -1 if not specified */
+    double		aspect_ratio;		/* -1.0 if not specififed */
+
+    double		gamma;			/* -1.0 if not specified */
+
+    int			standby;
+    int			suspend;
+    int			active_off;
+
+    int			srgb_is_standard;
+    int			preferred_timing_includes_native;
+    int			continuous_frequency;
+
+    double		red_x;
+    double		red_y;
+    double		green_x;
+    double		green_y;
+    double		blue_x;
+    double		blue_y;
+    double		white_x;
+    double		white_y;
+
+    Timing		established[24];	/* Terminated by 0x0x0 */
+    Timing		standard[8];
+    
+    int			n_detailed_timings;
+    DetailedTiming	detailed_timings[4];	/* If monitor has a preferred
+						 * mode, it is the first one
+						 * (whether it has, is
+						 * determined by the 
+						 * preferred_timing_includes
+						 * bit.
+						 */
+
+    /* Optional product description */
+    char		dsc_serial_number[14];
+    char		dsc_product_name[14];
+    char		dsc_string[14];		/* Unspecified ASCII data */
+};
+
+MonitorInfo *decode_edid (const uchar *data);
+char *make_display_name (const MonitorInfo *info);
+
+#endif
diff --git a/dialogs/display-settings/main.c b/dialogs/display-settings/main.c
index a01e92d..2564653 100644
--- a/dialogs/display-settings/main.c
+++ b/dialogs/display-settings/main.c
@@ -558,9 +558,9 @@ display_settings_treeview_populate (GtkBuilder *builder)
                 continue;
 
             /* get a friendly name for the output */
-            name = (gchar *) xfce_randr_friendly_name (xfce_randr,
-                                                       xfce_randr->resources->outputs[n],
-                                                       xfce_randr->output_info[n]->name);
+            name = xfce_randr_friendly_name (xfce_randr,
+                                             xfce_randr->resources->outputs[n],
+                                             xfce_randr->output_info[n]->name);
 
             /* insert the output in the store */
             gtk_list_store_append (store, &iter);
@@ -569,6 +569,8 @@ display_settings_treeview_populate (GtkBuilder *builder)
                                 COLUMN_OUTPUT_ICON_NAME, "video-display",
                                 COLUMN_OUTPUT_ID, n, -1);
 
+            g_free (name);
+
             /* select active output */
             if (n == xfce_randr->active_output)
                 gtk_tree_selection_select_iter (selection, &iter);
diff --git a/dialogs/display-settings/xfce-randr.c b/dialogs/display-settings/xfce-randr.c
index feb7b91..5bb428d 100644
--- a/dialogs/display-settings/xfce-randr.c
+++ b/dialogs/display-settings/xfce-randr.c
@@ -32,6 +32,7 @@
 #include <X11/Xatom.h>
 
 #include "xfce-randr.h"
+#include "edid.h"
 
 #ifdef HAS_RANDR_ONE_POINT_TWO
 
@@ -439,79 +440,85 @@ xfce_randr_load (XfceRandr     *randr,
 
 
 
-const gchar *
+static guint8 *
+xfce_randr_read_edid_data (Display  *xdisplay,
+                           RROutput  output)
+{
+    unsigned char *prop;
+    int            actual_format;
+    unsigned long  nitems, bytes_after;
+    Atom           actual_type;
+    Atom           edid_atom;
+    guint8        *result = NULL;
+
+    edid_atom = gdk_x11_get_xatom_by_name (RR_PROPERTY_RANDR_EDID);
+
+    if (edid_atom != None)
+    {
+        if (XRRGetOutputProperty (xdisplay, output, edid_atom, 0, 100,
+                                  False, False, AnyPropertyType,
+                                  &actual_type, &actual_format, &nitems,
+                                  &bytes_after, &prop) == Success)
+        {
+            if (actual_type == XA_INTEGER && actual_format == 8)
+                result = g_memdup (prop, nitems);
+        }
+
+        XFree (prop);
+    }
+
+    return result;
+}
+
+
+
+gchar *
 xfce_randr_friendly_name (XfceRandr   *randr,
                           RROutput     output,
                           const gchar *name)
 {
-    Display         *xdisplay;
-    unsigned char   *prop;
-    int              actual_format;
-    unsigned long    nitems, bytes_after;
-    Atom             actual_type;
-    Atom             connector_type;
-    const gchar     *connector_name;
-    gchar           *friendly_name = NULL;
+    Display     *xdisplay;
+    MonitorInfo *info = NULL;
+    guint8      *edid_data;
+    gchar       *friendly_name = NULL;
 
     g_return_val_if_fail (randr != NULL && output != None && name != NULL, "<null>");
 
-#ifdef HAS_RANDR_ONE_POINT_THREE
+    /* special case, a laptop */
+    if (g_str_has_prefix (name, "LVDS")
+        || strcmp (name, "PANEL") == 0)
+        return g_strdup (_("Laptop"));
+
+    /* otherwise, get the vendor & size */
     xdisplay = gdk_x11_display_get_xdisplay (randr->display);
+    edid_data = xfce_randr_read_edid_data (xdisplay, output);
 
-    /* try to use the connector type first, more reliable */
-    connector_type = gdk_x11_get_xatom_by_name (RR_PROPERTY_CONNECTOR_TYPE);
+    if (edid_data)
+        info = decode_edid (edid_data);
 
-    if (randr->has_1_3 && connector_type != None)
-    {
-        if (XRRGetOutputProperty (xdisplay, output, connector_type, 0, 100,
-                                  False, False, AnyPropertyType, &actual_type,
-                                  &actual_format, &nitems, &bytes_after, &prop) == Success)
-        {
-            if (actual_type == XA_ATOM && actual_format == 32 && nitems == 1)
-            {
-                connector_type = *((Atom *) prop);
-                connector_name = gdk_x11_get_xatom_name (connector_type);
-
-                if (connector_name)
-                {
-                    if (strcmp (connector_name, "VGA") == 0)
-                        friendly_name = _("Monitor");
-                    else if (g_str_has_prefix (connector_name, "DVI")
-                             || strcmp (connector_name, "HDMI") == 0
-                             || strcmp (connector_name, "DisplayPort") == 0)
-                        friendly_name = _("Digital Display");
-                    else if (strcmp (connector_name, "Panel") == 0)
-                        friendly_name = _("Laptop");
-                    else if (g_str_has_prefix (connector_name, "TV"))
-                        friendly_name = _("Television");
-                    else
-                        g_warning ("Unknown or unsupported connector type.");
-                }
-            }
-            XFree (prop);
-        }
-    }
+    if (info)
+        friendly_name = make_display_name (info);
+
+    g_free (info);
+    g_free (edid_data);
 
     if (friendly_name)
         return friendly_name;
-#endif
 
-    /* fallback */
-    if (g_str_has_prefix (name, "LVDS")
-        || strcmp (name, "PANEL") == 0)
-        return _("Laptop");
-    else if (g_str_has_prefix (name, "VGA")
+    /* last attempt to return a better name */
+    if (g_str_has_prefix (name, "VGA")
              || g_str_has_prefix (name, "Analog"))
-        return _("Monitor");
+        return g_strdup (_("Monitor"));
     else if (g_str_has_prefix (name, "TV")
              || strcmp (name, "S-video") == 0)
-        return _("Television");
+        return g_strdup (_("Television"));
     else if (g_str_has_prefix (name, "TMDS")
              || g_str_has_prefix (name, "DVI")
              || g_str_has_prefix (name, "Digital"))
-        return _("Digital display");
+        return g_strdup (_("Digital display"));
 
-    return name;
+    /* everything failed, fallback */
+    return g_strdup (name);
 }
 
 #endif /* !HAS_RANDR_ONE_POINT_TWO */
diff --git a/dialogs/display-settings/xfce-randr.h b/dialogs/display-settings/xfce-randr.h
index 517666b..9eaae46 100644
--- a/dialogs/display-settings/xfce-randr.h
+++ b/dialogs/display-settings/xfce-randr.h
@@ -107,24 +107,24 @@ struct _XfceRandr
 
 
 
-XfceRandr   *xfce_randr_new           (GdkDisplay    *display,
-                                       GError       **error);
+XfceRandr *xfce_randr_new           (GdkDisplay    *display,
+                                     GError       **error);
 
-void         xfce_randr_free          (XfceRandr     *randr);
+void       xfce_randr_free          (XfceRandr     *randr);
 
-void         xfce_randr_reload        (XfceRandr     *randr);
+void       xfce_randr_reload        (XfceRandr     *randr);
 
-void         xfce_randr_save          (XfceRandr     *randr,
-                                       const gchar   *scheme,
-                                       XfconfChannel *channel);
+void       xfce_randr_save          (XfceRandr     *randr,
+                                     const gchar   *scheme,
+                                     XfconfChannel *channel);
 
-void         xfce_randr_load          (XfceRandr     *randr,
-                                       const gchar   *scheme,
-                                       XfconfChannel *channel);
+void       xfce_randr_load          (XfceRandr     *randr,
+                                     const gchar   *scheme,
+                                     XfconfChannel *channel);
 
-const gchar *xfce_randr_friendly_name (XfceRandr     *randr,
-                                       RROutput       output,
-                                       const gchar   *name);
+gchar     *xfce_randr_friendly_name (XfceRandr     *randr,
+                                     RROutput       output,
+                                     const gchar   *name);
 
 #endif /* !HAS_RANDR_ONE_POINT_TWO */
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1161f73..9cf1738 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,7 @@ dialogs/display-settings/display-dialog-xrandr1.2.glade
 dialogs/display-settings/main.c
 dialogs/display-settings/xfce-randr.c
 dialogs/display-settings/xfce-randr-legacy.c
+dialogs/display-settings/display-name.c
 dialogs/display-settings/xfce-display-settings.desktop.in
 
 dialogs/keyboard-settings/command-dialog.c



More information about the Xfce4-commits mailing list