[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