diff --git a/add-randr-12.patch b/add-randr-12.patch index 3f71e6f..aa95a17 100644 --- a/add-randr-12.patch +++ b/add-randr-12.patch @@ -1,1395 +1,1068 @@ -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/randrwrap.c ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/randrwrap.c 2008-04-08 23:39:06.000000000 -0400 -@@ -0,0 +1,1124 @@ -+#define I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA -+#include "libgnomeui/randrwrap.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DISPLAY(o) ((o)->info->screen->xdisplay) -+ -+typedef struct ScreenInfo ScreenInfo; -+ -+struct ScreenInfo -+{ -+ int min_width; -+ int max_width; -+ int min_height; -+ int max_height; -+ -+ XRRScreenResources *resources; -+ -+ RWOutput ** outputs; -+ RWCrtc ** crtcs; -+ RWMode ** modes; -+ -+ RWScreen * screen; -+}; -+ -+struct RWScreen -+{ -+ GdkScreen * gdk_screen; -+ GdkWindow * gdk_root; -+ Display * xdisplay; -+ Screen * xscreen; -+ Window xroot; -+ ScreenInfo * info; -+ -+ int randr_event_base; -+ -+ RWScreenChanged callback; -+ gpointer data; -+}; +diff --git a/configure.in b/configure.in +index f18ad7b..5b0202b 100644 +--- a/configure.in ++++ b/configure.in +@@ -51,10 +51,10 @@ AC_SUBST(GNOME_MICRO) + AC_SUBST(GNOME_DISTRIBUTOR) + AC_SUBST(GNOME_DATE) + +-GNOME_COMMON_INIT +-GNOME_DEBUG_CHECK +-GNOME_COMPILE_WARNINGS([maximum]) +-GNOME_MAINTAINER_MODE_DEFINES ++#GNOME_COMMON_INIT ++#GNOME_DEBUG_CHECK ++#GNOME_COMPILE_WARNINGS([maximum]) ++#GNOME_MAINTAINER_MODE_DEFINES + + # As a special favour for vuntz, support --disable-deprecations + +diff --git a/libgnome-desktop/ChangeLog b/libgnome-desktop/ChangeLog +index a6a4486..bc95a61 100644 +--- a/libgnome-desktop/ChangeLog ++++ b/libgnome-desktop/ChangeLog +@@ -1,3 +1,10 @@ ++2008-04-17 James Westby ++ ++ * monitor-db.c (configuration_new_current): Invert the logic in ++ the detection of clone mode so that it works for a single screen ++ as well. Without this change single screens are always reported as ++ clone, which makes no sense. ++ + 2008-03-29 Matthias Clasen + + * gnome-bg.c (get_current_slide): Handle start times in +diff --git a/libgnome-desktop/Makefile.am b/libgnome-desktop/Makefile.am +index 08e1395..68bf653 100644 +--- a/libgnome-desktop/Makefile.am ++++ b/libgnome-desktop/Makefile.am +@@ -20,7 +20,12 @@ libgnome_desktop_2_la_SOURCES = \ + gnome-desktop-item.c \ + gnome-ditem-edit.c \ + gnome-hint.c \ +- gnome-bg.c ++ gnome-bg.c \ ++ display-name.c \ ++ randrwrap.c \ ++ monitor-db.c \ ++ edid-parse.c \ ++ edid.h + + libgnome_desktop_2_la_LIBADD = \ + $(XLIB_LIBS) \ +diff --git a/libgnome-desktop/display-name.c b/libgnome-desktop/display-name.c +new file mode 100644 +index 0000000..5c46920 +--- /dev/null ++++ b/libgnome-desktop/display-name.c +@@ -0,0 +1,252 @@ ++/* ++ * 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. ++ */ + -+struct RWOutput -+{ -+ ScreenInfo * info; -+ RROutput id; -+ -+ char * name; -+ RWCrtc * current_crtc; -+ gboolean connected; -+ gulong width_mm; -+ gulong height_mm; -+ RWCrtc ** possible_crtcs; -+ RWOutput ** clones; -+ RWMode ** modes; -+ int n_preferred; -+ guint8 * edid_data; -+}; ++/* Author: Soren Sandmann */ + -+struct RWOutputWrap -+{ -+ RROutput id; -+}; ++#include ++#include ++#include ++#include ++#include ++#include "edid.h" + -+struct RWCrtc ++typedef struct Vendor Vendor; ++struct Vendor +{ -+ ScreenInfo * info; -+ RRCrtc id; -+ -+ RWMode * current_mode; -+ RWOutput ** current_outputs; -+ RWOutput ** possible_outputs; -+ int x; -+ int y; -+ -+ RWRotation current_rotation; -+ RWRotation rotations; ++ const char vendor_id[4]; ++ const char vendor_name[28]; +}; + -+struct RWMode ++/* This list of vendor codes derived from lshw ++ * ++ * http://ezix.org/project/wiki/HardwareLiSter ++ */ ++static const struct Vendor vendors[] = +{ -+ ScreenInfo * info; -+ RRMode id; -+ char * name; -+ int width; -+ int height; -+ int freq; /* in mHz */ -+}; -+ -+/* RWCrtc */ -+static RWCrtc * crtc_new (ScreenInfo *info, -+ RRCrtc id); -+static void crtc_free (RWCrtc *crtc); -+static void crtc_initialize (RWCrtc *crtc, -+ XRRScreenResources *res); -+ -+ -+/* RWOutput */ -+static RWOutput *output_new (ScreenInfo *info, -+ RROutput id); -+static void output_initialize (RWOutput *output, -+ XRRScreenResources *res); -+static void output_free (RWOutput *output); -+ -+ -+/* RWMode */ -+static RWMode * mode_new (ScreenInfo *info, -+ RRMode id); -+static void mode_initialize (RWMode *mode, -+ XRRModeInfo *info); -+static void mode_free (RWMode *mode); ++ { "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" }, ++ { "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" }, + -+/* Screen */ -+static RWOutput * -+rw_output_by_id (ScreenInfo *info, RROutput id) -+{ -+ RWOutput **output; -+ -+ for (output = info->outputs; *output; ++output) -+ { -+ if ((*output)->id == id) -+ return *output; -+ } -+ -+ return NULL; -+} -+ -+static RWCrtc * -+crtc_by_id (ScreenInfo *info, RRCrtc id) -+{ -+ RWCrtc **crtc; -+ -+ for (crtc = info->crtcs; *crtc; ++crtc) -+ { -+ if ((*crtc)->id == id) -+ return *crtc; -+ } -+ -+ return NULL; -+} -+ -+static RWMode * -+mode_by_id (ScreenInfo *info, RRMode id) -+{ -+ RWMode **mode; -+ -+ for (mode = info->modes; *mode; ++mode) -+ { -+ if ((*mode)->id == id) -+ return *mode; -+ } -+ -+ return NULL; -+} -+ -+static void -+screen_info_free (ScreenInfo *info) -+{ -+ RWOutput **output; -+ RWCrtc **crtc; -+ RWMode **mode; -+ -+ if (info->resources) -+ { -+ XRRFreeScreenResources (info->resources); -+ -+ info->resources = NULL; -+ } -+ -+ if (info->outputs) -+ { -+ for (output = info->outputs; *output; ++output) -+ output_free (*output); -+ g_free (info->outputs); -+ } -+ -+ if (info->crtcs) -+ { -+ for (crtc = info->crtcs; *crtc; ++crtc) -+ crtc_free (*crtc); -+ g_free (info->crtcs); -+ } -+ -+ if (info->modes) -+ { -+ for (mode = info->modes; *mode; ++mode) -+ mode_free (*mode); -+ g_free (info->modes); -+ } -+ -+ g_free (info); -+} -+ -+static gboolean -+fill_out_screen_info (Display *xdisplay, Window xroot, -+ ScreenInfo *info) -+{ -+ XRRScreenResources *resources; -+ -+ XRRGetScreenSizeRange (xdisplay, xroot, -+ &(info->min_width), -+ &(info->min_height), -+ &(info->max_width), -+ &(info->max_height)); -+ -+#if 0 -+ g_print ("ranges: %d - %d; %d - %d\n", -+ screen->min_width, screen->max_width, -+ screen->min_height, screen->max_height); -+#endif -+ -+ resources = XRRGetScreenResources (xdisplay, xroot); -+ -+ if (resources) -+ { -+ int i; -+ GPtrArray *a; -+ RWCrtc **crtc; -+ RWOutput **output; -+ -+#if 0 -+ g_print ("Resource Timestamp: %u\n", (guint32)resources->timestamp); -+ g_print ("Resource Configuration Timestamp: %u\n", (guint32)resources->configTimestamp); -+#endif -+ -+ info->resources = resources; -+ -+ /* We create all the structures before initializing them, so -+ * that they can refer to each other. -+ */ -+ a = g_ptr_array_new (); -+ for (i = 0; i < resources->ncrtc; ++i) -+ { -+ RWCrtc *crtc = crtc_new (info, resources->crtcs[i]); -+ -+ g_ptr_array_add (a, crtc); -+ } -+ g_ptr_array_add (a, NULL); -+ info->crtcs = (RWCrtc **)g_ptr_array_free (a, FALSE); -+ -+ a = g_ptr_array_new (); -+ for (i = 0; i < resources->noutput; ++i) -+ { -+ RWOutput *output = output_new (info, resources->outputs[i]); -+ -+ g_ptr_array_add (a, output); -+ } -+ g_ptr_array_add (a, NULL); -+ info->outputs = (RWOutput **)g_ptr_array_free (a, FALSE); -+ -+ a = g_ptr_array_new (); -+ for (i = 0; i < resources->nmode; ++i) -+ { -+ RWMode *mode = mode_new (info, resources->modes[i].id); -+ -+ g_ptr_array_add (a, mode); -+ } -+ g_ptr_array_add (a, NULL); -+ info->modes = (RWMode **)g_ptr_array_free (a, FALSE); -+ -+ /* Initialize */ -+ for (crtc = info->crtcs; *crtc; ++crtc) -+ crtc_initialize (*crtc, resources); -+ -+ for (output = info->outputs; *output; ++output) -+ output_initialize (*output, resources); -+ -+ for (i = 0; i < resources->nmode; ++i) -+ { -+ RWMode *mode = mode_by_id (info, resources->modes[i].id); -+ -+ mode_initialize (mode, &(resources->modes[i])); -+ } -+ -+ return TRUE; -+ } -+ else -+ { -+ g_print ("Couldn't get screen resources\n"); -+ -+ return FALSE; -+ } -+} -+ -+static ScreenInfo * -+screen_info_new (RWScreen *screen) -+{ -+ ScreenInfo *info = g_new0 (ScreenInfo, 1); -+ RWOutput **o; -+ -+ info->outputs = NULL; -+ info->crtcs = NULL; -+ info->modes = NULL; -+ info->screen = screen; -+ -+ if (fill_out_screen_info (screen->xdisplay, screen->xroot, info)) -+ { -+ return info; -+ } -+ else -+ { -+ g_free (info); -+ return NULL; -+ } -+ -+ for (o = info->outputs; *o; o++) -+ { -+ -+ } -+ -+} -+ -+static gboolean -+screen_update (RWScreen *screen, gboolean force_callback) -+{ -+ ScreenInfo *info; -+ gboolean changed = FALSE; -+ -+ g_return_val_if_fail (screen != NULL, FALSE); -+ -+ info = screen_info_new (screen); -+ if (info) -+ { -+ if (info->resources->configTimestamp != screen->info->resources->configTimestamp) -+ changed = TRUE; -+ -+ screen_info_free (screen->info); -+ -+ screen->info = info; -+ } -+ -+ if ((changed || force_callback) && screen->callback) -+ screen->callback (screen, screen->data); -+ -+ return changed; -+} -+ -+static GdkFilterReturn -+screen_on_event (GdkXEvent *xevent, -+ GdkEvent *event, -+ gpointer data) -+{ -+ RWScreen *screen = data; -+ XEvent *e = xevent; -+ -+ if (e->type - screen->randr_event_base == RRNotify) -+ { -+ XRRNotifyEvent *event = (XRRNotifyEvent *)e; -+ -+ switch (event->subtype) -+ { -+ default: -+ break; -+ } -+ -+ /* FIXME: we may need to be more discriminating in -+ * what causes 'changed' events -+ */ -+ screen_update (screen, TRUE); -+ } -+ -+ /* Pass the event on to GTK+ */ -+ return GDK_FILTER_CONTINUE; -+} -+ -+RWScreen * -+rw_screen_new (GdkScreen *gdk_screen, -+ RWScreenChanged callback, -+ gpointer data) -+{ -+ Display *dpy = GDK_SCREEN_XDISPLAY (gdk_screen); -+ int event_base; -+ int ignore; -+ -+ if (XRRQueryExtension (dpy, &event_base, &ignore)) -+ { -+ RWScreen *screen = g_new0 (RWScreen, 1); -+ -+ screen->gdk_screen = gdk_screen; -+ screen->gdk_root = gdk_screen_get_root_window (gdk_screen); -+ screen->xroot = gdk_x11_drawable_get_xid (screen->gdk_root); -+ screen->xdisplay = dpy; -+ screen->xscreen = gdk_x11_screen_get_xscreen (screen->gdk_screen); -+ -+ screen->callback = callback; -+ screen->data = data; -+ -+ screen->randr_event_base = event_base; -+ -+ screen->info = screen_info_new (screen); -+ -+ XRRSelectInput (screen->xdisplay, -+ screen->xroot, -+ RRScreenChangeNotifyMask | -+ RRCrtcChangeNotifyMask | -+ RROutputPropertyNotifyMask); -+ -+ gdk_x11_register_standard_event_type ( -+ gdk_screen_get_display (gdk_screen), -+ event_base, -+ RRNotify + 1); -+ -+ gdk_window_add_filter (screen->gdk_root, screen_on_event, screen); -+ return screen; -+ } -+ -+ return NULL; -+} -+ -+void -+rw_screen_set_size (RWScreen *screen, -+ int width, -+ int height, -+ int mm_width, -+ int mm_height) -+{ -+ g_return_if_fail (screen != NULL); -+ -+ XRRSetScreenSize (screen->xdisplay, screen->xroot, -+ width, height, mm_width, mm_height); -+} -+ -+void -+rw_screen_get_ranges (RWScreen *screen, -+ int *min_width, -+ int *max_width, -+ int *min_height, -+ int *max_height) -+{ -+ g_return_if_fail (screen != NULL); -+ -+ if (min_width) -+ *min_width = screen->info->min_width; -+ -+ if (max_width) -+ *max_width = screen->info->max_width; -+ -+ if (min_height) -+ *min_height = screen->info->min_height; -+ -+ if (max_height) -+ *max_height = screen->info->max_height; -+} -+ -+gboolean -+rw_screen_refresh (RWScreen *screen) -+{ -+ return screen_update (screen, FALSE); -+} -+ -+RWMode ** -+rw_screen_list_modes (RWScreen *screen) -+{ -+ return screen->info->modes; -+} -+ -+RWCrtc ** -+rw_screen_list_crtcs (RWScreen *screen) -+{ -+ return screen->info->crtcs; -+} -+ -+RWOutput ** -+rw_screen_list_outputs (RWScreen *screen) -+{ -+ return screen->info->outputs; -+} -+ -+RWCrtc * -+rw_screen_get_crtc_by_id (RWScreen *screen, -+ guint32 id) -+{ -+ int i; -+ -+ for (i = 0; screen->info->crtcs[i] != NULL; ++i) -+ { -+ if (screen->info->crtcs[i]->id == id) -+ return screen->info->crtcs[i]; -+ } -+ -+ return NULL; -+} -+ -+RWOutput * -+rw_screen_get_output_by_id (RWScreen *screen, -+ guint32 id) -+{ -+ int i; -+ -+ for (i = 0; screen->info->outputs[i] != NULL; ++i) -+ { -+ if (screen->info->outputs[i]->id == id) -+ return screen->info->outputs[i]; -+ } -+ -+ return NULL; -+} -+ -+/* RWOutput */ -+static RWOutput * -+output_new (ScreenInfo *info, RROutput id) -+{ -+ RWOutput *output = g_new0 (RWOutput, 1); -+ -+ output->id = id; -+ output->info = info; -+ -+ return output; -+} -+ -+static guint8 * -+get_property (Display *dpy, -+ RROutput output, -+ Atom atom, -+ int *len) -+{ -+ unsigned char *prop; -+ int actual_format; -+ unsigned long nitems, bytes_after; -+ Atom actual_type; -+ guint8 *result; -+ -+ XRRGetOutputProperty (dpy, output, atom, -+ 0, 100, False, False, -+ AnyPropertyType, -+ &actual_type, &actual_format, -+ &nitems, &bytes_after, &prop); -+ -+ if (actual_type == XA_INTEGER && actual_format == 8) -+ { -+ result = g_memdup (prop, nitems); -+ if (len) -+ *len = nitems; -+ } -+ else -+ { -+ result = NULL; -+ } -+ -+ XFree (prop); -+ -+ return result; -+} -+ -+static guint8 * -+read_edid_data (RWOutput *output) -+{ -+ Atom edid_atom = XInternAtom (DISPLAY (output), "EDID_DATA", FALSE); -+ guint8 *result; -+ int len; -+ -+ result = get_property (DISPLAY (output), -+ output->id, edid_atom, &len); -+ -+ if (result) -+ { -+ if (len == 128) -+ return result; -+ else -+ g_free (result); -+ } -+ -+ return NULL; -+} -+ -+static void -+output_initialize (RWOutput *output, XRRScreenResources *res) -+{ -+ XRROutputInfo *info = XRRGetOutputInfo ( -+ DISPLAY (output), res, output->id); -+ GPtrArray *a; -+ int i; -+ -+ g_print ("Output %lx Timestamp: %u\n", output->id, (guint32)info->timestamp); -+ -+ if (!info) -+ { -+ /* FIXME */ -+ return; -+ } -+ -+ output->name = g_strdup (info->name); /* FIXME: what is nameLen used for? */ -+ output->current_crtc = crtc_by_id (output->info, info->crtc); -+ output->width_mm = info->mm_width; -+ output->height_mm = info->mm_height; -+ output->connected = (info->connection == RR_Connected); -+ -+ /* Possible crtcs */ -+ a = g_ptr_array_new (); -+ -+ for (i = 0; i < info->ncrtc; ++i) -+ { -+ RWCrtc *crtc = crtc_by_id (output->info, info->crtcs[i]); -+ -+ if (crtc) -+ g_ptr_array_add (a, crtc); -+ } -+ g_ptr_array_add (a, NULL); -+ output->possible_crtcs = (RWCrtc **)g_ptr_array_free (a, FALSE); -+ -+ /* Clones */ -+ a = g_ptr_array_new (); -+ for (i = 0; i < info->nclone; ++i) -+ { -+ RWOutput *rw_output = rw_output_by_id (output->info, info->clones[i]); -+ -+ if (rw_output) -+ g_ptr_array_add (a, rw_output); -+ } -+ g_ptr_array_add (a, NULL); -+ output->clones = (RWOutput **)g_ptr_array_free (a, FALSE); -+ -+ /* Modes */ -+ a = g_ptr_array_new (); -+ for (i = 0; i < info->nmode; ++i) -+ { -+ RWMode *mode = mode_by_id (output->info, info->modes[i]); -+ -+ if (mode) -+ g_ptr_array_add (a, mode); -+ } -+ g_ptr_array_add (a, NULL); -+ output->modes = (RWMode **)g_ptr_array_free (a, FALSE); -+ -+ output->n_preferred = info->npreferred; -+ -+ /* Edid data */ -+ output->edid_data = read_edid_data (output); -+ -+ XRRFreeOutputInfo (info); -+} -+ -+static void -+output_free (RWOutput *output) -+{ -+ g_free (output); -+} -+ -+guint32 -+rw_output_get_id (RWOutput *output) -+{ -+ return output->id; -+} ++ /* 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" }, + -+const guint8 * -+rw_output_get_edid_data (RWOutput *output) -+{ -+ return output->edid_data; -+} ++ { "???", "Unknown" }, ++}; + -+RWOutput * -+rw_screen_get_output_by_name (RWScreen *screen, -+ const char *name) ++static const char * ++find_vendor (const char *code) +{ + int i; + -+ for (i = 0; screen->info->outputs[i] != NULL; ++i) ++ for (i = 0; i < sizeof (vendors) / sizeof (vendors[0]); ++i) + { -+ RWOutput *output = screen->info->outputs[i]; -+ -+ if (strcmp (output->name, name) == 0) -+ return output; ++ const Vendor *v = &(vendors[i]); ++ ++ if (strcmp (v->vendor_id, code) == 0) ++ return v->vendor_name; + } + -+ return NULL; -+} -+ -+RWCrtc * -+rw_output_get_crtc (RWOutput *output) -+{ -+ return output->current_crtc; -+} ++ return code; ++}; + -+RWMode * -+rw_output_get_current_mode (RWOutput *output) ++char * ++make_display_name (const char *output_name, ++ const MonitorInfo *info) +{ -+ RWCrtc *crtc; -+ -+ g_return_val_if_fail (output != NULL, NULL); -+ -+ if ((crtc = rw_output_get_crtc (output))) -+ return rw_crtc_get_current_mode (crtc); -+ -+ return NULL; -+} ++ const char *vendor; ++ int width_mm, height_mm, inches; + -+void -+rw_output_get_position (RWOutput *output, -+ int *x, -+ int *y) -+{ -+ RWCrtc *crtc; ++ if (output_name && ++ (strstr ("lvds", output_name) || ++ strstr ("LVDS", output_name) || ++ strstr ("Lvds", output_name))) ++ { ++ vendor = "Laptop"; ++ } ++ else if (info) ++ { ++ vendor = find_vendor (info->manufacturer_code); ++ } ++ else ++ { ++ vendor = "Unknown"; ++ } + -+ g_return_if_fail (output != NULL); ++ 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 ((crtc = rw_output_get_crtc (output))) -+ rw_crtc_get_position (crtc, x, y); -+} -+ -+const char * -+rw_output_get_name (RWOutput *output) -+{ -+ return output->name; -+} -+ -+int -+rw_output_get_width_mm (RWOutput *output) -+{ -+ return output->width_mm; -+} -+ -+int -+rw_output_get_height_mm (RWOutput *output) -+{ -+ return output->height_mm; -+} -+ -+RWMode * -+rw_output_get_preferred_mode (RWOutput *output) -+{ -+ if (output->n_preferred) -+ return output->modes[0]; -+ -+ return NULL; -+} -+ -+RWMode ** -+rw_output_list_modes (RWOutput *output) -+{ -+ return output->modes; -+} -+ -+gboolean -+rw_output_is_connected (RWOutput *output) -+{ -+ return output->connected; -+} -+ -+gboolean -+rw_output_supports_mode (RWOutput *output, -+ RWMode *mode) -+{ -+ int i; -+ -+ g_return_val_if_fail (output != NULL, FALSE); -+ g_return_val_if_fail (mode != NULL, FALSE); ++ if (width_mm != -1 && height_mm != -1) ++ { ++ double d = sqrt (width_mm * width_mm + height_mm * height_mm); + -+ for (i = 0; output->modes[i] != NULL; ++i) ++ inches = (int)(d / 25.4 + 0.5); ++ } ++ else + { -+ if (output->modes[i] == mode) -+ return TRUE; ++ inches = -1; + } + -+ return FALSE; ++ if (inches > 0) ++ return g_strdup_printf ("%s %d\"", vendor, inches); ++ else ++ return g_strdup_printf ("%s\n", vendor); +} +diff --git a/libgnome-desktop/edid-parse.c b/libgnome-desktop/edid-parse.c +new file mode 100644 +index 0000000..2611a24 +--- /dev/null ++++ b/libgnome-desktop/edid-parse.c +@@ -0,0 +1,551 @@ ++/* ++ * 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. ++ */ + -+gboolean -+rw_output_can_clone (RWOutput *output, -+ RWOutput *clone) -+{ -+ int i; ++/* Author: Soren Sandmann */ + -+ g_return_val_if_fail (output != NULL, FALSE); -+ g_return_val_if_fail (clone != NULL, FALSE); ++#include "edid.h" ++#include ++#include ++#include + -+ for (i = 0; output->clones[i] != NULL; ++i) -+ { -+ if (output->clones[i] == clone) -+ return TRUE; -+ } ++#define TRUE 1 ++#define FALSE 0 + -+ return FALSE; ++static int ++get_bit (int in, int bit) ++{ ++ return (in & (1 << bit)) >> bit; +} + -+/* RWCrtc */ -+typedef struct -+{ -+ Rotation xrot; -+ RWRotation rot; -+} RotationMap; -+static const RotationMap rotation_map[] = ++static int ++get_bits (int in, int begin, int end) +{ -+ { RR_Rotate_0, RW_ROTATION_0 }, -+ { RR_Rotate_90, RW_ROTATION_90 }, -+ { RR_Rotate_180, RW_ROTATION_180 }, -+ { RR_Rotate_270, RW_ROTATION_270 }, -+ { RR_Reflect_X, RW_REFLECT_X }, -+ { RR_Reflect_Y, RW_REFLECT_Y }, -+}; ++ int mask = (1 << (end - begin + 1)) - 1; ++ ++ return (in >> begin) & mask; ++} + -+static RWRotation -+rw_rotation_from_xrotation (Rotation r) ++static int ++decode_header (const uchar *edid) +{ -+ int i; -+ RWRotation result = 0; -+ -+ for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i) -+ { -+ if (r & rotation_map[i].xrot) -+ result |= rotation_map[i].rot; -+ } -+ -+ return result; ++ if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0) ++ return TRUE; ++ return FALSE; +} + -+static Rotation -+xrotation_from_rotation (RWRotation r) ++static int ++decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info) +{ -+ int i; -+ Rotation result = 0; ++ 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; + -+ for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i) -+ { -+ if (r & rotation_map[i].rot) -+ result |= rotation_map[i].xrot; -+ } ++ /* Product Code */ ++ info->product_code = edid[0x0b] << 8 | edid[0x0a]; + -+ return result; -+} ++ /* Serial Number */ ++ info->serial_number = ++ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24; + -+gboolean -+rw_crtc_set_config (RWCrtc *crtc, -+ int x, -+ int y, -+ RWMode *mode, -+ RWRotation rotation, -+ RWOutput **outputs, -+ int n_outputs) -+{ -+ ScreenInfo *info; -+ GArray *output_ids; -+ int i; ++ /* Week and Year */ ++ is_model_year = FALSE; ++ switch (edid[0x10]) ++ { ++ case 0x00: ++ info->production_week = -1; ++ break; + -+ g_return_val_if_fail (crtc != NULL, FALSE); -+ g_return_val_if_fail (mode != NULL || outputs == NULL || n_outputs == 0, FALSE); ++ case 0xff: ++ info->production_week = -1; ++ is_model_year = TRUE; ++ break; + -+ info = crtc->info; -+ -+ if (mode) -+ { -+ g_return_val_if_fail (x + mode->width <= info->max_width, FALSE); -+ g_return_val_if_fail (y + mode->height <= info->max_height, FALSE); ++ default: ++ info->production_week = edid[0x10]; ++ break; + } + -+ output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput)); -+ -+ if (outputs) ++ if (is_model_year) + { -+ for (i = 0; i < n_outputs; ++i) -+ g_array_append_val (output_ids, outputs[i]->id); ++ info->production_year = -1; ++ info->model_year = 1990 + edid[0x11]; ++ } ++ else ++ { ++ info->production_year = 1990 + edid[0x11]; ++ info->model_year = -1; + } -+ -+ XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id, -+ CurrentTime, -+ x, y, -+ mode? mode->id : None, -+ xrotation_from_rotation (rotation), -+ (RROutput *)output_ids->data, -+ output_ids->len); + -+ g_array_free (output_ids, TRUE); -+ + return TRUE; +} + -+RWMode * -+rw_crtc_get_current_mode (RWCrtc *crtc) -+{ -+ g_return_val_if_fail (crtc != NULL, NULL); -+ -+ return crtc->current_mode; -+} -+ -+guint32 -+rw_crtc_get_id (RWCrtc *crtc) ++static int ++decode_edid_version (const uchar *edid, MonitorInfo *info) +{ -+ g_return_val_if_fail (crtc != NULL, 0); ++ info->major_version = edid[0x12]; ++ info->minor_version = edid[0x13]; + -+ return crtc->id; ++ return TRUE; +} + -+gboolean -+rw_crtc_can_drive_output (RWCrtc *crtc, -+ RWOutput *output) ++static int ++decode_display_parameters (const uchar *edid, MonitorInfo *info) +{ -+ int i; ++ /* Digital vs Analog */ ++ info->is_digital = get_bit (edid[0x14], 7); + -+ g_return_val_if_fail (crtc != NULL, FALSE); -+ g_return_val_if_fail (output != NULL, FALSE); -+ -+ for (i = 0; crtc->possible_outputs[i] != NULL; ++i) ++ if (info->is_digital) + { -+ if (crtc->possible_outputs[i] == output) -+ return TRUE; -+ } ++ int bits; ++ ++ static const int bit_depth[8] = ++ { ++ -1, 6, 8, 10, 12, 14, 16, -1 ++ }; + -+ return FALSE; -+} ++ static const Interface interfaces[6] = ++ { ++ UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT ++ }; + -+/* FIXME: merge with get_mode()? */ -+void -+rw_crtc_get_position (RWCrtc *crtc, -+ int *x, -+ int *y) -+{ -+ g_return_if_fail (crtc != NULL); -+ -+ if (x) -+ *x = crtc->x; ++ bits = get_bits (edid[0x14], 4, 6); ++ info->digital.bits_per_primary = bit_depth[bits]; + -+ if (y) -+ *y = crtc->y; -+} ++ bits = get_bits (edid[0x14], 0, 3); ++ ++ if (bits <= 5) ++ info->digital.interface = interfaces[bits]; ++ else ++ info->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 }, ++ }; + -+/* FIXME: merge with get_mode()? */ -+RWRotation -+rw_crtc_get_current_rotation (RWCrtc *crtc) -+{ -+ return crtc->current_rotation; -+} ++ info->analog.video_signal_level = levels[bits][0]; ++ info->analog.sync_signal_level = levels[bits][1]; ++ info->analog.total_signal_level = levels[bits][2]; + -+RWRotation -+rw_crtc_get_rotations (RWCrtc *crtc) -+{ -+ return crtc->rotations; -+} ++ info->analog.blank_to_black = get_bit (edid[0x14], 4); + -+gboolean -+rw_crtc_supports_rotation (RWCrtc * crtc, -+ RWRotation rotation) -+{ -+ return (crtc->rotations & rotation); -+} ++ info->analog.separate_hv_sync = get_bit (edid[0x14], 3); ++ info->analog.composite_sync_on_h = get_bit (edid[0x14], 2); ++ info->analog.composite_sync_on_green = get_bit (edid[0x14], 1); + -+static RWCrtc * -+crtc_new (ScreenInfo *info, RROutput id) -+{ -+ RWCrtc *crtc = g_new0 (RWCrtc, 1); -+ -+ crtc->id = id; -+ crtc->info = info; -+ -+ return crtc; -+} ++ info->analog.serration_on_vsync = get_bit (edid[0x14], 0); ++ } + -+static void -+crtc_initialize (RWCrtc *crtc, XRRScreenResources *res) -+{ -+ XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id); -+ GPtrArray *a; -+ int i; -+ -+ g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp); -+ -+ if (!info) ++ /* Screen Size / Aspect Ratio */ ++ if (edid[0x15] == 0 && edid[0x16] == 0) + { -+ /* FIXME: We need to reaquire the screen resources */ -+ return; ++ info->width_mm = -1; ++ info->height_mm = -1; ++ info->aspect_ratio = -1.0; + } -+ -+ /* RWMode */ -+ crtc->current_mode = mode_by_id (crtc->info, info->mode); -+ -+ crtc->x = info->x; -+ crtc->y = info->y; -+ -+ /* Current outputs */ -+ a = g_ptr_array_new (); -+ for (i = 0; i < info->noutput; ++i) ++ 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) + { -+ RWOutput *output = rw_output_by_id (crtc->info, info->outputs[i]); -+ -+ if (output) -+ g_ptr_array_add (a, output); ++ info->digital.rgb444 = TRUE; ++ if (get_bit (edid[0x18], 3)) ++ info->digital.ycrcb444 = 1; ++ if (get_bit (edid[0x18], 4)) ++ info->digital.ycrcb422 = 1; + } -+ g_ptr_array_add (a, NULL); -+ crtc->current_outputs = (RWOutput **)g_ptr_array_free (a, FALSE); -+ -+ /* Possible outputs */ -+ a = g_ptr_array_new (); -+ for (i = 0; i < info->npossible; ++i) ++ else + { -+ RWOutput *output = rw_output_by_id (crtc->info, info->possible[i]); -+ -+ if (output) -+ g_ptr_array_add (a, output); ++ int bits = get_bits (edid[0x18], 3, 4); ++ ColorType color_type[4] = ++ { ++ MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR ++ }; ++ ++ info->analog.color_type = color_type[bits]; + } -+ g_ptr_array_add (a, NULL); -+ crtc->possible_outputs = (RWOutput **)g_ptr_array_free (a, FALSE); + -+ /* Rotations */ -+ crtc->current_rotation = rw_rotation_from_xrotation (info->rotation); -+ crtc->rotations = rw_rotation_from_xrotation (info->rotations); ++ info->srgb_is_standard = get_bit (edid[0x18], 2); + -+ XRRFreeCrtcInfo (info); ++ /* 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 void -+crtc_free (RWCrtc *crtc) ++static double ++decode_fraction (int high, int low) +{ -+ g_free (crtc->current_outputs); -+ g_free (crtc->possible_outputs); -+ g_free (crtc); ++ 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; +} + -+/* RWMode */ -+static RWMode * -+mode_new (ScreenInfo *info, RRMode id) ++static int ++decode_color_characteristics (const uchar *edid, MonitorInfo *info) +{ -+ RWMode *mode = g_new0 (RWMode, 1); -+ -+ mode->id = id; -+ mode->info = info; -+ -+ return mode; ++ 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; +} + -+guint32 -+rw_mode_get_id (RWMode *mode) ++static int ++decode_established_timings (const uchar *edid, MonitorInfo *info) +{ -+ return mode->id; ++ 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; +} + -+guint -+rw_mode_get_width (RWMode *mode) ++static int ++decode_standard_timings (const uchar *edid, MonitorInfo *info) +{ -+ return mode->width; ++ 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; +} + -+int -+rw_mode_get_freq (RWMode *mode) ++static void ++decode_lf_string (const uchar *s, int n_chars, char *result) +{ -+ return (mode->freq) / 1000; ++ 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]; ++ } ++ } +} + -+guint -+rw_mode_get_height (RWMode *mode) ++static void ++decode_display_descriptor (const uchar *desc, ++ MonitorInfo *info) +{ -+ return mode->height; ++ 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 -+mode_initialize (RWMode *mode, XRRModeInfo *info) ++decode_detailed_timing (const uchar *timing, ++ DetailedTiming *detailed) +{ -+ mode->name = g_strdup (info->name); -+ mode->width = info->width; -+ mode->height = info->height; -+ mode->freq = ((info->dotClock / (double)info->hTotal) / info->vTotal + 0.5) * 1000; -+} ++ 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]; + -+static void -+mode_free (RWMode *mode) -+{ -+ g_free (mode->name); -+ g_free (mode); -+} ++ 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]; + -+#ifdef INCLUDE_MAIN -+static void -+on_screen_changed (RWScreen *screen, gpointer data) -+{ -+ g_print ("Changed\n"); -+} ++ /* Sync */ ++ bits = timing[0x11]; + -+static gboolean -+do_refresh (gpointer data) -+{ -+ RWScreen *screen = data; ++ detailed->digital_sync = get_bit (bits, 4); ++ if (detailed->digital_sync) ++ { ++ detailed->digital.composite = !get_bit (bits, 3); + -+ rw_screen_refresh (screen); ++ if (detailed->digital.composite) ++ { ++ detailed->digital.serrations = get_bit (bits, 2); ++ detailed->digital.negative_vsync = FALSE; ++ } ++ else ++ { ++ detailed->digital.serrations = FALSE; ++ detailed->digital.negative_vsync = !get_bit (bits, 2); ++ } + -+ return TRUE; ++ detailed->digital.negative_hsync = !get_bit (bits, 0); ++ } ++ else ++ { ++ detailed->analog.bipolar = get_bit (bits, 3); ++ detailed->analog.serrations = get_bit (bits, 2); ++ detailed->analog.sync_on_green = !get_bit (bits, 1); ++ } +} + -+int -+main (int argc, char **argv) ++static int ++decode_descriptors (const uchar *edid, MonitorInfo *info) +{ + int i; ++ int timing_idx; + -+ gtk_init (&argc, &argv); -+ -+ RWScreen *screen = rw_screen_new (gdk_screen_get_default(), -+ on_screen_changed, -+ NULL); ++ timing_idx = 0; + -+ for (i = 0; screen->info->crtcs[i]; ++i) ++ for (i = 0; i < 4; ++i) + { -+ RWCrtc *crtc = screen->info->crtcs[i]; -+ -+ if (crtc->current_mode) ++ int index = 0x36 + i * 18; ++ ++ if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00) + { -+ g_print ("CRTC %p: (%d %d %d %d)\n", -+ crtc, crtc->x, crtc->y, -+ crtc->current_mode->width, crtc->current_mode->height); ++ decode_display_descriptor (edid + index, info); + } + else + { -+ g_print ("CRTC %p: turned off\n", crtc); ++ decode_detailed_timing ( ++ edid + index, &(info->detailed_timings[timing_idx++])); + } + } -+ -+ for (i = 0; screen->info->outputs[i]; ++i) -+ { -+ RWOutput *output = screen->info->outputs[i]; -+ -+ g_print ("Output %s currently", output->name); -+ -+ if (!output->current_crtc) -+ g_print (" turned off\n"); -+ else -+ g_print (" driven by CRTC %p\n", output->current_crtc); -+ } + -+ g_timeout_add (500, do_refresh, screen); -+ -+ gtk_main (); -+ -+ return 0; ++ info->n_detailed_timings = timing_idx; ++ ++ return TRUE; +} -+#endif -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/display-name.c ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/display-name.c 2008-04-08 23:39:06.000000000 -0400 -@@ -0,0 +1,252 @@ -+/* -+ * 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 */ ++static void ++decode_check_sum (const uchar *edid, ++ MonitorInfo *info) ++{ ++ int i; ++ uchar check = 0; + -+#include -+#include -+#include -+#include -+#include -+#include "edid.h" ++ for (i = 0; i < 128; ++i) ++ check += edid[i]; + -+typedef struct Vendor Vendor; -+struct Vendor -+{ -+ const char vendor_id[4]; -+ const char vendor_name[28]; -+}; ++ info->checksum = check; ++} + -+/* This list of vendor codes derived from lshw -+ * -+ * http://ezix.org/project/wiki/HardwareLiSter -+ */ -+static const struct Vendor vendors[] = ++MonitorInfo * ++decode_edid (const uchar *edid) +{ -+ { "AIC", "AG Neovo" }, -+ { "ACR", "Acer" }, -+ { "DEL", "DELL" }, -+ { "SAM", "SAMSUNG" }, -+ { "SNY", "SONY" }, -+ { "SEC", "Epson" }, -+ { "WAC", "Wacom" }, -+ { "NEC", "NEC" }, -+ { "CMO", "CMO" }, /* Chi Mei */ -+ { "BNQ", "BenQ" }, ++ MonitorInfo *info = calloc (1, sizeof (MonitorInfo)); + -+ { "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" }, -+ { "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" }, ++ decode_check_sum (edid, info); ++ ++ if (!decode_header (edid)) ++ return NULL; ++ ++ if (!decode_vendor_and_product_identification (edid, info)) ++ return NULL; ++ ++ if (!decode_edid_version (edid, info)) ++ return NULL; ++ ++ if (!decode_display_parameters (edid, info)) ++ return NULL; ++ ++ if (!decode_color_characteristics (edid, info)) ++ return NULL; ++ ++ if (!decode_established_timings (edid, info)) ++ return NULL; ++ ++ if (!decode_standard_timings (edid, info)) ++ return NULL; ++ ++ if (!decode_descriptors (edid, info)) ++ return NULL; ++ ++ return info; ++} +diff --git a/libgnome-desktop/edid.h b/libgnome-desktop/edid.h +new file mode 100644 +index 0000000..4f0573a +--- /dev/null ++++ b/libgnome-desktop/edid.h +@@ -0,0 +1,170 @@ ++typedef unsigned char uchar; ++typedef struct MonitorInfo MonitorInfo; ++typedef struct Timing Timing; ++typedef struct DetailedTiming DetailedTiming; + -+ /* 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" }, ++typedef enum ++{ ++ UNDEFINED, ++ DVI, ++ HDMI_A, ++ HDMI_B, ++ MDDI, ++ DISPLAY_PORT ++} Interface; + -+ { "???", "Unknown" }, ++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; +}; + -+static const char * -+find_vendor (const char *code) ++struct DisplayDescriptor +{ -+ int i; ++}; + -+ for (i = 0; i < sizeof (vendors) / sizeof (vendors[0]); ++i) ++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 + { -+ const Vendor *v = &(vendors[i]); -+ -+ if (strcmp (v->vendor_id, code) == 0) -+ return v->vendor_name; -+ } ++ struct ++ { ++ int bipolar; ++ int serrations; ++ int sync_on_green; ++ } analog; + -+ return code; ++ struct ++ { ++ int composite; ++ int serrations; ++ int negative_vsync; ++ int negative_hsync; ++ } digital; ++ }; +}; + -+char * -+make_display_name (const char *output_name, -+ const MonitorInfo *info) ++struct MonitorInfo +{ -+ const char *vendor; -+ int width_mm, height_mm, inches; ++ 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 */ + -+ if (output_name && -+ (strstr ("lvds", output_name) || -+ strstr ("LVDS", output_name) || -+ strstr ("Lvds", output_name))) -+ { -+ vendor = "Laptop"; -+ } -+ else if (info) -+ { -+ vendor = find_vendor (info->manufacturer_code); -+ } -+ else -+ { -+ vendor = "Unknown"; -+ } ++ int major_version; ++ int minor_version; + -+ 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; -+ } ++ int is_digital; + -+ if (width_mm != -1 && height_mm != -1) ++ union + { -+ double d = sqrt (width_mm * width_mm + height_mm * height_mm); ++ struct ++ { ++ int bits_per_primary; ++ Interface interface; ++ int rgb444; ++ int ycrcb444; ++ int ycrcb422; ++ } digital; + -+ inches = (int)(d / 25.4 + 0.5); -+ } -+ else -+ { -+ inches = -1; -+ } ++ struct ++ { ++ double video_signal_level; ++ double sync_signal_level; ++ double total_signal_level; + -+ if (inches > 0) -+ return g_strdup_printf ("%s %d\"", vendor, inches); -+ else -+ return g_strdup_printf ("%s\n", vendor); -+} -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/monitor-db.h ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/monitor-db.h 2008-04-08 23:39:06.000000000 -0400 -@@ -0,0 +1,56 @@ -+#ifndef I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA -+#error This is not for general consumption yet. -+#endif ++ 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; ++ }; ++ ++ 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 char *output_name, ++ const MonitorInfo *info); +diff --git a/libgnome-desktop/libgnomeui/Makefile.am b/libgnome-desktop/libgnomeui/Makefile.am +index 24c762b..0a143b3 100644 +--- a/libgnome-desktop/libgnomeui/Makefile.am ++++ b/libgnome-desktop/libgnomeui/Makefile.am +@@ -1,5 +1,7 @@ + libgnomeui_desktopdir = $(includedir)/gnome-desktop-2.0/libgnomeui +-libgnomeui_desktop_HEADERS = \ +- gnome-ditem-edit.h \ +- gnome-hint.h \ +- gnome-bg.h ++libgnomeui_desktop_HEADERS = \ ++ gnome-ditem-edit.h \ ++ gnome-hint.h \ ++ gnome-bg.h \ ++ randrwrap.h \ ++ monitor-db.h +diff --git a/libgnome-desktop/libgnomeui/monitor-db.h b/libgnome-desktop/libgnomeui/monitor-db.h +new file mode 100644 +index 0000000..05c7749 +--- /dev/null ++++ b/libgnome-desktop/libgnomeui/monitor-db.h +@@ -0,0 +1,52 @@ +#ifndef MONITOR_DB_H +#define MONITOR_DB_H + @@ -1442,14 +1115,12 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/monitor-db.h + RWScreen *screen); + +#endif -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/randrwrap.h ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/randrwrap.h 2008-04-08 23:39:06.000000000 -0400 -@@ -0,0 +1,100 @@ -+#ifndef I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA -+#error This is not yet for general consumption. -+#endif -+ +diff --git a/libgnome-desktop/libgnomeui/randrwrap.h b/libgnome-desktop/libgnomeui/randrwrap.h +new file mode 100644 +index 0000000..f9ab2c9 +--- /dev/null ++++ b/libgnome-desktop/libgnomeui/randrwrap.h +@@ -0,0 +1,96 @@ +#ifndef RANDR_WRAP_H +#define RANDR_WRAP_H + @@ -1546,26 +1217,15 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/randrwrap.h + RWRotation rotation); + +#endif -diff -up gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/Makefile.am.add-randr-12 gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/Makefile.am ---- gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/Makefile.am.add-randr-12 2008-04-07 17:18:12.000000000 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/libgnomeui/Makefile.am 2008-04-08 23:39:06.000000000 -0400 -@@ -2,4 +2,7 @@ libgnomeui_desktopdir = $(includedir)/gn - libgnomeui_desktop_HEADERS = \ - gnome-ditem-edit.h \ - gnome-hint.h \ -- gnome-bg.h -+ gnome-bg.h \ -+ randrwrap.h \ -+ monitor-db.h -+ -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c 2008-04-08 23:42:08.000000000 -0400 -@@ -0,0 +1,1308 @@ +diff --git a/libgnome-desktop/monitor-db.c b/libgnome-desktop/monitor-db.c +new file mode 100644 +index 0000000..95b03bd +--- /dev/null ++++ b/libgnome-desktop/monitor-db.c +@@ -0,0 +1,1286 @@ +#include +#include +#include -+#define I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA +#include "libgnomeui/monitor-db.h" +#include "edid.h" + @@ -1833,6 +1493,8 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c + int i; + GList *list; + ++ g_assert (parser != NULL); ++ + if (parser->output) + output_free (parser->output); + @@ -1912,9 +1574,11 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c + int clone_width = -1; + int clone_height = -1; + ++ g_return_val_if_fail (screen != NULL, NULL); ++ + rw_outputs = rw_screen_list_outputs (screen); + -+ config->clone = TRUE; ++ config->clone = FALSE; + + for (i = 0; rw_outputs[i] != NULL; ++i) + { @@ -1941,9 +1605,10 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c + MonitorInfo *info = NULL; + + if (edid_data) -+ { + info = decode_edid (edid_data); -+ ++ ++ if (info) ++ { + memcpy (output->vendor, info->manufacturer_code, + sizeof (output->vendor)); + @@ -1976,18 +1641,14 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c + output->rate = rw_mode_get_freq (mode); + output->rotation = rw_crtc_get_current_rotation (crtc); + -+ if (output->x != 0 || output->y != 0) -+ config->clone = FALSE; -+ -+ if (clone_width == -1) -+ { -+ clone_width = output->width; -+ clone_height = output->height; -+ } -+ else if (clone_width != output->width || -+ clone_height != output->height) -+ { -+ config->clone = FALSE; ++ if (output->x == 0 && output->y == 0) { ++ if (clone_width == -1) { ++ clone_width = output->width; ++ clone_height = output->height; ++ } else if (clone_width == output->width && ++ clone_height == output->height) { ++ config->clone = TRUE; ++ } + } + } + else @@ -2072,6 +1733,8 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c +{ + int i; + ++ g_assert (outputs != NULL); ++ + for (i = 0; outputs[i] != NULL; ++i) + output_free (outputs[i]); +} @@ -2079,6 +1742,7 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c +void +configuration_free (Configuration *config) +{ ++ g_return_if_fail (config != NULL); + outputs_free (config->outputs); + + g_free (config); @@ -2089,6 +1753,8 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c +{ + int i; + ++ g_assert (configurations != NULL); ++ + for (i = 0; configurations[i] != NULL; ++i) + configuration_free (configurations[i]); + @@ -2139,6 +1805,9 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c +static gboolean +output_match (Output *output1, Output *output2) +{ ++ g_assert (output1 != NULL); ++ g_assert (output2 != NULL); ++ + if (strcmp (output1->name, output2->name) != 0) + return FALSE; + @@ -2157,1480 +1826,1887 @@ diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/monitor-db.c + return TRUE; +} + -+static Output * -+find_output (Configuration *config, const char *name) -+{ -+ int i; ++static Output * ++find_output (Configuration *config, const char *name) ++{ ++ int i; ++ ++ for (i = 0; config->outputs[i] != NULL; ++i) ++ { ++ Output *output = config->outputs[i]; ++ ++ if (strcmp (name, output->name) == 0) ++ return output; ++ } ++ ++ return NULL; ++} ++ ++gboolean ++configuration_match (Configuration *c1, Configuration *c2) ++{ ++ int i; ++ ++ for (i = 0; c1->outputs[i] != NULL; ++i) ++ { ++ Output *output1 = c1->outputs[i]; ++ Output *output2; ++ ++ output2 = find_output (c2, output1->name); ++ if (!output2 || !output_match (output1, output2)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static Output ** ++make_outputs (Configuration *config) ++{ ++ GPtrArray *outputs; ++ Output *first_on;; ++ int i; ++ ++ outputs = g_ptr_array_new (); ++ ++ first_on = NULL; ++ ++ for (i = 0; config->outputs[i] != NULL; ++i) ++ { ++ Output *old = config->outputs[i]; ++ Output *new = output_copy (old); ++ ++ if (old->on && !first_on) ++ first_on = old; ++ ++ if (config->clone && new->on) ++ { ++ g_assert (first_on); ++ ++ new->width = first_on->width; ++ new->height = first_on->height; ++ new->rotation = first_on->rotation; ++ new->x = 0; ++ new->y = 0; ++ } ++ ++ g_ptr_array_add (outputs, new); ++ } ++ ++ g_ptr_array_add (outputs, NULL); ++ ++ return (Output **)g_ptr_array_free (outputs, FALSE); ++} ++ ++gboolean ++configuration_applicable (Configuration *configuration, ++ RWScreen *screen) ++{ ++ Output **outputs = make_outputs (configuration); ++ CrtcAssignment *assign = crtc_assignment_new (screen, outputs); ++ gboolean result; ++ ++ if (assign) ++ { ++ result = TRUE; ++ crtc_assignment_free (assign); ++ } ++ else ++ { ++ result = FALSE; ++ } ++ ++ outputs_free (outputs); ++ ++ return result; ++} ++ ++static Configuration * ++configuration_find (Configuration **haystack, ++ Configuration *needle) ++{ ++ int i; ++ ++ for (i = 0; haystack[i] != NULL; ++i) ++ { ++ if (configuration_match (haystack[i], needle)) ++ return haystack[i]; ++ } ++ ++ return NULL; ++} ++ ++/* Database management */ ++static gboolean ++do_free (gpointer data) ++{ ++ g_free (data); ++ return FALSE; ++} ++ ++static gchar * ++idle_free (gchar *s) ++{ ++ g_idle_add (do_free, s); ++ ++ return s; ++} ++ ++static const gchar * ++get_filename (void) ++{ ++ return idle_free ( ++ g_build_filename ( ++ g_get_home_dir(), ".gnome2", "monitors.xml", NULL)); ++} ++ ++static const char * ++get_rotation_name (RWRotation r) ++{ ++ if (r & RW_ROTATION_0) ++ return "normal"; ++ if (r & RW_ROTATION_90) ++ return "left"; ++ if (r & RW_ROTATION_180) ++ return "upside_down"; ++ if (r & RW_ROTATION_270) ++ return "right"; ++ ++ return "normal"; ++} ++ ++static const char * ++yes_no (int x) ++{ ++ return x? "yes" : "no"; ++} ++ ++static const char * ++get_reflect_x (RWRotation r) ++{ ++ return yes_no (r & RW_REFLECT_X); ++} ++ ++static const char * ++get_reflect_y (RWRotation r) ++{ ++ return yes_no (r & RW_REFLECT_Y); ++} ++ ++static void ++emit_configuration (Configuration *config, ++ GString *string) ++{ ++ int j; ++ ++ g_string_append_printf (string, "\n"); ++ ++ g_string_append_printf (string, " %s\n", yes_no (config->clone)); ++ ++ for (j = 0; config->outputs[j] != NULL; ++j) ++ { ++ Output *output = config->outputs[j]; ++ ++ g_string_append_printf ( ++ string, " \n", output->name); ++ ++ if (output->connected && *output->vendor != '\0') ++ { ++ g_string_append_printf ( ++ string, " %s\n", output->vendor); ++ g_string_append_printf ( ++ string, " 0x%04x\n", output->product); ++ g_string_append_printf ( ++ string, " 0x%08x\n", output->serial); ++ } ++ ++ /* An unconnected output which is on does not make sense */ ++ if (output->connected && output->on) ++ { ++ g_string_append_printf ( ++ string, " %d\n", output->width); ++ g_string_append_printf ( ++ string, " %d\n", output->height); ++ g_string_append_printf ( ++ string, " %d\n", output->rate); ++ g_string_append_printf ( ++ string, " %d\n", output->x); ++ g_string_append_printf ( ++ string, " %d\n", output->y); ++ g_string_append_printf ( ++ string, " %s\n", get_rotation_name (output->rotation)); ++ g_string_append_printf ( ++ string, " %s\n", get_reflect_x (output->rotation)); ++ g_string_append_printf ( ++ string, " %s\n", get_reflect_y (output->rotation)); ++ } ++ ++ g_string_append_printf (string, " \n"); ++ } ++ ++ g_string_append_printf (string, "\n"); ++} ++ ++void ++configuration_sanitize (Configuration *config) ++{ ++ int i; ++ int x_offset, y_offset; ++ ++ /* Offset everything by the top/left-most coordinate to ++ * make sure the configuration starts at (0, 0) ++ */ ++ x_offset = y_offset = G_MAXINT; ++ for (i = 0; config->outputs[i]; ++i) ++ { ++ Output *output = config->outputs[i]; ++ ++ if (output->on) ++ { ++ x_offset = MIN (x_offset, output->x); ++ y_offset = MIN (y_offset, output->y); ++ } ++ } + -+ for (i = 0; config->outputs[i] != NULL; ++i) ++ for (i = 0; config->outputs[i]; ++i) + { + Output *output = config->outputs[i]; + -+ if (strcmp (name, output->name) == 0) -+ return output; ++ if (output->on) ++ { ++ output->x -= x_offset; ++ output->y -= y_offset; ++ } + } -+ -+ return NULL; +} + +gboolean -+configuration_match (Configuration *c1, Configuration *c2) ++configuration_save (Configuration *configuration, GError **err) +{ ++ Configuration **configurations; ++ GString *output = g_string_new(""); + int i; + -+ for (i = 0; c1->outputs[i] != NULL; ++i) ++ configurations = configurations_read (get_filename(), NULL); ++ ++ if (configurations) + { -+ Output *output1 = c1->outputs[i]; -+ Output *output2; ++ for (i = 0; configurations[i] != NULL; ++i) ++ { ++ if (!configuration_match (configurations[i], configuration)) ++ emit_configuration (configurations[i], output); ++ } + -+ output2 = find_output (c2, output1->name); -+ if (!output2 || !output_match (output1, output2)) -+ return FALSE; ++ configurations_free (configurations); + } -+ -+ return TRUE; ++ ++ emit_configuration (configuration, output); ++ ++ return g_file_set_contents (get_filename(), output->str, -1, err); +} + -+static Output ** -+make_outputs (Configuration *config) ++static gboolean ++apply_configuration (Configuration *conf, RWScreen *screen) +{ -+ GPtrArray *outputs; -+ Output *first_on;; -+ int i; ++ CrtcAssignment *assignment; ++ Output **outputs; + -+ outputs = g_ptr_array_new (); ++ outputs = make_outputs (conf); + -+ first_on = NULL; ++ assignment = crtc_assignment_new (screen, outputs); ++ ++ outputs_free (outputs); + -+ for (i = 0; config->outputs[i] != NULL; ++i) ++ if (assignment) + { -+ Output *old = config->outputs[i]; -+ Output *new = output_copy (old); -+ -+ if (old->on && !first_on) -+ first_on = old; -+ -+ if (config->clone && new->on) -+ { -+ g_assert (first_on); -+ -+ new->width = first_on->width; -+ new->height = first_on->height; -+ new->rotation = first_on->rotation; -+ new->x = 0; -+ new->y = 0; -+ } ++ crtc_assignment_apply (assignment); ++ ++ crtc_assignment_free (assignment); + -+ g_ptr_array_add (outputs, new); ++ return TRUE; + } + -+ g_ptr_array_add (outputs, NULL); -+ -+ return (Output **)g_ptr_array_free (outputs, FALSE); ++ return FALSE; +} + +gboolean -+configuration_applicable (Configuration *configuration, -+ RWScreen *screen) ++configuration_apply_stored (RWScreen *screen) +{ -+ Output **outputs = make_outputs (configuration); -+ CrtcAssignment *assign = crtc_assignment_new (screen, outputs); ++ char *file = g_build_filename ( ++ g_get_home_dir(), ".gnome2", "monitors.xml", NULL); ++ Configuration **configs = configurations_read (file, NULL); ++ Configuration *current; ++ Configuration *found; + gboolean result; + -+ if (assign) -+ { -+ result = TRUE; -+ crtc_assignment_free (assign); -+ } -+ else ++ if (!screen) ++ return FALSE; ++ ++ rw_screen_refresh (screen); ++ ++ current = configuration_new_current (screen); ++ if (configs) + { -+ result = FALSE; ++ if ((found = configuration_find (configs, current))) ++ { ++ apply_configuration (found, screen); ++ result = TRUE; ++ } ++ else ++ { ++ result = FALSE; ++ } ++ ++ configurations_free (configs); + } -+ -+ outputs_free (outputs); ++ ++ g_free (file); ++ configuration_free (current); + + return result; +} + -+static Configuration * -+configuration_find (Configuration **haystack, -+ Configuration *needle) ++ ++/* ++ * CRTC assignment ++ */ ++typedef struct CrtcInfo CrtcInfo; ++ ++struct CrtcInfo ++{ ++ RWMode *mode; ++ int x; ++ int y; ++ RWRotation rotation; ++ GPtrArray *outputs; ++}; ++ ++struct CrtcAssignment ++{ ++ RWScreen *screen; ++ GHashTable *info; ++}; ++ ++static gboolean ++can_clone (CrtcInfo *info, ++ RWOutput *output) +{ + int i; + -+ for (i = 0; haystack[i] != NULL; ++i) ++ for (i = 0; i < info->outputs->len; ++i) + { -+ if (configuration_match (haystack[i], needle)) -+ return haystack[i]; ++ RWOutput *clone = info->outputs->pdata[i]; ++ ++ if (!rw_output_can_clone (clone, output)) ++ return FALSE; + } + -+ return NULL; ++ return TRUE; +} + -+/* Database management */ +static gboolean -+do_free (gpointer data) ++crtc_assignment_assign (CrtcAssignment *assign, ++ RWCrtc *crtc, ++ RWMode *mode, ++ int x, ++ int y, ++ RWRotation rotation, ++ RWOutput *output) +{ -+ g_free (data); ++ /* FIXME: We should reject stuff that is outside the screen ranges */ ++ ++ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); ++ ++ if (!rw_crtc_can_drive_output (crtc, output) || ++ !rw_output_supports_mode (output, mode) || ++ !rw_crtc_supports_rotation (crtc, rotation)) ++ { ++ return FALSE; ++ } ++ ++ if (info) ++ { ++ if (info->mode == mode && ++ info->x == x && ++ info->y == y && ++ info->rotation == rotation && ++ can_clone (info, output)) ++ { ++ g_ptr_array_add (info->outputs, output); ++ ++ return TRUE; ++ } ++ } ++ else ++ { ++ CrtcInfo *info = g_new0 (CrtcInfo, 1); ++ ++ info->mode = mode; ++ info->x = x; ++ info->y = y; ++ info->rotation = rotation; ++ info->outputs = g_ptr_array_new (); ++ ++ g_ptr_array_add (info->outputs, output); ++ ++ g_hash_table_insert (assign->info, crtc, info); ++ ++ return TRUE; ++ } ++ + return FALSE; +} + -+static gchar * -+idle_free (gchar *s) ++static void ++crtc_assignment_unassign (CrtcAssignment *assign, ++ RWCrtc *crtc, ++ RWOutput *output) +{ -+ g_idle_add (do_free, s); ++ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); + -+ return s; -+} ++ if (info) ++ { ++ g_ptr_array_remove (info->outputs, output); + -+static const gchar * -+get_filename (void) -+{ -+ return idle_free ( -+ g_build_filename ( -+ g_get_home_dir(), ".gnome2", "monitors.xml", NULL)); ++ if (info->outputs->len == 0) ++ g_hash_table_remove (assign->info, crtc); ++ } +} + -+static const char * -+get_rotation_name (RWRotation r) ++static void ++crtc_assignment_free (CrtcAssignment *assign) +{ -+ if (r & RW_ROTATION_0) -+ return "normal"; -+ if (r & RW_ROTATION_90) -+ return "left"; -+ if (r & RW_ROTATION_180) -+ return "upside_down"; -+ if (r & RW_ROTATION_270) -+ return "right"; ++ g_hash_table_destroy (assign->info); + -+ return "normal"; ++ g_free (assign); +} + -+static const char * -+yes_no (int x) ++static void ++configure_crtc (gpointer key, ++ gpointer value, ++ gpointer data) +{ -+ return x? "yes" : "no"; ++ RWCrtc *crtc = key; ++ CrtcInfo *info = value; ++ ++ rw_crtc_set_config (crtc, ++ info->x, info->y, ++ info->mode, ++ info->rotation, ++ (RWOutput **)info->outputs->pdata, ++ info->outputs->len); +} + -+static const char * -+get_reflect_x (RWRotation r) ++static gboolean ++mode_is_rotated (CrtcInfo *info) +{ -+ return yes_no (r & RW_REFLECT_X); ++ if ((info->rotation & RW_ROTATION_270) || ++ (info->rotation & RW_ROTATION_90)) ++ { ++ return TRUE; ++ } ++ return FALSE; +} + -+static const char * -+get_reflect_y (RWRotation r) ++static gboolean ++crtc_is_rotated (RWCrtc *crtc) +{ -+ return yes_no (r & RW_REFLECT_Y); ++ RWRotation r = rw_crtc_get_current_rotation (crtc); ++ ++ if ((r & RW_ROTATION_270) || ++ (r & RW_ROTATION_90)) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; +} + +static void -+emit_configuration (Configuration *config, -+ GString *string) ++crtc_assignment_apply (CrtcAssignment *assign) +{ -+ int j; -+ -+ g_string_append_printf (string, "\n"); ++ GList *active_crtcs = g_hash_table_get_keys (assign->info); ++ RWCrtc **all_crtcs = rw_screen_list_crtcs (assign->screen); ++ GList *list; ++ int width, height; ++ int i; ++ int min_width, max_width, min_height, max_height; ++ int width_mm, height_mm; + -+ g_string_append_printf (string, " %s\n", yes_no (config->clone)); -+ -+ for (j = 0; config->outputs[j] != NULL; ++j) ++ /* Compute size of the screen */ ++ width = height = 1; ++ for (list = active_crtcs; list != NULL; list = list->next) + { -+ Output *output = config->outputs[j]; -+ -+ g_string_append_printf ( -+ string, " \n", output->name); -+ -+ if (output->connected && *output->vendor != '\0') -+ { -+ g_string_append_printf ( -+ string, " %s\n", output->vendor); -+ g_string_append_printf ( -+ string, " 0x%04x\n", output->product); -+ g_string_append_printf ( -+ string, " 0x%08x\n", output->serial); -+ } ++ RWCrtc *crtc = list->data; ++ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); ++ int w, h; ++ ++ w = rw_mode_get_width (info->mode); ++ h = rw_mode_get_height (info->mode); + -+ /* An unconnected output which is on does not make sense */ -+ if (output->connected && output->on) ++ if (mode_is_rotated (info)) + { -+ g_string_append_printf ( -+ string, " %d\n", output->width); -+ g_string_append_printf ( -+ string, " %d\n", output->height); -+ g_string_append_printf ( -+ string, " %d\n", output->rate); -+ g_string_append_printf ( -+ string, " %d\n", output->x); -+ g_string_append_printf ( -+ string, " %d\n", output->y); -+ g_string_append_printf ( -+ string, " %s\n", get_rotation_name (output->rotation)); -+ g_string_append_printf ( -+ string, " %s\n", get_reflect_x (output->rotation)); -+ g_string_append_printf ( -+ string, " %s\n", get_reflect_y (output->rotation)); ++ int tmp = h; ++ h = w; ++ w = tmp; + } + -+ g_string_append_printf (string, " \n"); ++ width = MAX (width, info->x + w); ++ height = MAX (height, info->y + h); + } -+ -+ g_string_append_printf (string, "\n"); -+} ++ g_list_free (active_crtcs); + -+void -+configuration_sanitize (Configuration *config) -+{ -+ int i; -+ int x_offset, y_offset; ++ rw_screen_get_ranges ( ++ assign->screen, &min_width, &max_width, &min_height, &max_height); + -+ /* Offset everything by the top/left-most coordinate to -+ * make sure the configuration starts at (0, 0) -+ */ -+ x_offset = y_offset = G_MAXINT; -+ for (i = 0; config->outputs[i]; ++i) ++ width = MAX (min_width, width); ++ width = MIN (max_width, width); ++ height = MAX (min_height, height); ++ height = MIN (max_height, height); ++ ++ /* Turn off all crtcs currently displaying outside the new screen */ ++ for (i = 0; all_crtcs[i] != NULL; ++i) + { -+ Output *output = config->outputs[i]; ++ RWCrtc *crtc = all_crtcs[i]; ++ RWMode *mode = rw_crtc_get_current_mode (crtc); ++ int x, y; + -+ if (output->on) ++ if (mode) + { -+ x_offset = MIN (x_offset, output->x); -+ y_offset = MIN (y_offset, output->y); ++ int w, h; ++ rw_crtc_get_position (crtc, &x, &y); ++ ++ w = rw_mode_get_width (mode); ++ h = rw_mode_get_height (mode); ++ ++ if (crtc_is_rotated (crtc)) ++ { ++ int tmp = h; ++ h = w; ++ w = tmp; ++ } ++ ++ if (x + w > width || y + h > height) ++ rw_crtc_set_config (crtc, 0, 0, NULL, RW_ROTATION_0, NULL, 0); + } + } + -+ for (i = 0; config->outputs[i]; ++i) ++ /* Turn off all CRTC's that are not in the assignment */ ++ for (i = 0; all_crtcs[i] != NULL; ++i) + { -+ Output *output = config->outputs[i]; ++ RWCrtc *crtc = all_crtcs[i]; + -+ if (output->on) -+ { -+ output->x -= x_offset; -+ output->y -= y_offset; -+ } ++ if (!g_hash_table_lookup (assign->info, crtc)) ++ rw_crtc_set_config (crtc, 0, 0, NULL, RW_ROTATION_0, NULL, 0); + } ++ ++ /* The 'physical size' of an X screen is meaningless if that screen ++ * can consist of many monitors. So just pick a size that make the ++ * dpi 96. ++ * ++ * Firefox and Evince apparently believe what X tells them. ++ */ ++ width_mm = (width / 96.0) * 25.4 + 0.5; ++ height_mm = (height / 96.0) * 25.4 + 0.5; ++ ++ rw_screen_set_size (assign->screen, width, height, width_mm, height_mm); ++ ++ g_hash_table_foreach (assign->info, configure_crtc, NULL); +} + -+gboolean -+configuration_save (Configuration *configuration, GError **err) ++/* Check whether the given set of settings can be used ++ * at the same time -- ie. whether there is an assignment ++ * of CRTC's to outputs. ++ * ++ * Brute force - the number of objects involved is small ++ * enough that it doesn't matter. ++ */ ++static gboolean ++real_assign_crtcs (RWScreen *screen, ++ Output **outputs, ++ CrtcAssignment *assignment) +{ -+ Configuration **configurations; -+ GString *output = g_string_new(""); ++ RWCrtc **crtcs = rw_screen_list_crtcs (screen); ++ Output *output; + int i; + -+ configurations = configurations_read (get_filename(), NULL); -+ -+ if (configurations) ++ output = *outputs; ++ if (!output) ++ return TRUE; ++ ++ /* It is always allowed for an output to be turned off */ ++ if (!output->on) + { -+ for (i = 0; configurations[i] != NULL; ++i) ++ return real_assign_crtcs (screen, outputs + 1, assignment); ++ } ++ ++ for (i = 0; crtcs[i] != NULL; ++i) ++ { ++ int pass; ++ ++ /* Make two passses, one where frequencies must match, then ++ * one where they don't have to ++ */ ++ for (pass = 0; pass < 2; ++pass) + { -+ if (!configuration_match (configurations[i], configuration)) -+ emit_configuration (configurations[i], output); ++ RWCrtc *crtc = crtcs[i]; ++ RWOutput *rw_output = rw_screen_get_output_by_name (screen, output->name); ++ RWMode **modes = rw_output_list_modes (rw_output); ++ int j; ++ ++ for (j = 0; modes[j] != NULL; ++j) ++ { ++ RWMode *mode = modes[j]; ++ ++ if (rw_mode_get_width (mode) == output->width && ++ rw_mode_get_height (mode) == output->height && ++ (pass == 1 || rw_mode_get_freq (mode) == output->rate)) ++ { ++ if (crtc_assignment_assign ( ++ assignment, crtc, modes[j], ++ output->x, output->y, ++ output->rotation, ++ rw_output)) ++ { ++ if (real_assign_crtcs (screen, outputs + 1, assignment)) ++ return TRUE; ++ ++ crtc_assignment_unassign (assignment, crtc, rw_output); ++ } ++ } ++ } + } -+ -+ configurations_free (configurations); + } + -+ emit_configuration (configuration, output); -+ -+ return g_file_set_contents (get_filename(), output->str, -1, err); ++ return FALSE; +} + -+static gboolean -+apply_configuration (Configuration *conf, RWScreen *screen) ++static void ++crtc_info_free (CrtcInfo *info) +{ -+ CrtcAssignment *assignment; -+ Output **outputs; ++ g_ptr_array_free (info->outputs, TRUE); ++ g_free (info); ++} + -+ g_print ("applying configuration. Clone: %s\n", yes_no (conf->clone)); -+ -+ outputs = make_outputs (conf); ++static CrtcAssignment * ++crtc_assignment_new (RWScreen *screen, Output **outputs) ++{ ++ CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1); + -+ assignment = crtc_assignment_new (screen, outputs); ++ assignment->info = g_hash_table_new_full ( ++ g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free); + -+ outputs_free (outputs); -+ -+ if (assignment) ++ if (real_assign_crtcs (screen, outputs, assignment)) + { -+ crtc_assignment_apply (assignment); -+ -+ crtc_assignment_free (assignment); -+ -+ return TRUE; ++ assignment->screen = screen; ++ ++ return assignment; + } + else + { -+ g_print (" ... no assignment found\n"); ++ crtc_assignment_free (assignment); ++ ++ return NULL; + } -+ -+ return FALSE; +} +diff --git a/libgnome-desktop/randrwrap.c b/libgnome-desktop/randrwrap.c +new file mode 100644 +index 0000000..6b4cecb +--- /dev/null ++++ b/libgnome-desktop/randrwrap.c +@@ -0,0 +1,1195 @@ ++#include "libgnomeui/randrwrap.h" ++#include ++#include ++#include ++#include ++#include ++#include + -+gboolean -+configuration_apply_stored (RWScreen *screen) ++#define DISPLAY(o) ((o)->info->screen->xdisplay) ++ ++typedef struct ScreenInfo ScreenInfo; ++ ++struct ScreenInfo +{ -+ char *file = g_build_filename ( -+ g_get_home_dir(), ".gnome2", "monitors.xml", NULL); -+ Configuration **configs = configurations_read (file, NULL); -+ Configuration *current; -+ Configuration *found; -+ gboolean result; ++ int min_width; ++ int max_width; ++ int min_height; ++ int max_height; + -+ rw_screen_refresh (screen); ++ XRRScreenResources *resources; + -+ current = configuration_new_current (screen); -+ if (configs) -+ { -+ if ((found = configuration_find (configs, current))) -+ { -+ apply_configuration (found, screen); -+ result = TRUE; -+ } -+ else -+ { -+ result = FALSE; -+ } -+ -+ configurations_free (configs); -+ } -+ -+ g_free (file); -+ configuration_free (current); ++ RWOutput ** outputs; ++ RWCrtc ** crtcs; ++ RWMode ** modes; + -+ return result; -+} ++ RWScreen * screen; ++}; + ++struct RWScreen ++{ ++ GdkScreen * gdk_screen; ++ GdkWindow * gdk_root; ++ Display * xdisplay; ++ Screen * xscreen; ++ Window xroot; ++ ScreenInfo * info; ++ ++ int randr_event_base; + -+/* -+ * CRTC assignment -+ */ -+typedef struct CrtcInfo CrtcInfo; ++ RWScreenChanged callback; ++ gpointer data; ++}; + -+struct CrtcInfo ++struct RWOutput +{ -+ RWMode *mode; -+ int x; -+ int y; -+ RWRotation rotation; -+ GPtrArray *outputs; ++ ScreenInfo * info; ++ RROutput id; ++ ++ char * name; ++ RWCrtc * current_crtc; ++ gboolean connected; ++ gulong width_mm; ++ gulong height_mm; ++ RWCrtc ** possible_crtcs; ++ RWOutput ** clones; ++ RWMode ** modes; ++ int n_preferred; ++ guint8 * edid_data; +}; + -+struct CrtcAssignment ++struct RWOutputWrap +{ -+ RWScreen *screen; -+ GHashTable *info; ++ RROutput id; +}; + -+static gboolean -+can_clone (CrtcInfo *info, -+ RWOutput *output) ++struct RWCrtc +{ -+ int i; ++ ScreenInfo * info; ++ RRCrtc id; ++ ++ RWMode * current_mode; ++ RWOutput ** current_outputs; ++ RWOutput ** possible_outputs; ++ int x; ++ int y; + -+ for (i = 0; i < info->outputs->len; ++i) -+ { -+ RWOutput *clone = info->outputs->pdata[i]; ++ RWRotation current_rotation; ++ RWRotation rotations; ++}; + -+ if (!rw_output_can_clone (clone, output)) -+ return FALSE; -+ } ++struct RWMode ++{ ++ ScreenInfo * info; ++ RRMode id; ++ char * name; ++ int width; ++ int height; ++ int freq; /* in mHz */ ++}; + -+ return TRUE; -+} ++/* RWCrtc */ ++static RWCrtc * crtc_new (ScreenInfo *info, ++ RRCrtc id); ++static void crtc_free (RWCrtc *crtc); ++static void crtc_initialize (RWCrtc *crtc, ++ XRRScreenResources *res); + -+static gboolean -+crtc_assignment_assign (CrtcAssignment *assign, -+ RWCrtc *crtc, -+ RWMode *mode, -+ int x, -+ int y, -+ RWRotation rotation, -+ RWOutput *output) ++ ++/* RWOutput */ ++static RWOutput *output_new (ScreenInfo *info, ++ RROutput id); ++static void output_initialize (RWOutput *output, ++ XRRScreenResources *res); ++static void output_free (RWOutput *output); ++ ++ ++/* RWMode */ ++static RWMode * mode_new (ScreenInfo *info, ++ RRMode id); ++static void mode_initialize (RWMode *mode, ++ XRRModeInfo *info); ++static void mode_free (RWMode *mode); ++ ++ ++/* Screen */ ++static RWOutput * ++rw_output_by_id (ScreenInfo *info, RROutput id) +{ -+ /* FIXME: We should reject stuff that is outside the screen ranges */ -+ -+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); ++ RWOutput **output; + -+ if (!rw_crtc_can_drive_output (crtc, output) || -+ !rw_output_supports_mode (output, mode) || -+ !rw_crtc_supports_rotation (crtc, rotation)) -+ { -+ return FALSE; -+ } ++ g_assert (info != NULL); + -+ if (info) ++ for (output = info->outputs; *output; ++output) + { -+ if (info->mode == mode && -+ info->x == x && -+ info->y == y && -+ info->rotation == rotation && -+ can_clone (info, output)) -+ { -+ g_ptr_array_add (info->outputs, output); -+ -+ return TRUE; -+ } -+ } -+ else -+ { -+ CrtcInfo *info = g_new0 (CrtcInfo, 1); -+ -+ info->mode = mode; -+ info->x = x; -+ info->y = y; -+ info->rotation = rotation; -+ info->outputs = g_ptr_array_new (); -+ -+ g_ptr_array_add (info->outputs, output); -+ -+ g_hash_table_insert (assign->info, crtc, info); -+ -+ return TRUE; ++ if ((*output)->id == id) ++ return *output; + } + -+ return FALSE; ++ return NULL; +} + -+static void -+crtc_assignment_unassign (CrtcAssignment *assign, -+ RWCrtc *crtc, -+ RWOutput *output) ++static RWCrtc * ++crtc_by_id (ScreenInfo *info, RRCrtc id) +{ -+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); ++ RWCrtc **crtc; + -+ if (info) -+ { -+ g_ptr_array_remove (info->outputs, output); ++ if (!info) ++ return NULL; + -+ if (info->outputs->len == 0) -+ g_hash_table_remove (assign->info, crtc); ++ for (crtc = info->crtcs; *crtc; ++crtc) ++ { ++ if ((*crtc)->id == id) ++ return *crtc; + } ++ ++ return NULL; +} + -+static void -+crtc_assignment_free (CrtcAssignment *assign) ++static RWMode * ++mode_by_id (ScreenInfo *info, RRMode id) +{ -+ g_hash_table_destroy (assign->info); ++ RWMode **mode; + -+ g_free (assign); ++ g_assert (info != NULL); ++ ++ for (mode = info->modes; *mode; ++mode) ++ { ++ if ((*mode)->id == id) ++ return *mode; ++ } ++ ++ return NULL; +} + +static void -+configure_crtc (gpointer key, -+ gpointer value, -+ gpointer data) ++screen_info_free (ScreenInfo *info) +{ -+ RWCrtc *crtc = key; -+ CrtcInfo *info = value; ++ RWOutput **output; ++ RWCrtc **crtc; ++ RWMode **mode; + -+ g_print ("Configuring crtc %x with ", rw_crtc_get_id (crtc)); ++ g_assert (info != NULL); + -+ if (info->mode) ++ if (info->resources) + { -+ int n_outputs = info->outputs->len; -+ -+ g_print ("mode %x, %d outputs (%d %d %d %d), and rotation %d ", -+ rw_mode_get_id (info->mode), -+ n_outputs, -+ info->x, info->y, -+ rw_mode_get_width (info->mode), -+ rw_mode_get_height (info->mode), -+ info->rotation); ++ XRRFreeScreenResources (info->resources); ++ ++ info->resources = NULL; + } -+ else ++ ++ if (info->outputs) + { -+ g_print ("no mode "); ++ for (output = info->outputs; *output; ++output) ++ output_free (*output); ++ g_free (info->outputs); + } + -+ if (rw_crtc_set_config (crtc, -+ info->x, info->y, -+ info->mode, -+ info->rotation, -+ (RWOutput **)info->outputs->pdata, -+ info->outputs->len)) ++ if (info->crtcs) + { -+ g_print ("succeeded\n"); ++ for (crtc = info->crtcs; *crtc; ++crtc) ++ crtc_free (*crtc); ++ g_free (info->crtcs); + } -+ else ++ ++ if (info->modes) + { -+ g_print ("failed\n"); ++ for (mode = info->modes; *mode; ++mode) ++ mode_free (*mode); ++ g_free (info->modes); + } ++ ++ g_free (info); +} + +static gboolean -+mode_is_rotated (CrtcInfo *info) ++fill_out_screen_info (Display *xdisplay, Window xroot, ++ ScreenInfo *info) +{ -+ if ((info->rotation & RW_ROTATION_270) || -+ (info->rotation & RW_ROTATION_90)) ++ XRRScreenResources *resources; ++ ++ g_assert (xdisplay != NULL); ++ g_assert (info != NULL); ++ ++ gdk_error_trap_push (); ++ ++ if (!XRRGetScreenSizeRange (xdisplay, xroot, ++ &(info->min_width), ++ &(info->min_height), ++ &(info->max_width), ++ &(info->max_height))) { ++ /* XRR caught an error */ ++ return False; ++ } ++ ++ gdk_flush (); ++ if (gdk_error_trap_pop ()) ++ { ++ /* Unhandled X Error was generated */ ++ return False; ++ } ++ ++#if 0 ++ g_print ("ranges: %d - %d; %d - %d\n", ++ screen->min_width, screen->max_width, ++ screen->min_height, screen->max_height); ++#endif ++ ++ resources = XRRGetScreenResources (xdisplay, xroot); ++ ++ if (resources) + { -+ g_print ("rotated: %d\n", info->rotation); ++ int i; ++ GPtrArray *a; ++ RWCrtc **crtc; ++ RWOutput **output; ++ ++#if 0 ++ g_print ("Resource Timestamp: %u\n", (guint32)resources->timestamp); ++ g_print ("Resource Configuration Timestamp: %u\n", (guint32)resources->configTimestamp); ++#endif ++ ++ info->resources = resources; ++ ++ /* We create all the structures before initializing them, so ++ * that they can refer to each other. ++ */ ++ a = g_ptr_array_new (); ++ for (i = 0; i < resources->ncrtc; ++i) ++ { ++ RWCrtc *crtc = crtc_new (info, resources->crtcs[i]); ++ ++ g_ptr_array_add (a, crtc); ++ } ++ g_ptr_array_add (a, NULL); ++ info->crtcs = (RWCrtc **)g_ptr_array_free (a, FALSE); ++ ++ a = g_ptr_array_new (); ++ for (i = 0; i < resources->noutput; ++i) ++ { ++ RWOutput *output = output_new (info, resources->outputs[i]); ++ ++ g_ptr_array_add (a, output); ++ } ++ g_ptr_array_add (a, NULL); ++ info->outputs = (RWOutput **)g_ptr_array_free (a, FALSE); ++ ++ a = g_ptr_array_new (); ++ for (i = 0; i < resources->nmode; ++i) ++ { ++ RWMode *mode = mode_new (info, resources->modes[i].id); ++ ++ g_ptr_array_add (a, mode); ++ } ++ g_ptr_array_add (a, NULL); ++ info->modes = (RWMode **)g_ptr_array_free (a, FALSE); ++ ++ /* Initialize */ ++ for (crtc = info->crtcs; *crtc; ++crtc) ++ crtc_initialize (*crtc, resources); ++ ++ for (output = info->outputs; *output; ++output) ++ output_initialize (*output, resources); ++ ++ for (i = 0; i < resources->nmode; ++i) ++ { ++ RWMode *mode = mode_by_id (info, resources->modes[i].id); ++ ++ mode_initialize (mode, &(resources->modes[i])); ++ } ++ + return TRUE; + } -+ return FALSE; ++ else ++ { ++ g_print ("Couldn't get screen resources\n"); ++ ++ return FALSE; ++ } +} + -+static gboolean -+crtc_is_rotated (RWCrtc *crtc) ++static ScreenInfo * ++screen_info_new (RWScreen *screen) +{ -+ RWRotation r = rw_crtc_get_current_rotation (crtc); ++ ScreenInfo *info = g_new0 (ScreenInfo, 1); ++ RWOutput **o; + -+ if ((r & RW_ROTATION_270) || -+ (r & RW_ROTATION_90)) ++ g_assert (screen != NULL); ++ ++ info->outputs = NULL; ++ info->crtcs = NULL; ++ info->modes = NULL; ++ info->screen = screen; ++ ++ if (fill_out_screen_info (screen->xdisplay, screen->xroot, info)) + { -+ return TRUE; ++ return info; ++ } ++ else ++ { ++ g_free (info); ++ return NULL; + } + -+ return FALSE; ++ for (o = info->outputs; *o; o++) ++ { ++ ++ } ++ +} + -+static void -+crtc_assignment_apply (CrtcAssignment *assign) ++static gboolean ++screen_update (RWScreen *screen, gboolean force_callback) +{ -+ GList *active_crtcs = g_hash_table_get_keys (assign->info); -+ RWCrtc **all_crtcs = rw_screen_list_crtcs (assign->screen); -+ GList *list; -+ int width, height; -+ int i; -+ int min_width, max_width, min_height, max_height; -+ int width_mm, height_mm; ++ ScreenInfo *info; ++ gboolean changed = FALSE; ++ ++ g_assert (screen != NULL); + -+ /* Compute size of the screen */ -+ width = height = 1; -+ for (list = active_crtcs; list != NULL; list = list->next) ++ info = screen_info_new (screen); ++ if (info) + { -+ RWCrtc *crtc = list->data; -+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); -+ int w, h; -+ -+ w = rw_mode_get_width (info->mode); -+ h = rw_mode_get_height (info->mode); ++ if (info->resources->configTimestamp != screen->info->resources->configTimestamp) ++ changed = TRUE; + -+ if (mode_is_rotated (info)) -+ { -+ int tmp = h; -+ h = w; -+ w = tmp; -+ } ++ screen_info_free (screen->info); + -+ width = MAX (width, info->x + w); -+ height = MAX (height, info->y + h); ++ screen->info = info; + } -+ g_list_free (active_crtcs); ++ ++ if ((changed || force_callback) && screen->callback) ++ screen->callback (screen, screen->data); + -+ rw_screen_get_ranges ( -+ assign->screen, &min_width, &max_width, &min_height, &max_height); ++ return changed; ++} + -+ width = MAX (min_width, width); -+ width = MIN (max_width, width); -+ height = MAX (min_height, height); -+ height = MIN (max_height, height); ++static GdkFilterReturn ++screen_on_event (GdkXEvent *xevent, ++ GdkEvent *event, ++ gpointer data) ++{ ++ RWScreen *screen = data; ++ XEvent *e = xevent; + -+ /* Turn off all crtcs currently displaying outside the new screen */ -+ for (i = 0; all_crtcs[i] != NULL; ++i) ++ if (e && e->type - screen->randr_event_base == RRNotify) + { -+ RWCrtc *crtc = all_crtcs[i]; -+ RWMode *mode = rw_crtc_get_current_mode (crtc); -+ int x, y; ++ XRRNotifyEvent *event = (XRRNotifyEvent *)e; + -+ if (mode) ++ switch (event->subtype) + { -+ int w, h; -+ rw_crtc_get_position (crtc, &x, &y); -+ -+ w = rw_mode_get_width (mode); -+ h = rw_mode_get_height (mode); -+ -+ if (crtc_is_rotated (crtc)) -+ { -+ int tmp = h; -+ h = w; -+ w = tmp; -+ } -+ -+ if (x + w > width || y + h > height) -+ rw_crtc_set_config (crtc, 0, 0, NULL, RW_ROTATION_0, NULL, 0); ++ default: ++ break; + } -+ } -+ -+ /* Turn off all CRTC's that are not in the assignment */ -+ for (i = 0; all_crtcs[i] != NULL; ++i) -+ { -+ RWCrtc *crtc = all_crtcs[i]; + -+ if (!g_hash_table_lookup (assign->info, crtc)) -+ rw_crtc_set_config (crtc, 0, 0, NULL, RW_ROTATION_0, NULL, 0); ++ /* FIXME: we may need to be more discriminating in ++ * what causes 'changed' events ++ */ ++ screen_update (screen, TRUE); + } -+ -+ /* The 'physical size' of an X screen is meaningless if that screen -+ * can consist of many monitors. So just pick a size that make the -+ * dpi 96. -+ * -+ * Firefox and evince apparently believe what X tells them. -+ */ -+ width_mm = (width / 96.0) * 25.4 + 0.5; -+ height_mm = (height / 96.0) * 25.4 + 0.5; + -+ rw_screen_set_size (assign->screen, width, height, width_mm, height_mm); -+ -+ g_hash_table_foreach (assign->info, configure_crtc, NULL); ++ /* Pass the event on to GTK+ */ ++ return GDK_FILTER_CONTINUE; +} + -+/* Check whether the given set of settings can be used -+ * at the same time -- ie. whether there is an assignment -+ * of CRTC's to outputs. -+ * -+ * Brute force - the number of objects involved is small -+ * enough that it doesn't matter. ++/* Returns NULL if screen could not be created. For instance, if driver ++ * does not support Xrandr 1.2. + */ -+static gboolean -+real_assign_crtcs (RWScreen *screen, -+ Output **outputs, -+ CrtcAssignment *assignment) ++RWScreen * ++rw_screen_new (GdkScreen *gdk_screen, ++ RWScreenChanged callback, ++ gpointer data) +{ -+ RWCrtc **crtcs = rw_screen_list_crtcs (screen); -+ Output *output; -+ int i; ++ Display *dpy = GDK_SCREEN_XDISPLAY (gdk_screen); ++ int event_base; ++ int ignore; ++ ++ if (XRRQueryExtension (dpy, &event_base, &ignore)) ++ { ++ RWScreen *screen = g_new0 (RWScreen, 1); + -+ output = *outputs; -+ if (!output) -+ return TRUE; ++ screen->gdk_screen = gdk_screen; ++ screen->gdk_root = gdk_screen_get_root_window (gdk_screen); ++ screen->xroot = gdk_x11_drawable_get_xid (screen->gdk_root); ++ screen->xdisplay = dpy; ++ screen->xscreen = gdk_x11_screen_get_xscreen (screen->gdk_screen); + -+ /* It is always allowed for an output to be turned off */ -+ if (!output->on) -+ { -+ return real_assign_crtcs (screen, outputs + 1, assignment); -+ } ++ screen->callback = callback; ++ screen->data = data; ++ ++ screen->randr_event_base = event_base; + -+ for (i = 0; crtcs[i] != NULL; ++i) -+ { -+ int pass; ++ screen->info = screen_info_new (screen); + -+ /* Make two passses, one where frequencies must match, then -+ * one where they don't have to -+ */ -+ for (pass = 0; pass < 2; ++pass) -+ { -+ RWCrtc *crtc = crtcs[i]; -+ RWOutput *rw_output = rw_screen_get_output_by_name (screen, output->name); -+ RWMode **modes = rw_output_list_modes (rw_output); -+ int j; ++ if (!screen->info) ++ return NULL; + -+ for (j = 0; modes[j] != NULL; ++j) -+ { -+ RWMode *mode = modes[j]; -+ -+ if (rw_mode_get_width (mode) == output->width && -+ rw_mode_get_height (mode) == output->height && -+ (pass == 1 || rw_mode_get_freq (mode) == output->rate)) -+ { -+ if (crtc_assignment_assign ( -+ assignment, crtc, modes[j], -+ output->x, output->y, -+ output->rotation, -+ rw_output)) -+ { -+ if (real_assign_crtcs (screen, outputs + 1, assignment)) -+ return TRUE; -+ -+ crtc_assignment_unassign (assignment, crtc, rw_output); -+ } -+ } -+ } -+ } -+ } ++ XRRSelectInput (screen->xdisplay, ++ screen->xroot, ++ RRScreenChangeNotifyMask | ++ RRCrtcChangeNotifyMask | ++ RROutputPropertyNotifyMask); ++ ++ gdk_x11_register_standard_event_type ( ++ gdk_screen_get_display (gdk_screen), ++ event_base, ++ RRNotify + 1); + -+ return FALSE; ++ gdk_window_add_filter (screen->gdk_root, screen_on_event, screen); ++ return screen; ++ } ++ ++ return NULL; +} + -+static void -+crtc_info_free (CrtcInfo *info) ++void ++rw_screen_set_size (RWScreen *screen, ++ int width, ++ int height, ++ int mm_width, ++ int mm_height) +{ -+ g_ptr_array_free (info->outputs, TRUE); -+ g_free (info); ++ g_return_if_fail (screen != NULL); ++ ++ XRRSetScreenSize (screen->xdisplay, screen->xroot, ++ width, height, mm_width, mm_height); +} + -+static CrtcAssignment * -+crtc_assignment_new (RWScreen *screen, Output **outputs) ++void ++rw_screen_get_ranges (RWScreen *screen, ++ int *min_width, ++ int *max_width, ++ int *min_height, ++ int *max_height) +{ -+ CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1); -+ -+ assignment->info = g_hash_table_new_full ( -+ g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free); ++ g_return_if_fail (screen != NULL); + -+ if (real_assign_crtcs (screen, outputs, assignment)) -+ { -+ assignment->screen = screen; -+ -+ return assignment; -+ } -+ else -+ { -+ crtc_assignment_free (assignment); -+ -+ return NULL; -+ } -+} -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/edid-parse.c ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/edid-parse.c 2008-04-08 23:39:06.000000000 -0400 -@@ -0,0 +1,551 @@ -+/* -+ * 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. -+ */ ++ if (min_width) ++ *min_width = screen->info->min_width; + -+/* Author: Soren Sandmann */ ++ if (max_width) ++ *max_width = screen->info->max_width; + -+#include "edid.h" -+#include -+#include -+#include ++ if (min_height) ++ *min_height = screen->info->min_height; + -+#define TRUE 1 -+#define FALSE 0 ++ if (max_height) ++ *max_height = screen->info->max_height; ++} + -+static int -+get_bit (int in, int bit) ++gboolean ++rw_screen_refresh (RWScreen *screen) +{ -+ return (in & (1 << bit)) >> bit; ++ return screen_update (screen, FALSE); +} + -+static int -+get_bits (int in, int begin, int end) ++RWMode ** ++rw_screen_list_modes (RWScreen *screen) +{ -+ int mask = (1 << (end - begin + 1)) - 1; -+ -+ return (in >> begin) & mask; ++ g_return_val_if_fail (screen != NULL, NULL); ++ g_return_val_if_fail (screen->info != NULL, NULL); ++ ++ return screen->info->modes; +} + -+static int -+decode_header (const uchar *edid) ++RWCrtc ** ++rw_screen_list_crtcs (RWScreen *screen) +{ -+ if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0) -+ return TRUE; -+ return FALSE; ++ g_return_val_if_fail (screen != NULL, NULL); ++ g_return_val_if_fail (screen->info != NULL, NULL); ++ ++ return screen->info->crtcs; +} + -+static int -+decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info) ++RWOutput ** ++rw_screen_list_outputs (RWScreen *screen) +{ -+ 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; ++ g_return_val_if_fail (screen != NULL, NULL); ++ g_return_val_if_fail (screen->info != NULL, NULL); + -+ /* Product Code */ -+ info->product_code = edid[0x0b] << 8 | edid[0x0a]; ++ return screen->info->outputs; ++} + -+ /* Serial Number */ -+ info->serial_number = -+ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24; ++RWCrtc * ++rw_screen_get_crtc_by_id (RWScreen *screen, ++ guint32 id) ++{ ++ int i; + -+ /* Week and Year */ -+ is_model_year = FALSE; -+ switch (edid[0x10]) ++ g_return_val_if_fail (screen != NULL, NULL); ++ g_return_val_if_fail (screen->info != NULL, NULL); ++ ++ for (i = 0; screen->info->crtcs[i] != NULL; ++i) + { -+ case 0x00: -+ info->production_week = -1; -+ break; ++ if (screen->info->crtcs[i]->id == id) ++ return screen->info->crtcs[i]; ++ } + -+ case 0xff: -+ info->production_week = -1; -+ is_model_year = TRUE; -+ break; ++ return NULL; ++} + -+ default: -+ info->production_week = edid[0x10]; -+ break; -+ } ++RWOutput * ++rw_screen_get_output_by_id (RWScreen *screen, ++ guint32 id) ++{ ++ int i; + -+ if (is_model_year) -+ { -+ info->production_year = -1; -+ info->model_year = 1990 + edid[0x11]; -+ } -+ else ++ g_return_val_if_fail (screen != NULL, NULL); ++ g_return_val_if_fail (screen->info != NULL, NULL); ++ ++ for (i = 0; screen->info->outputs[i] != NULL; ++i) + { -+ info->production_year = 1990 + edid[0x11]; -+ info->model_year = -1; ++ if (screen->info->outputs[i]->id == id) ++ return screen->info->outputs[i]; + } + -+ return TRUE; ++ return NULL; +} + -+static int -+decode_edid_version (const uchar *edid, MonitorInfo *info) ++/* RWOutput */ ++static RWOutput * ++output_new (ScreenInfo *info, RROutput id) +{ -+ info->major_version = edid[0x12]; -+ info->minor_version = edid[0x13]; ++ RWOutput *output = g_new0 (RWOutput, 1); + -+ return TRUE; ++ output->id = id; ++ output->info = info; ++ ++ return output; +} + -+static int -+decode_display_parameters (const uchar *edid, MonitorInfo *info) ++static guint8 * ++get_property (Display *dpy, ++ RROutput output, ++ Atom atom, ++ int *len) +{ -+ /* Digital vs Analog */ -+ info->is_digital = get_bit (edid[0x14], 7); -+ -+ if (info->is_digital) ++ unsigned char *prop; ++ int actual_format; ++ unsigned long nitems, bytes_after; ++ Atom actual_type; ++ guint8 *result; ++ ++ XRRGetOutputProperty (dpy, output, atom, ++ 0, 100, False, False, ++ AnyPropertyType, ++ &actual_type, &actual_format, ++ &nitems, &bytes_after, &prop); ++ ++ if (actual_type == XA_INTEGER && actual_format == 8) + { -+ 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->digital.bits_per_primary = bit_depth[bits]; -+ -+ bits = get_bits (edid[0x14], 0, 3); -+ -+ if (bits <= 5) -+ info->digital.interface = interfaces[bits]; -+ else -+ info->digital.interface = UNDEFINED; ++ result = g_memdup (prop, nitems); ++ if (len) ++ *len = nitems; + } + 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 }, -+ }; ++ result = NULL; ++ } + -+ info->analog.video_signal_level = levels[bits][0]; -+ info->analog.sync_signal_level = levels[bits][1]; -+ info->analog.total_signal_level = levels[bits][2]; ++ XFree (prop); + -+ info->analog.blank_to_black = get_bit (edid[0x14], 4); ++ return result; ++} + -+ info->analog.separate_hv_sync = get_bit (edid[0x14], 3); -+ info->analog.composite_sync_on_h = get_bit (edid[0x14], 2); -+ info->analog.composite_sync_on_green = get_bit (edid[0x14], 1); ++static guint8 * ++read_edid_data (RWOutput *output) ++{ ++ Atom edid_atom = XInternAtom (DISPLAY (output), "EDID_DATA", FALSE); ++ guint8 *result; ++ int len; + -+ info->analog.serration_on_vsync = get_bit (edid[0x14], 0); ++ result = get_property (DISPLAY (output), ++ output->id, edid_atom, &len); ++ ++ if (result) ++ { ++ if (len == 128) ++ return result; ++ else ++ g_free (result); + } + -+ /* Screen Size / Aspect Ratio */ -+ if (edid[0x15] == 0 && edid[0x16] == 0) ++ return NULL; ++} ++ ++static void ++output_initialize (RWOutput *output, XRRScreenResources *res) ++{ ++ XRROutputInfo *info = XRRGetOutputInfo ( ++ DISPLAY (output), res, output->id); ++ GPtrArray *a; ++ int i; ++ ++ g_print ("Output %lx Timestamp: %u\n", output->id, (guint32)info->timestamp); ++ ++ if (!info || !output->info) + { -+ info->width_mm = -1; -+ info->height_mm = -1; -+ info->aspect_ratio = -1.0; ++ /* FIXME */ ++ return; + } -+ else if (edid[0x16] == 0) ++ ++ output->name = g_strdup (info->name); /* FIXME: what is nameLen used for? */ ++ output->current_crtc = crtc_by_id (output->info, info->crtc); ++ output->width_mm = info->mm_width; ++ output->height_mm = info->mm_height; ++ output->connected = (info->connection == RR_Connected); ++ ++ /* Possible crtcs */ ++ a = g_ptr_array_new (); ++ ++ for (i = 0; i < info->ncrtc; ++i) + { -+ info->width_mm = -1; -+ info->height_mm = -1; -+ info->aspect_ratio = 100.0 / (edid[0x15] + 99); ++ RWCrtc *crtc = crtc_by_id (output->info, info->crtcs[i]); ++ ++ if (crtc) ++ g_ptr_array_add (a, crtc); + } -+ else if (edid[0x15] == 0) ++ g_ptr_array_add (a, NULL); ++ output->possible_crtcs = (RWCrtc **)g_ptr_array_free (a, FALSE); ++ ++ /* Clones */ ++ a = g_ptr_array_new (); ++ for (i = 0; i < info->nclone; ++i) + { -+ info->width_mm = -1; -+ info->height_mm = -1; -+ info->aspect_ratio = 100.0 / (edid[0x16] + 99); -+ info->aspect_ratio = 1/info->aspect_ratio; /* portrait */ ++ RWOutput *rw_output = rw_output_by_id (output->info, info->clones[i]); ++ ++ if (rw_output) ++ g_ptr_array_add (a, rw_output); + } -+ else ++ g_ptr_array_add (a, NULL); ++ output->clones = (RWOutput **)g_ptr_array_free (a, FALSE); ++ ++ /* Modes */ ++ a = g_ptr_array_new (); ++ for (i = 0; i < info->nmode; ++i) + { -+ info->width_mm = 10 * edid[0x15]; -+ info->height_mm = 10 * edid[0x16]; ++ RWMode *mode = mode_by_id (output->info, info->modes[i]); ++ ++ if (mode) ++ g_ptr_array_add (a, mode); + } ++ g_ptr_array_add (a, NULL); ++ output->modes = (RWMode **)g_ptr_array_free (a, FALSE); + -+ /* Gamma */ -+ if (edid[0x17] == 0xFF) -+ info->gamma = -1.0; -+ else -+ info->gamma = (edid[0x17] + 100.0) / 100.0; ++ output->n_preferred = info->npreferred; ++ ++ /* Edid data */ ++ output->edid_data = read_edid_data (output); ++ ++ XRRFreeOutputInfo (info); ++} + -+ /* Features */ -+ info->standby = get_bit (edid[0x18], 7); -+ info->suspend = get_bit (edid[0x18], 6); -+ info->active_off = get_bit (edid[0x18], 5); ++static void ++output_free (RWOutput *output) ++{ ++ g_free (output); ++} + -+ if (info->is_digital) -+ { -+ info->digital.rgb444 = TRUE; -+ if (get_bit (edid[0x18], 3)) -+ info->digital.ycrcb444 = 1; -+ if (get_bit (edid[0x18], 4)) -+ info->digital.ycrcb422 = 1; -+ } -+ else ++guint32 ++rw_output_get_id (RWOutput *output) ++{ ++ g_assert(output != NULL); ++ ++ return output->id; ++} ++ ++const guint8 * ++rw_output_get_edid_data (RWOutput *output) ++{ ++ g_return_val_if_fail (output != NULL, NULL); ++ ++ return output->edid_data; ++} ++ ++RWOutput * ++rw_screen_get_output_by_name (RWScreen *screen, ++ const char *name) ++{ ++ int i; ++ ++ g_return_val_if_fail (screen != NULL, NULL); ++ g_return_val_if_fail (screen->info != NULL, NULL); ++ ++ for (i = 0; screen->info->outputs[i] != NULL; ++i) + { -+ int bits = get_bits (edid[0x18], 3, 4); -+ ColorType color_type[4] = -+ { -+ MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR -+ }; ++ RWOutput *output = screen->info->outputs[i]; + -+ info->analog.color_type = color_type[bits]; ++ if (strcmp (output->name, name) == 0) ++ return output; + } + -+ info->srgb_is_standard = get_bit (edid[0x18], 2); ++ return NULL; ++} + -+ /* In 1.3 this is called "has preferred timing" */ -+ info->preferred_timing_includes_native = get_bit (edid[0x18], 1); ++RWCrtc * ++rw_output_get_crtc (RWOutput *output) ++{ ++ g_return_val_if_fail (output != NULL, NULL); ++ ++ return output->current_crtc; ++} ++ ++RWMode * ++rw_output_get_current_mode (RWOutput *output) ++{ ++ RWCrtc *crtc; ++ ++ g_return_val_if_fail (output != NULL, NULL); + -+ /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */ -+ info->continuous_frequency = get_bit (edid[0x18], 0); -+ return TRUE; ++ if ((crtc = rw_output_get_crtc (output))) ++ return rw_crtc_get_current_mode (crtc); ++ ++ return NULL; +} + -+static double -+decode_fraction (int high, int low) ++void ++rw_output_get_position (RWOutput *output, ++ int *x, ++ int *y) +{ -+ double result = 0.0; -+ int i; ++ RWCrtc *crtc; + -+ high = (high << 2) | low; ++ g_return_if_fail (output != NULL); + -+ for (i = 0; i < 10; ++i) -+ result += get_bit (high, i) * pow (2, i - 10); ++ if ((crtc = rw_output_get_crtc (output))) ++ rw_crtc_get_position (crtc, x, y); ++} + -+ return result; ++const char * ++rw_output_get_name (RWOutput *output) ++{ ++ g_assert (output != NULL); ++ return output->name; +} + -+static int -+decode_color_characteristics (const uchar *edid, MonitorInfo *info) ++int ++rw_output_get_width_mm (RWOutput *output) +{ -+ 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)); ++ g_assert (output != NULL); ++ return output->width_mm; ++} + -+ return TRUE; ++int ++rw_output_get_height_mm (RWOutput *output) ++{ ++ g_assert (output != NULL); ++ return output->height_mm; +} + -+static int -+decode_established_timings (const uchar *edid, MonitorInfo *info) ++RWMode * ++rw_output_get_preferred_mode (RWOutput *output) +{ -+ 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 } -+ }, -+ }; ++ g_return_val_if_fail (output != NULL, NULL); ++ if (output->n_preferred) ++ return output->modes[0]; + -+ int i, j, idx; ++ return NULL; ++} + -+ idx = 0; -+ for (i = 0; i < 3; ++i) -+ { -+ for (j = 0; j < 8; ++j) -+ { -+ int byte = edid[0x23 + i]; ++RWMode ** ++rw_output_list_modes (RWOutput *output) ++{ ++ g_return_val_if_fail (output != NULL, NULL); ++ return output->modes; ++} + -+ if (get_bit (byte, j) && established[i][j].frequency != 0) -+ info->established[idx++] = established[i][j]; -+ } -+ } -+ return TRUE; ++gboolean ++rw_output_is_connected (RWOutput *output) ++{ ++ g_return_val_if_fail (output != NULL, FALSE); ++ return output->connected; +} + -+static int -+decode_standard_timings (const uchar *edid, MonitorInfo *info) ++gboolean ++rw_output_supports_mode (RWOutput *output, ++ RWMode *mode) +{ + 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; -+ } ++ g_return_val_if_fail (output != NULL, FALSE); ++ g_return_val_if_fail (mode != NULL, FALSE); + -+ info->standard[i].width = w; -+ info->standard[i].height = h; -+ info->standard[i].frequency = get_bits (second, 0, 5) + 60; -+ } ++ for (i = 0; output->modes[i] != NULL; ++i) ++ { ++ if (output->modes[i] == mode) ++ return TRUE; + } -+ -+ return TRUE; ++ ++ return FALSE; +} + -+static void -+decode_lf_string (const uchar *s, int n_chars, char *result) ++gboolean ++rw_output_can_clone (RWOutput *output, ++ RWOutput *clone) +{ + int i; -+ for (i = 0; i < n_chars; ++i) ++ ++ g_return_val_if_fail (output != NULL, FALSE); ++ g_return_val_if_fail (clone != NULL, FALSE); ++ ++ for (i = 0; output->clones[i] != NULL; ++i) + { -+ if (s[i] == 0x0a) -+ { -+ *result++ = '\0'; -+ break; -+ } -+ else if (s[i] == 0x00) -+ { -+ /* Convert embedded 0's to spaces */ -+ *result++ = ' '; -+ } -+ else -+ { -+ *result++ = s[i]; -+ } ++ if (output->clones[i] == clone) ++ return TRUE; + } ++ ++ return FALSE; +} + -+static void -+decode_display_descriptor (const uchar *desc, -+ MonitorInfo *info) ++/* RWCrtc */ ++typedef struct +{ -+ 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; -+ } -+} ++ Rotation xrot; ++ RWRotation rot; ++} RotationMap; ++static const RotationMap rotation_map[] = ++{ ++ { RR_Rotate_0, RW_ROTATION_0 }, ++ { RR_Rotate_90, RW_ROTATION_90 }, ++ { RR_Rotate_180, RW_ROTATION_180 }, ++ { RR_Rotate_270, RW_ROTATION_270 }, ++ { RR_Reflect_X, RW_REFLECT_X }, ++ { RR_Reflect_Y, RW_REFLECT_Y }, ++}; + -+static void -+decode_detailed_timing (const uchar *timing, -+ DetailedTiming *detailed) ++static RWRotation ++rw_rotation_from_xrotation (Rotation r) +{ -+ 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]; ++ int i; ++ RWRotation result = 0; + -+ detailed->interlaced = get_bit (timing[0x11], 7); ++ for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i) ++ { ++ if (r & rotation_map[i].xrot) ++ result |= rotation_map[i].rot; ++ } + -+ /* Stereo */ -+ bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0); -+ detailed->stereo = stereo[bits]; ++ return result; ++} + -+ /* Sync */ -+ bits = timing[0x11]; ++static Rotation ++xrotation_from_rotation (RWRotation r) ++{ ++ int i; ++ Rotation result = 0; + -+ detailed->digital_sync = get_bit (bits, 4); -+ if (detailed->digital_sync) ++ for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i) + { -+ detailed->digital.composite = !get_bit (bits, 3); ++ if (r & rotation_map[i].rot) ++ result |= rotation_map[i].xrot; ++ } + -+ if (detailed->digital.composite) -+ { -+ detailed->digital.serrations = get_bit (bits, 2); -+ detailed->digital.negative_vsync = FALSE; -+ } -+ else -+ { -+ detailed->digital.serrations = FALSE; -+ detailed->digital.negative_vsync = !get_bit (bits, 2); -+ } ++ return result; ++} + -+ detailed->digital.negative_hsync = !get_bit (bits, 0); ++gboolean ++rw_crtc_set_config (RWCrtc *crtc, ++ int x, ++ int y, ++ RWMode *mode, ++ RWRotation rotation, ++ RWOutput **outputs, ++ int n_outputs) ++{ ++ ScreenInfo *info; ++ GArray *output_ids; ++ int i; ++ ++ g_return_val_if_fail (crtc != NULL, FALSE); ++ g_return_val_if_fail (mode != NULL || outputs == NULL || n_outputs == 0, FALSE); ++ ++ info = crtc->info; ++ ++ if (mode) ++ { ++ g_return_val_if_fail (x + mode->width <= info->max_width, FALSE); ++ g_return_val_if_fail (y + mode->height <= info->max_height, FALSE); + } -+ else ++ ++ output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput)); ++ ++ if (outputs) + { -+ detailed->analog.bipolar = get_bit (bits, 3); -+ detailed->analog.serrations = get_bit (bits, 2); -+ detailed->analog.sync_on_green = !get_bit (bits, 1); ++ for (i = 0; i < n_outputs; ++i) ++ g_array_append_val (output_ids, outputs[i]->id); + } ++ ++ XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id, ++ CurrentTime, ++ x, y, ++ mode? mode->id : None, ++ xrotation_from_rotation (rotation), ++ (RROutput *)output_ids->data, ++ output_ids->len); ++ ++ g_array_free (output_ids, TRUE); ++ ++ return TRUE; +} + -+static int -+decode_descriptors (const uchar *edid, MonitorInfo *info) ++RWMode * ++rw_crtc_get_current_mode (RWCrtc *crtc) ++{ ++ g_return_val_if_fail (crtc != NULL, NULL); ++ ++ return crtc->current_mode; ++} ++ ++guint32 ++rw_crtc_get_id (RWCrtc *crtc) ++{ ++ g_return_val_if_fail (crtc != NULL, 0); ++ ++ return crtc->id; ++} ++ ++gboolean ++rw_crtc_can_drive_output (RWCrtc *crtc, ++ RWOutput *output) +{ + int i; -+ int timing_idx; -+ -+ timing_idx = 0; ++ ++ g_return_val_if_fail (crtc != NULL, FALSE); ++ g_return_val_if_fail (output != NULL, FALSE); + -+ for (i = 0; i < 4; ++i) ++ for (i = 0; crtc->possible_outputs[i] != NULL; ++i) + { -+ int index = 0x36 + i * 18; -+ -+ if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00) -+ { -+ decode_display_descriptor (edid + index, info); -+ } -+ else -+ { -+ decode_detailed_timing ( -+ edid + index, &(info->detailed_timings[timing_idx++])); -+ } ++ if (crtc->possible_outputs[i] == output) ++ return TRUE; + } + -+ info->n_detailed_timings = timing_idx; ++ return FALSE; ++} + -+ return TRUE; ++/* FIXME: merge with get_mode()? */ ++void ++rw_crtc_get_position (RWCrtc *crtc, ++ int *x, ++ int *y) ++{ ++ g_return_if_fail (crtc != NULL); ++ ++ if (x) ++ *x = crtc->x; ++ ++ if (y) ++ *y = crtc->y; +} + -+static void -+decode_check_sum (const uchar *edid, -+ MonitorInfo *info) ++/* FIXME: merge with get_mode()? */ ++RWRotation ++rw_crtc_get_current_rotation (RWCrtc *crtc) +{ -+ int i; -+ uchar check = 0; ++ g_assert(crtc != NULL); ++ return crtc->current_rotation; ++} + -+ for (i = 0; i < 128; ++i) -+ check += edid[i]; ++RWRotation ++rw_crtc_get_rotations (RWCrtc *crtc) ++{ ++ g_assert(crtc != NULL); ++ return crtc->rotations; ++} + -+ info->checksum = check; ++gboolean ++rw_crtc_supports_rotation (RWCrtc * crtc, ++ RWRotation rotation) ++{ ++ g_return_val_if_fail (crtc != NULL, FALSE); ++ return (crtc->rotations & rotation); +} + -+MonitorInfo * -+decode_edid (const uchar *edid) ++static RWCrtc * ++crtc_new (ScreenInfo *info, RROutput id) +{ -+ MonitorInfo *info = calloc (1, sizeof (MonitorInfo)); ++ RWCrtc *crtc = g_new0 (RWCrtc, 1); + -+ decode_check_sum (edid, info); ++ crtc->id = id; ++ crtc->info = info; + -+ if (!decode_header (edid)) -+ return NULL; -+ -+ if (!decode_vendor_and_product_identification (edid, info)) -+ return NULL; ++ return crtc; ++} + -+ if (!decode_edid_version (edid, info)) -+ return NULL; ++static void ++crtc_initialize (RWCrtc *crtc, XRRScreenResources *res) ++{ ++ XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id); ++ GPtrArray *a; ++ int i; ++ ++ g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp); ++ ++ if (!info) ++ { ++ /* FIXME: We need to reaquire the screen resources */ ++ return; ++ } ++ ++ /* RWMode */ ++ crtc->current_mode = mode_by_id (crtc->info, info->mode); ++ ++ crtc->x = info->x; ++ crtc->y = info->y; ++ ++ /* Current outputs */ ++ a = g_ptr_array_new (); ++ for (i = 0; i < info->noutput; ++i) ++ { ++ RWOutput *output = rw_output_by_id (crtc->info, info->outputs[i]); ++ ++ if (output) ++ g_ptr_array_add (a, output); ++ } ++ g_ptr_array_add (a, NULL); ++ crtc->current_outputs = (RWOutput **)g_ptr_array_free (a, FALSE); ++ ++ /* Possible outputs */ ++ a = g_ptr_array_new (); ++ for (i = 0; i < info->npossible; ++i) ++ { ++ RWOutput *output = rw_output_by_id (crtc->info, info->possible[i]); ++ ++ if (output) ++ g_ptr_array_add (a, output); ++ } ++ g_ptr_array_add (a, NULL); ++ crtc->possible_outputs = (RWOutput **)g_ptr_array_free (a, FALSE); + -+ if (!decode_display_parameters (edid, info)) -+ return NULL; ++ /* Rotations */ ++ crtc->current_rotation = rw_rotation_from_xrotation (info->rotation); ++ crtc->rotations = rw_rotation_from_xrotation (info->rotations); + -+ if (!decode_color_characteristics (edid, info)) -+ return NULL; ++ XRRFreeCrtcInfo (info); ++} + -+ if (!decode_established_timings (edid, info)) -+ return NULL; ++static void ++crtc_free (RWCrtc *crtc) ++{ ++ g_free (crtc->current_outputs); ++ g_free (crtc->possible_outputs); ++ g_free (crtc); ++} + -+ if (!decode_standard_timings (edid, info)) -+ return NULL; ++/* RWMode */ ++static RWMode * ++mode_new (ScreenInfo *info, RRMode id) ++{ ++ RWMode *mode = g_new0 (RWMode, 1); + -+ if (!decode_descriptors (edid, info)) -+ return NULL; ++ mode->id = id; ++ mode->info = info; + -+ return info; ++ return mode; +} -diff -up gnome-desktop-2.22.1/libgnome-desktop/Makefile.am.add-randr-12 gnome-desktop-2.22.1/libgnome-desktop/Makefile.am ---- gnome-desktop-2.22.1/libgnome-desktop/Makefile.am.add-randr-12 2008-04-07 17:18:13.000000000 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/Makefile.am 2008-04-08 23:39:06.000000000 -0400 -@@ -20,7 +20,12 @@ libgnome_desktop_2_la_SOURCES = \ - gnome-desktop-item.c \ - gnome-ditem-edit.c \ - gnome-hint.c \ -- gnome-bg.c -+ gnome-bg.c \ -+ display-name.c \ -+ randrwrap.c \ -+ monitor-db.c \ -+ edid-parse.c \ -+ edid.h - - libgnome_desktop_2_la_LIBADD = \ - $(XLIB_LIBS) \ -diff -up /dev/null gnome-desktop-2.22.1/libgnome-desktop/edid.h ---- /dev/null 2008-03-16 00:14:46.954006998 -0400 -+++ gnome-desktop-2.22.1/libgnome-desktop/edid.h 2008-04-08 23:39:06.000000000 -0400 -@@ -0,0 +1,170 @@ -+typedef unsigned char uchar; -+typedef struct MonitorInfo MonitorInfo; -+typedef struct Timing Timing; -+typedef struct DetailedTiming DetailedTiming; + -+typedef enum ++guint32 ++rw_mode_get_id (RWMode *mode) +{ -+ UNDEFINED, -+ DVI, -+ HDMI_A, -+ HDMI_B, -+ MDDI, -+ DISPLAY_PORT -+} Interface; ++ g_return_val_if_fail (mode != NULL, 0); ++ return mode->id; ++} + -+typedef enum ++guint ++rw_mode_get_width (RWMode *mode) +{ -+ UNDEFINED_COLOR, -+ MONOCHROME, -+ RGB, -+ OTHER_COLOR -+} ColorType; ++ g_return_val_if_fail (mode != NULL, 0); ++ return mode->width; ++} + -+typedef enum ++int ++rw_mode_get_freq (RWMode *mode) +{ -+ NO_STEREO, -+ FIELD_RIGHT, -+ FIELD_LEFT, -+ TWO_WAY_RIGHT_ON_EVEN, -+ TWO_WAY_LEFT_ON_EVEN, -+ FOUR_WAY_INTERLEAVED, -+ SIDE_BY_SIDE -+} StereoType; ++ g_return_val_if_fail (mode != NULL, 0); ++ return (mode->freq) / 1000; ++} + -+struct Timing ++guint ++rw_mode_get_height (RWMode *mode) +{ -+ int width; -+ int height; -+ int frequency; -+}; ++ g_return_val_if_fail (mode != NULL, 0); ++ return mode->height; ++} + -+struct DisplayDescriptor ++static void ++mode_initialize (RWMode *mode, XRRModeInfo *info) +{ -+}; ++ g_assert (mode != NULL); ++ g_assert (info != NULL); + -+struct DetailedTiming ++ mode->name = g_strdup (info->name); ++ mode->width = info->width; ++ mode->height = info->height; ++ mode->freq = ((info->dotClock / (double)info->hTotal) / info->vTotal + 0.5) * 1000; ++} ++ ++static void ++mode_free (RWMode *mode) +{ -+ 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; ++ g_free (mode->name); ++ g_free (mode); ++} + -+ 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; -+ }; -+}; ++#ifdef INCLUDE_MAIN ++static void ++on_screen_changed (RWScreen *screen, gpointer data) ++{ ++ g_print ("Changed\n"); ++} + -+struct MonitorInfo ++static gboolean ++do_refresh (gpointer data) +{ -+ 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 */ ++ RWScreen *screen = data; + -+ int major_version; -+ int minor_version; ++ rw_screen_refresh (screen); + -+ int is_digital; ++ return TRUE; ++} ++ ++int ++main (int argc, char **argv) ++{ ++ int i; + -+ union ++ gtk_init (&argc, &argv); ++ ++ RWScreen *screen = rw_screen_new (gdk_screen_get_default(), ++ on_screen_changed, ++ NULL); ++ ++ for (i = 0; screen->info->crtcs[i]; ++i) + { -+ struct ++ RWCrtc *crtc = screen->info->crtcs[i]; ++ ++ if (crtc->current_mode) + { -+ int bits_per_primary; -+ Interface interface; -+ int rgb444; -+ int ycrcb444; -+ int ycrcb422; -+ } digital; -+ -+ struct ++ g_print ("CRTC %p: (%d %d %d %d)\n", ++ crtc, crtc->x, crtc->y, ++ crtc->current_mode->width, crtc->current_mode->height); ++ } ++ else + { -+ 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; -+ }; -+ -+ 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]; ++ g_print ("CRTC %p: turned off\n", crtc); ++ } ++ } + -+ 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 */ -+}; ++ for (i = 0; screen->info->outputs[i]; ++i) ++ { ++ RWOutput *output = screen->info->outputs[i]; ++ ++ g_print ("Output %s currently", output->name); ++ ++ if (!output->current_crtc) ++ g_print (" turned off\n"); ++ else ++ g_print (" driven by CRTC %p\n", output->current_crtc); ++ } + -+MonitorInfo *decode_edid (const uchar *data); -+char * make_display_name (const char *output_name, -+ const MonitorInfo *info); -diff -up gnome-desktop-2.22.1/configure.in.add-randr-12 gnome-desktop-2.22.1/configure.in ---- gnome-desktop-2.22.1/configure.in.add-randr-12 2008-04-07 17:27:00.000000000 -0400 -+++ gnome-desktop-2.22.1/configure.in 2008-04-08 23:39:06.000000000 -0400 -@@ -51,10 +51,10 @@ AC_SUBST(GNOME_MICRO) - AC_SUBST(GNOME_DISTRIBUTOR) - AC_SUBST(GNOME_DATE) - --GNOME_COMMON_INIT --GNOME_DEBUG_CHECK --GNOME_COMPILE_WARNINGS([maximum]) --GNOME_MAINTAINER_MODE_DEFINES -+#GNOME_COMMON_INIT -+#GNOME_DEBUG_CHECK -+#GNOME_COMPILE_WARNINGS([maximum]) -+#GNOME_MAINTAINER_MODE_DEFINES - - # As a special favour for vuntz, support --disable-deprecations - ++ g_timeout_add (500, do_refresh, screen); ++ ++ gtk_main (); ++ ++ return 0; ++} ++#endif diff --git a/gnome-desktop.spec b/gnome-desktop.spec index 4630c2f..af65a76 100644 --- a/gnome-desktop.spec +++ b/gnome-desktop.spec @@ -12,7 +12,7 @@ Summary: Package containing code shared among gnome-panel, gnome-session, nautilus, etc Name: gnome-desktop Version: 2.22.1 -Release: 2%{?dist} +Release: 3%{?dist} URL: http://www.gnome.org Source0: http://download.gnome.org/sources/gnome-desktop/2.22/%{name}-%{version}.tar.bz2 License: GPLv2+ and LGPLv2+ @@ -126,6 +126,9 @@ rm -rf $RPM_BUILD_ROOT %doc %{_datadir}/gtk-doc/html/gnome-desktop/ %changelog +* Fri Apr 25 2008 Soren Sandmann - 2.22.1-3 +- Integrate a number of fixes from other distributions + * Tue Apr 8 2008 Soren Sandmann - 2.22.1-2 - Fix bug where the dpi of the screen got miscalculated