diff --git a/gnome-desktop-2.23.4.tar.bz2 b/gnome-desktop-2.23.4.tar.bz2 deleted file mode 100644 index 597348a..0000000 --- a/gnome-desktop-2.23.4.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ca079e878affd9cae0490c218d52f60bcb0681172f646c76cd2399802a545cb3 -size 1425318 diff --git a/gnome-desktop-2.23.6.tar.bz2 b/gnome-desktop-2.23.6.tar.bz2 new file mode 100644 index 0000000..02732d0 --- /dev/null +++ b/gnome-desktop-2.23.6.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c785e6769255ae2d4aa3fb7ca76ea75c8833370ec118880a119b6688638f71d9 +size 1510062 diff --git a/gnome-desktop-fate300461-desktop-gettext.patch b/gnome-desktop-fate300461-desktop-gettext.patch new file mode 100644 index 0000000..7855c4d --- /dev/null +++ b/gnome-desktop-fate300461-desktop-gettext.patch @@ -0,0 +1,134 @@ +Add support of gettext for desktop entry files. + +We only support this for the following keys: Name, GenericName, Comment. We +don't support all keys because it can create issues for the Icon key (which is +localizable -- which can result in a broken icon). + +Translations that are present in the desktop entry take precedence over +translations via gettext. If we don't do this, then user modifications won't +appear since they will have lower precedence. + +Index: gnome-desktop-2.23.4/libgnome-desktop/gnome-desktop-item.c +=================================================================== +--- gnome-desktop-2.23.4.orig/libgnome-desktop/gnome-desktop-item.c ++++ gnome-desktop-2.23.4/libgnome-desktop/gnome-desktop-item.c +@@ -84,6 +84,7 @@ struct _GnomeDesktopItem { + GHashTable *main_hash; + + char *location; ++ const char *gettext_domain; + + time_t mtime; + +@@ -139,6 +140,8 @@ static GnomeDesktopItem *gnome_desktop_i + + static void update_recently_used_apps (const GnomeDesktopItem *item); + ++static const char *lookup (const GnomeDesktopItem *item, const char *key); ++ + static int + readbuf_getc (ReadBuf *rb) + { +@@ -399,6 +402,7 @@ gnome_desktop_item_new (void) + "1.0"); + + retval->launch_time = 0; ++ retval->gettext_domain = NULL; + + return retval; + } +@@ -477,6 +481,8 @@ gnome_desktop_item_copy (const GnomeDesk + copy_string_hash, + retval->main_hash); + ++ retval->gettext_domain = lookup (retval, GNOME_DESKTOP_ITEM_GETTEXT_DOMAIN); ++ + return retval; + } + +@@ -924,6 +930,9 @@ gnome_desktop_item_unref (GnomeDesktopIt + g_free (item->location); + item->location = NULL; + ++ /* no need to free it, it's a const key */ ++ item->gettext_domain = NULL; ++ + g_free (item); + } + +@@ -999,16 +1008,51 @@ lookup (const GnomeDesktopItem *item, co + static const char * + lookup_locale (const GnomeDesktopItem *item, const char *key, const char *locale) + { ++ const char *ret; ++ ++ ret = NULL; ++ + if (locale == NULL || + strcmp (locale, "C") == 0) { +- return lookup (item, key); ++ ret = lookup (item, key); + } else { +- const char *ret; + char *full = g_strdup_printf ("%s[%s]", key, locale); + ret = lookup (item, full); + g_free (full); +- return ret; + } ++ ++ /* we're only interested in gettext translation if we don't have a ++ * translation in the .desktop file itself and if the key is one of the ++ * keys we know we want to translate: Name, GenericName, Comment. ++ * Blindly doing this for all keys can give strange result for the ++ * icons, since the Icon is a locale string in the spec, eg. */ ++ if (!ret && item->gettext_domain && ++ (strcmp (key, GNOME_DESKTOP_ITEM_NAME) == 0 || ++ strcmp (key, GNOME_DESKTOP_ITEM_GENERIC_NAME) == 0 || ++ strcmp (key, GNOME_DESKTOP_ITEM_COMMENT) == 0)) { ++ const char *msg_locale = setlocale (LC_MESSAGES, NULL); ++ ++ /* only get translation in the mo file if the requested locale ++ * is the LC_MESSAGES one. Ideally, we should do more and ++ * change LC_MESSAGES to use the requested locale, but there's ++ * no guarantee it's installed on the system and it might have ++ * some side-effects. Since this is a corner case, let's ignore ++ * it. */ ++ if (msg_locale && locale && ++ strcmp (msg_locale, locale) == 0) { ++ const char *value = lookup (item, key); ++ if (value != NULL && value[0] != '\0') { ++ ret = dgettext (item->gettext_domain, value); ++ /* don't accept no translation, since we might ++ * have something better later, with another ++ * locale */ ++ if (ret == value) ++ ret = NULL; ++ } ++ } ++ } ++ ++ return ret; + } + + static const char * +@@ -4039,6 +4083,8 @@ ditem_load (ReadBuf *rb, + + readbuf_close (rb); + ++ item->gettext_domain = lookup (item, GNOME_DESKTOP_ITEM_GETTEXT_DOMAIN); ++ + return item; + } + +Index: gnome-desktop-2.23.4/libgnome-desktop/libgnome/gnome-desktop-item.h +=================================================================== +--- gnome-desktop-2.23.4.orig/libgnome-desktop/libgnome/gnome-desktop-item.h ++++ gnome-desktop-2.23.4/libgnome-desktop/libgnome/gnome-desktop-item.h +@@ -98,6 +98,7 @@ typedef struct _GnomeDesktopItem GnomeDe + #define GNOME_DESKTOP_ITEM_DOC_PATH "X-GNOME-DocPath" /* string */ + #define GNOME_DESKTOP_ITEM_SUBSTITUTEUID "X-KDE-SubstituteUID" /*boolean*/ + #define GNOME_DESKTOP_ITEM_ROOT_ONLY "X-KDE-RootOnly" /*boolean*/ ++#define GNOME_DESKTOP_ITEM_GETTEXT_DOMAIN "X-SUSE-Gettext-Domain" /* string */ + /* The vfolder proposal */ + #define GNOME_DESKTOP_ITEM_CATEGORIES "Categories" /* string */ + #define GNOME_DESKTOP_ITEM_ONLY_SHOW_IN "OnlyShowIn" /* string */ diff --git a/gnome-desktop-randr-1.2.diff b/gnome-desktop-randr-1.2.diff deleted file mode 100644 index 226c709..0000000 --- a/gnome-desktop-randr-1.2.diff +++ /dev/null @@ -1,3907 +0,0 @@ -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. -+ */ -+ -+/* Author: Soren Sandmann */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "edid.h" -+ -+typedef struct Vendor Vendor; -+struct Vendor -+{ -+ const char vendor_id[4]; -+ const char vendor_name[28]; -+}; -+ -+/* This list of vendor codes derived from lshw -+ * -+ * http://ezix.org/project/wiki/HardwareLiSter -+ */ -+static const struct Vendor vendors[] = -+{ -+ { "AIC", "AG Neovo" }, -+ { "ACR", "Acer" }, -+ { "DEL", "DELL" }, -+ { "SAM", "SAMSUNG" }, -+ { "SNY", "SONY" }, -+ { "SEC", "Epson" }, -+ { "WAC", "Wacom" }, -+ { "NEC", "NEC" }, -+ { "CMO", "CMO" }, /* Chi Mei */ -+ { "BNQ", "BenQ" }, -+ -+ { "ABP", "Advansys" }, -+ { "ACC", "Accton" }, -+ { "ACE", "Accton" }, -+ { "ADP", "Adaptec" }, -+ { "ADV", "AMD" }, -+ { "AIR", "AIR" }, -+ { "AMI", "AMI" }, -+ { "ASU", "ASUS" }, -+ { "ATI", "ATI" }, -+ { "ATK", "Allied Telesyn" }, -+ { "AZT", "Aztech" }, -+ { "BAN", "Banya" }, -+ { "BRI", "Boca Research" }, -+ { "BUS", "Buslogic" }, -+ { "CCI", "Cache Computers Inc." }, -+ { "CHA", "Chase" }, -+ { "CMD", "CMD Technology, Inc." }, -+ { "COG", "Cogent" }, -+ { "CPQ", "Compaq" }, -+ { "CRS", "Crescendo" }, -+ { "CSC", "Crystal" }, -+ { "CSI", "CSI" }, -+ { "CTL", "Creative Labs" }, -+ { "DBI", "Digi" }, -+ { "DEC", "Digital Equipment" }, -+ { "DBK", "Databook" }, -+ { "EGL", "Eagle Technology" }, -+ { "ELS", "ELSA" }, -+ { "ESS", "ESS" }, -+ { "FAR", "Farallon" }, -+ { "FDC", "Future Domain" }, -+ { "HWP", "Hewlett-Packard" }, -+ { "IBM", "IBM" }, -+ { "INT", "Intel" }, -+ { "ISA", "Iomega" }, -+ { "MDG", "Madge" }, -+ { "MDY", "Microdyne" }, -+ { "MET", "Metheus" }, -+ { "MIC", "Micronics" }, -+ { "MLX", "Mylex" }, -+ { "NVL", "Novell" }, -+ { "OLC", "Olicom" }, -+ { "PRO", "Proteon" }, -+ { "RII", "Racal" }, -+ { "RTL", "Realtek" }, -+ { "SCM", "SCM" }, -+ { "SKD", "SysKonnect" }, -+ { "SGI", "SGI" }, -+ { "SMC", "SMC" }, -+ { "SNI", "Siemens Nixdorf" }, -+ { "STL", "Stallion Technologies" }, -+ { "SUN", "Sun" }, -+ { "SUP", "SupraExpress" }, -+ { "SVE", "SVEC" }, -+ { "TCC", "Thomas-Conrad" }, -+ { "TCI", "Tulip" }, -+ { "TCM", "3Com" }, -+ { "TCO", "Thomas-Conrad" }, -+ { "TEC", "Tecmar" }, -+ { "TRU", "Truevision" }, -+ { "TOS", "Toshiba" }, -+ { "TYN", "Tyan" }, -+ { "UBI", "Ungermann-Bass" }, -+ { "USC", "UltraStor" }, -+ { "VDM", "Vadem" }, -+ { "VMI", "Vermont" }, -+ { "WDC", "Western Digital" }, -+ { "ZDS", "Zeos" }, -+ -+ /* From http://faydoc.tripod.com/structures/01/0136.htm */ -+ { "ACT", "Targa" }, -+ { "ADI", "ADI" }, -+ { "AOC", "AOC Intl" }, -+ { "API", "Acer America" }, -+ { "APP", "Apple Computer" }, -+ { "ART", "ArtMedia" }, -+ { "AST", "AST Research" }, -+ { "CPL", "Compal" }, -+ { "CTX", "Chuntex Electronic Co." }, -+ { "DPC", "Delta Electronics" }, -+ { "DWE", "Daewoo" }, -+ { "ECS", "ELITEGROUP" }, -+ { "EIZ", "EIZO" }, -+ { "FCM", "Funai" }, -+ { "GSM", "LG Electronics" }, -+ { "GWY", "Gateway 2000" }, -+ { "HEI", "Hyundai" }, -+ { "HIT", "Hitachi" }, -+ { "HSL", "Hansol" }, -+ { "HTC", "Hitachi" }, -+ { "ICL", "Fujitsu ICL" }, -+ { "IVM", "Idek Iiyama" }, -+ { "KFC", "KFC Computek" }, -+ { "LKM", "ADLAS" }, -+ { "LNK", "LINK Tech" }, -+ { "LTN", "Lite-On" }, -+ { "MAG", "MAG InnoVision" }, -+ { "MAX", "Maxdata" }, -+ { "MEI", "Panasonic" }, -+ { "MEL", "Mitsubishi" }, -+ { "MIR", "miro" }, -+ { "MTC", "MITAC" }, -+ { "NAN", "NANAO" }, -+ { "NEC", "NEC Tech" }, -+ { "NOK", "Nokia" }, -+ { "OQI", "OPTIQUEST" }, -+ { "PBN", "Packard Bell" }, -+ { "PGS", "Princeton" }, -+ { "PHL", "Philips" }, -+ { "REL", "Relisys" }, -+ { "SDI", "Samtron" }, -+ { "SMI", "Smile" }, -+ { "SPT", "Sceptre" }, -+ { "SRC", "Shamrock Technology" }, -+ { "STP", "Sceptre" }, -+ { "TAT", "Tatung" }, -+ { "TRL", "Royal Information Company" }, -+ { "TSB", "Toshiba, Inc." }, -+ { "UNM", "Unisys" }, -+ { "VSC", "ViewSonic" }, -+ { "WTC", "Wen Tech" }, -+ { "ZCM", "Zenith Data Systems" }, -+ -+ { "???", "Unknown" }, -+}; -+ -+static const char * -+find_vendor (const char *code) -+{ -+ int i; -+ -+ for (i = 0; i < sizeof (vendors) / sizeof (vendors[0]); ++i) -+ { -+ const Vendor *v = &(vendors[i]); -+ -+ if (strcmp (v->vendor_id, code) == 0) -+ return v->vendor_name; -+ } -+ -+ return code; -+}; -+ -+char * -+make_display_name (const char *output_name, -+ const MonitorInfo *info) -+{ -+ const char *vendor; -+ int width_mm, height_mm, inches; -+ -+ 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"; -+ } -+ -+ if (info && info->width_mm != -1 && info->height_mm) -+ { -+ width_mm = info->width_mm; -+ height_mm = info->height_mm; -+ } -+ else if (info && info->n_detailed_timings) -+ { -+ width_mm = info->detailed_timings[0].width_mm; -+ height_mm = info->detailed_timings[0].height_mm; -+ } -+ else -+ { -+ width_mm = -1; -+ height_mm = -1; -+ } -+ -+ if (width_mm != -1 && height_mm != -1) -+ { -+ double d = sqrt (width_mm * width_mm + height_mm * height_mm); -+ -+ inches = (int)(d / 25.4 + 0.5); -+ } -+ else -+ { -+ inches = -1; -+ } -+ -+ if (inches > 0) -+ return g_strdup_printf ("%s %d\"", vendor, inches); -+ else -+ return g_strdup_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. -+ */ -+ -+/* Author: Soren Sandmann */ -+ -+#include "edid.h" -+#include -+#include -+#include -+ -+#define TRUE 1 -+#define FALSE 0 -+ -+static int -+get_bit (int in, int bit) -+{ -+ return (in & (1 << bit)) >> bit; -+} -+ -+static int -+get_bits (int in, int begin, int end) -+{ -+ int mask = (1 << (end - begin + 1)) - 1; -+ -+ return (in >> begin) & mask; -+} -+ -+static int -+decode_header (const uchar *edid) -+{ -+ if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0) -+ return TRUE; -+ return FALSE; -+} -+ -+static int -+decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info) -+{ -+ int is_model_year; -+ -+ /* Manufacturer Code */ -+ info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6); -+ info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3; -+ info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7); -+ info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4); -+ info->manufacturer_code[3] = '\0'; -+ -+ info->manufacturer_code[0] += 'A' - 1; -+ info->manufacturer_code[1] += 'A' - 1; -+ info->manufacturer_code[2] += 'A' - 1; -+ -+ /* Product Code */ -+ info->product_code = edid[0x0b] << 8 | edid[0x0a]; -+ -+ /* Serial Number */ -+ info->serial_number = -+ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24; -+ -+ /* Week and Year */ -+ is_model_year = FALSE; -+ switch (edid[0x10]) -+ { -+ case 0x00: -+ info->production_week = -1; -+ break; -+ -+ case 0xff: -+ info->production_week = -1; -+ is_model_year = TRUE; -+ break; -+ -+ default: -+ info->production_week = edid[0x10]; -+ break; -+ } -+ -+ if (is_model_year) -+ { -+ info->production_year = -1; -+ info->model_year = 1990 + edid[0x11]; -+ } -+ else -+ { -+ info->production_year = 1990 + edid[0x11]; -+ info->model_year = -1; -+ } -+ -+ return TRUE; -+} -+ -+static int -+decode_edid_version (const uchar *edid, MonitorInfo *info) -+{ -+ info->major_version = edid[0x12]; -+ info->minor_version = edid[0x13]; -+ -+ return TRUE; -+} -+ -+static int -+decode_display_parameters (const uchar *edid, MonitorInfo *info) -+{ -+ /* Digital vs Analog */ -+ info->is_digital = get_bit (edid[0x14], 7); -+ -+ if (info->is_digital) -+ { -+ int bits; -+ -+ static const int bit_depth[8] = -+ { -+ -1, 6, 8, 10, 12, 14, 16, -1 -+ }; -+ -+ static const Interface interfaces[6] = -+ { -+ UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT -+ }; -+ -+ bits = get_bits (edid[0x14], 4, 6); -+ info->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; -+ } -+ else -+ { -+ int bits = get_bits (edid[0x14], 5, 6); -+ -+ static const double levels[][3] = -+ { -+ { 0.7, 0.3, 1.0 }, -+ { 0.714, 0.286, 1.0 }, -+ { 1.0, 0.4, 1.4 }, -+ { 0.7, 0.0, 0.7 }, -+ }; -+ -+ info->analog.video_signal_level = levels[bits][0]; -+ info->analog.sync_signal_level = levels[bits][1]; -+ info->analog.total_signal_level = levels[bits][2]; -+ -+ info->analog.blank_to_black = get_bit (edid[0x14], 4); -+ -+ 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); -+ -+ info->analog.serration_on_vsync = get_bit (edid[0x14], 0); -+ } -+ -+ /* Screen Size / Aspect Ratio */ -+ if (edid[0x15] == 0 && edid[0x16] == 0) -+ { -+ info->width_mm = -1; -+ info->height_mm = -1; -+ info->aspect_ratio = -1.0; -+ } -+ else if (edid[0x16] == 0) -+ { -+ info->width_mm = -1; -+ info->height_mm = -1; -+ info->aspect_ratio = 100.0 / (edid[0x15] + 99); -+ } -+ else if (edid[0x15] == 0) -+ { -+ info->width_mm = -1; -+ info->height_mm = -1; -+ info->aspect_ratio = 100.0 / (edid[0x16] + 99); -+ info->aspect_ratio = 1/info->aspect_ratio; /* portrait */ -+ } -+ else -+ { -+ info->width_mm = 10 * edid[0x15]; -+ info->height_mm = 10 * edid[0x16]; -+ } -+ -+ /* Gamma */ -+ if (edid[0x17] == 0xFF) -+ info->gamma = -1.0; -+ else -+ info->gamma = (edid[0x17] + 100.0) / 100.0; -+ -+ /* Features */ -+ info->standby = get_bit (edid[0x18], 7); -+ info->suspend = get_bit (edid[0x18], 6); -+ info->active_off = get_bit (edid[0x18], 5); -+ -+ if (info->is_digital) -+ { -+ info->digital.rgb444 = TRUE; -+ if (get_bit (edid[0x18], 3)) -+ info->digital.ycrcb444 = 1; -+ if (get_bit (edid[0x18], 4)) -+ info->digital.ycrcb422 = 1; -+ } -+ else -+ { -+ 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]; -+ } -+ -+ info->srgb_is_standard = get_bit (edid[0x18], 2); -+ -+ /* In 1.3 this is called "has preferred timing" */ -+ info->preferred_timing_includes_native = get_bit (edid[0x18], 1); -+ -+ /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */ -+ info->continuous_frequency = get_bit (edid[0x18], 0); -+ return TRUE; -+} -+ -+static double -+decode_fraction (int high, int low) -+{ -+ double result = 0.0; -+ int i; -+ -+ high = (high << 2) | low; -+ -+ for (i = 0; i < 10; ++i) -+ result += get_bit (high, i) * pow (2, i - 10); -+ -+ return result; -+} -+ -+static int -+decode_color_characteristics (const uchar *edid, MonitorInfo *info) -+{ -+ info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7)); -+ info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4)); -+ info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3)); -+ info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1)); -+ info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7)); -+ info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5)); -+ info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3)); -+ info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1)); -+ -+ return TRUE; -+} -+ -+static int -+decode_established_timings (const uchar *edid, MonitorInfo *info) -+{ -+ static const Timing established[][8] = -+ { -+ { -+ { 800, 600, 60 }, -+ { 800, 600, 56 }, -+ { 640, 480, 75 }, -+ { 640, 480, 72 }, -+ { 640, 480, 67 }, -+ { 640, 480, 60 }, -+ { 720, 400, 88 }, -+ { 720, 400, 70 } -+ }, -+ { -+ { 1280, 1024, 75 }, -+ { 1024, 768, 75 }, -+ { 1024, 768, 70 }, -+ { 1024, 768, 60 }, -+ { 1024, 768, 87 }, -+ { 832, 624, 75 }, -+ { 800, 600, 75 }, -+ { 800, 600, 72 } -+ }, -+ { -+ { 0, 0, 0 }, -+ { 0, 0, 0 }, -+ { 0, 0, 0 }, -+ { 0, 0, 0 }, -+ { 0, 0, 0 }, -+ { 0, 0, 0 }, -+ { 0, 0, 0 }, -+ { 1152, 870, 75 } -+ }, -+ }; -+ -+ int i, j, idx; -+ -+ idx = 0; -+ for (i = 0; i < 3; ++i) -+ { -+ for (j = 0; j < 8; ++j) -+ { -+ int byte = edid[0x23 + i]; -+ -+ if (get_bit (byte, j) && established[i][j].frequency != 0) -+ info->established[idx++] = established[i][j]; -+ } -+ } -+ return TRUE; -+} -+ -+static int -+decode_standard_timings (const uchar *edid, MonitorInfo *info) -+{ -+ int i; -+ -+ for (i = 0; i < 8; i++) -+ { -+ int first = edid[0x26 + 2 * i]; -+ int second = edid[0x27 + 2 * i]; -+ -+ if (first != 0x01 && second != 0x01) -+ { -+ int w = 8 * (first + 31); -+ int h; -+ -+ switch (get_bits (second, 6, 7)) -+ { -+ case 0x00: h = (w / 16) * 10; break; -+ case 0x01: h = (w / 4) * 3; break; -+ case 0x02: h = (w / 5) * 4; break; -+ case 0x03: h = (w / 16) * 9; break; -+ } -+ -+ info->standard[i].width = w; -+ info->standard[i].height = h; -+ info->standard[i].frequency = get_bits (second, 0, 5) + 60; -+ } -+ } -+ -+ return TRUE; -+} -+ -+static void -+decode_lf_string (const uchar *s, int n_chars, char *result) -+{ -+ int i; -+ for (i = 0; i < n_chars; ++i) -+ { -+ if (s[i] == 0x0a) -+ { -+ *result++ = '\0'; -+ break; -+ } -+ else if (s[i] == 0x00) -+ { -+ /* Convert embedded 0's to spaces */ -+ *result++ = ' '; -+ } -+ else -+ { -+ *result++ = s[i]; -+ } -+ } -+} -+ -+static void -+decode_display_descriptor (const uchar *desc, -+ MonitorInfo *info) -+{ -+ switch (desc[0x03]) -+ { -+ case 0xFC: -+ decode_lf_string (desc + 5, 13, info->dsc_product_name); -+ break; -+ case 0xFF: -+ decode_lf_string (desc + 5, 13, info->dsc_serial_number); -+ break; -+ case 0xFE: -+ decode_lf_string (desc + 5, 13, info->dsc_string); -+ break; -+ case 0xFD: -+ /* Range Limits */ -+ break; -+ case 0xFB: -+ /* Color Point */ -+ break; -+ case 0xFA: -+ /* Timing Identifications */ -+ break; -+ case 0xF9: -+ /* Color Management */ -+ break; -+ case 0xF8: -+ /* Timing Codes */ -+ break; -+ case 0xF7: -+ /* Established Timings */ -+ break; -+ case 0x10: -+ break; -+ } -+} -+ -+static void -+decode_detailed_timing (const uchar *timing, -+ DetailedTiming *detailed) -+{ -+ int bits; -+ StereoType stereo[] = -+ { -+ NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT, -+ TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN, -+ FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE -+ }; -+ -+ detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000; -+ detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4); -+ detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8); -+ detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4); -+ detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8); -+ detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8; -+ detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8; -+ detailed->v_front_porch = -+ get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4; -+ detailed->v_sync = -+ get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4; -+ detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8; -+ detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8; -+ detailed->right_border = timing[0x0f]; -+ detailed->top_border = timing[0x10]; -+ -+ detailed->interlaced = get_bit (timing[0x11], 7); -+ -+ /* Stereo */ -+ bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0); -+ detailed->stereo = stereo[bits]; -+ -+ /* Sync */ -+ bits = timing[0x11]; -+ -+ detailed->digital_sync = get_bit (bits, 4); -+ if (detailed->digital_sync) -+ { -+ detailed->digital.composite = !get_bit (bits, 3); -+ -+ 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); -+ } -+ -+ 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); -+ } -+} -+ -+static int -+decode_descriptors (const uchar *edid, MonitorInfo *info) -+{ -+ int i; -+ int timing_idx; -+ -+ timing_idx = 0; -+ -+ for (i = 0; i < 4; ++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++])); -+ } -+ } -+ -+ info->n_detailed_timings = timing_idx; -+ -+ return TRUE; -+} -+ -+static void -+decode_check_sum (const uchar *edid, -+ MonitorInfo *info) -+{ -+ int i; -+ uchar check = 0; -+ -+ for (i = 0; i < 128; ++i) -+ check += edid[i]; -+ -+ info->checksum = check; -+} -+ -+MonitorInfo * -+decode_edid (const uchar *edid) -+{ -+ MonitorInfo *info = calloc (1, sizeof (MonitorInfo)); -+ -+ 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..3a6cbf2 ---- /dev/null -+++ b/libgnome-desktop/edid.h -@@ -0,0 +1,199 @@ -+/* edid.h -+ * -+ * Copyright 2007, 2008, Red Hat, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome Library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: Soren Sandmann -+ */ -+ -+#ifndef EDID_H -+#define EDID_H -+ -+typedef unsigned char uchar; -+typedef struct MonitorInfo MonitorInfo; -+typedef struct Timing Timing; -+typedef struct DetailedTiming DetailedTiming; -+ -+typedef enum -+{ -+ UNDEFINED, -+ DVI, -+ HDMI_A, -+ HDMI_B, -+ MDDI, -+ DISPLAY_PORT -+} Interface; -+ -+typedef enum -+{ -+ UNDEFINED_COLOR, -+ MONOCHROME, -+ RGB, -+ OTHER_COLOR -+} ColorType; -+ -+typedef enum -+{ -+ NO_STEREO, -+ FIELD_RIGHT, -+ FIELD_LEFT, -+ TWO_WAY_RIGHT_ON_EVEN, -+ TWO_WAY_LEFT_ON_EVEN, -+ FOUR_WAY_INTERLEAVED, -+ SIDE_BY_SIDE -+} StereoType; -+ -+struct Timing -+{ -+ int width; -+ int height; -+ int frequency; -+}; -+ -+struct DisplayDescriptor -+{ -+}; -+ -+struct DetailedTiming -+{ -+ int pixel_clock; -+ int h_addr; -+ int h_blank; -+ int h_sync; -+ int h_front_porch; -+ int v_addr; -+ int v_blank; -+ int v_sync; -+ int v_front_porch; -+ int width_mm; -+ int height_mm; -+ int right_border; -+ int top_border; -+ int interlaced; -+ StereoType stereo; -+ -+ int digital_sync; -+ union -+ { -+ struct -+ { -+ int bipolar; -+ int serrations; -+ int sync_on_green; -+ } analog; -+ -+ struct -+ { -+ int composite; -+ int serrations; -+ int negative_vsync; -+ int negative_hsync; -+ } digital; -+ }; -+}; -+ -+struct MonitorInfo -+{ -+ int checksum; -+ char manufacturer_code[4]; -+ int product_code; -+ unsigned int serial_number; -+ -+ int production_week; /* -1 if not specified */ -+ int production_year; /* -1 if not specified */ -+ int model_year; /* -1 if not specified */ -+ -+ int major_version; -+ int minor_version; -+ -+ int is_digital; -+ -+ union -+ { -+ struct -+ { -+ int bits_per_primary; -+ Interface interface; -+ int rgb444; -+ int ycrcb444; -+ int ycrcb422; -+ } digital; -+ -+ struct -+ { -+ double video_signal_level; -+ double sync_signal_level; -+ double total_signal_level; -+ -+ int blank_to_black; -+ -+ int separate_hv_sync; -+ int composite_sync_on_h; -+ int composite_sync_on_green; -+ int serration_on_vsync; -+ ColorType color_type; -+ } analog; -+ }; -+ -+ 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); -+ -+#endif -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..07555b6 ---- /dev/null -+++ b/libgnome-desktop/libgnomeui/monitor-db.h -@@ -0,0 +1,79 @@ -+/* monitor-db.h -+ * -+ * Copyright 2007, 2008, Red Hat, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome Library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: Soren Sandmann -+ */ -+#ifndef MONITOR_DB_H -+#define MONITOR_DB_H -+ -+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API -+#error monitor-db.h is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including monitor-db.h -+#endif -+ -+#include -+#include -+ -+typedef struct Output Output; -+typedef struct Configuration Configuration; -+ -+struct Output -+{ -+ char * name; -+ -+ gboolean on; -+ int width; -+ int height; -+ int rate; -+ int x; -+ int y; -+ RWRotation rotation; -+ -+ gboolean connected; -+ char vendor[4]; -+ guint product; -+ guint serial; -+ double aspect; -+ int pref_width; -+ int pref_height; -+ char * display_name; -+ -+ gpointer user_data; -+}; -+ -+struct Configuration -+{ -+ gboolean clone; -+ -+ Output **outputs; -+}; -+ -+void configuration_free (Configuration *configuration); -+Configuration *configuration_new_current (RWScreen *screen); -+gboolean configuration_match (Configuration *config1, -+ Configuration *config2); -+gboolean configuration_save (Configuration *configuration, -+ GError **err); -+void configuration_sanitize (Configuration *configuration); -+gboolean configuration_apply_stored (RWScreen *screen); -+gboolean configuration_applicable (Configuration *configuration, -+ RWScreen *screen); -+ -+#endif -diff --git a/libgnome-desktop/libgnomeui/randrwrap.h b/libgnome-desktop/libgnomeui/randrwrap.h -new file mode 100644 -index 0000000..b185051 ---- /dev/null -+++ b/libgnome-desktop/libgnomeui/randrwrap.h -@@ -0,0 +1,123 @@ -+/* randrwrap.h -+ * -+ * Copyright 2007, 2008, Red Hat, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome Library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: Soren Sandmann -+ */ -+#ifndef RANDR_WRAP_H -+#define RANDR_WRAP_H -+ -+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API -+#error randrwrap is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including randrwrap.h -+#endif -+ -+#include -+#include -+ -+typedef struct RWScreen RWScreen; -+typedef struct RWOutput RWOutput; -+typedef struct RWCrtc RWCrtc; -+typedef struct RWMode RWMode; -+ -+typedef void (* RWScreenChanged) (RWScreen *screen, gpointer data); -+ -+typedef enum -+{ -+ RW_ROTATION_0 = (1 << 0), -+ RW_ROTATION_90 = (1 << 1), -+ RW_ROTATION_180 = (1 << 2), -+ RW_ROTATION_270 = (1 << 3), -+ RW_REFLECT_X = (1 << 4), -+ RW_REFLECT_Y = (1 << 5) -+} RWRotation; -+ -+/* RWScreen */ -+RWScreen * rw_screen_new (GdkScreen *screen, -+ RWScreenChanged callback, -+ gpointer data); -+RWOutput ** rw_screen_list_outputs (RWScreen *screen); -+RWCrtc ** rw_screen_list_crtcs (RWScreen *screen); -+RWMode ** rw_screen_list_modes (RWScreen *screen); -+void rw_screen_set_size (RWScreen *screen, -+ int width, -+ int height, -+ int mm_width, -+ int mm_height); -+RWCrtc * rw_screen_get_crtc_by_id (RWScreen *screen, -+ guint32 id); -+gboolean rw_screen_refresh (RWScreen *screen); -+RWOutput * rw_screen_get_output_by_id (RWScreen *screen, -+ guint32 id); -+RWOutput * rw_screen_get_output_by_name (RWScreen *screen, -+ const char *name); -+void rw_screen_get_ranges (RWScreen *screen, -+ int *min_width, -+ int *max_width, -+ int *min_height, -+ int *max_height); -+ -+/* RWOutput */ -+guint32 rw_output_get_id (RWOutput *output); -+const char * rw_output_get_name (RWOutput *output); -+gboolean rw_output_is_connected (RWOutput *output); -+int rw_output_get_size_inches (RWOutput *output); -+int rw_output_get_width_mm (RWOutput *outout); -+int rw_output_get_height_mm (RWOutput *output); -+const guint8 *rw_output_get_edid_data (RWOutput *output); -+RWCrtc ** rw_output_get_possible_crtcs (RWOutput *output); -+RWMode * rw_output_get_current_mode (RWOutput *output); -+RWCrtc * rw_output_get_crtc (RWOutput *output); -+void rw_output_get_position (RWOutput *output, -+ int *x, -+ int *y); -+gboolean rw_output_can_clone (RWOutput *output, -+ RWOutput *clone); -+RWMode ** rw_output_list_modes (RWOutput *output); -+RWMode * rw_output_get_preferred_mode (RWOutput *output); -+gboolean rw_output_supports_mode (RWOutput *output, -+ RWMode *mode); -+ -+/* RWMode */ -+guint32 rw_mode_get_id (RWMode *mode); -+guint rw_mode_get_width (RWMode *mode); -+guint rw_mode_get_height (RWMode *mode); -+int rw_mode_get_freq (RWMode *mode); -+ -+/* RWCrtc */ -+guint32 rw_crtc_get_id (RWCrtc *crtc); -+gboolean rw_crtc_set_config (RWCrtc *crtc, -+ int x, -+ int y, -+ RWMode *mode, -+ RWRotation rotation, -+ RWOutput **outputs, -+ int n_outputs); -+gboolean rw_crtc_can_drive_output (RWCrtc *crtc, -+ RWOutput *output); -+RWMode * rw_crtc_get_current_mode (RWCrtc *crtc); -+void rw_crtc_get_position (RWCrtc *crtc, -+ int *x, -+ int *y); -+RWRotation rw_crtc_get_current_rotation (RWCrtc *crtc); -+RWRotation rw_crtc_get_rotations (RWCrtc *crtc); -+gboolean rw_crtc_supports_rotation (RWCrtc *crtc, -+ RWRotation rotation); -+ -+#endif -diff --git a/libgnome-desktop/monitor-db.c b/libgnome-desktop/monitor-db.c -new file mode 100644 -index 0000000..ff6e8de ---- /dev/null -+++ b/libgnome-desktop/monitor-db.c -@@ -0,0 +1,1406 @@ -+/* monitor-db.c -+ * -+ * Copyright 2007, 2008, Red Hat, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome Library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: Soren Sandmann -+ */ -+ -+#define GNOME_DESKTOP_USE_UNSTABLE_API -+ -+#include -+#include -+#include -+#include -+#include "libgnomeui/monitor-db.h" -+#include "edid.h" -+ -+#define CONFIG_BASENAME "monitors.xml" -+ -+/* In version 0 of the config file format, we had several toplevel elements -+ * and no explicit version number. So, the filed looked like -+ * -+ * -+ * ... -+ * -+ * -+ * ... -+ * -+ * -+ * Since version 1 of the config file, the file has a toplevel element to group -+ * all the configurations. That element has a "version" attribute which is an integer. -+ * So, the file looks like this: -+ * -+ * -+ * -+ * ... -+ * -+ * -+ * ... -+ * -+ * -+ */ -+ -+/* A helper wrapper around the GMarkup parser stuff */ -+static gboolean parse_file_gmarkup (const gchar *file, -+ const GMarkupParser *parser, -+ gpointer data, -+ GError **err); -+ -+typedef struct CrtcAssignment CrtcAssignment; -+ -+static void crtc_assignment_apply (CrtcAssignment *assign); -+static CrtcAssignment *crtc_assignment_new (RWScreen *screen, -+ Output **outputs); -+static void crtc_assignment_free (CrtcAssignment *assign); -+static void output_free (Output *output); -+static Output * output_copy (Output *output); -+ -+static gchar *get_old_config_filename (void); -+static gchar *get_config_filename (void); -+ -+typedef struct Parser Parser; -+ -+/* Parser for monitor configurations */ -+struct Parser -+{ -+ int config_file_version; -+ Output *output; -+ Configuration *configuration; -+ GPtrArray *outputs; -+ GPtrArray *configurations; -+ GQueue *stack; -+}; -+ -+static int -+parse_int (const char *text) -+{ -+ return strtol (text, NULL, 0); -+} -+ -+static guint -+parse_uint (const char *text) -+{ -+ return strtoul (text, NULL, 0); -+} -+ -+static gboolean -+stack_is (Parser *parser, -+ const char *s1, -+ ...) -+{ -+ GList *stack = NULL; -+ const char *s; -+ GList *l1, *l2; -+ va_list args; -+ -+ stack = g_list_prepend (stack, (gpointer)s1); -+ -+ va_start (args, s1); -+ -+ s = va_arg (args, const char *); -+ while (s) -+ { -+ stack = g_list_prepend (stack, (gpointer)s); -+ s = va_arg (args, const char *); -+ } -+ -+ l1 = stack; -+ l2 = parser->stack->head; -+ -+ while (l1 && l2) -+ { -+ if (strcmp (l1->data, l2->data) != 0) -+ { -+ g_list_free (stack); -+ return FALSE; -+ } -+ -+ l1 = l1->next; -+ l2 = l2->next; -+ } -+ -+ g_list_free (stack); -+ -+ return (!l1 && !l2); -+} -+ -+static void -+handle_start_element (GMarkupParseContext *context, -+ const gchar *name, -+ const gchar **attr_names, -+ const gchar **attr_values, -+ gpointer user_data, -+ GError **err) -+{ -+ Parser *parser = user_data; -+ -+ if (strcmp (name, "output") == 0) -+ { -+ int i; -+ g_assert (parser->output == NULL); -+ -+ parser->output = g_new0 (Output, 1); -+ parser->output->rotation = 0; -+ -+ for (i = 0; attr_names[i] != NULL; ++i) -+ { -+ if (strcmp (attr_names[i], "name") == 0) -+ { -+ parser->output->name = g_strdup (attr_values[i]); -+ break; -+ } -+ } -+ -+ if (!parser->output->name) -+ { -+ /* This really shouldn't happen, but it's better to make -+ * something up than to crash later. -+ */ -+ g_warning ("Malformed monitor configuration file"); -+ -+ parser->output->name = g_strdup ("default"); -+ } -+ parser->output->connected = FALSE; -+ parser->output->on = FALSE; -+ } -+ else if (strcmp (name, "configuration") == 0) -+ { -+ g_assert (parser->configuration == NULL); -+ -+ parser->configuration = g_new0 (Configuration, 1); -+ parser->configuration->clone = FALSE; -+ parser->configuration->outputs = g_new0 (Output *, 1); -+ } -+ else if (strcmp (name, "monitors") == 0) -+ { -+ int i; -+ -+ for (i = 0; attr_names[i] != NULL; i++) -+ { -+ if (strcmp (attr_names[i], "version") == 0) -+ { -+ parser->config_file_version = parse_int (attr_values[i]); -+ break; -+ } -+ } -+ } -+ -+ g_queue_push_tail (parser->stack, g_strdup (name)); -+} -+ -+static void -+handle_end_element (GMarkupParseContext *context, -+ const gchar *name, -+ gpointer user_data, -+ GError **err) -+{ -+ Parser *parser = user_data; -+ -+ if (strcmp (name, "output") == 0) -+ { -+ /* If no rotation properties were set, just use RW_ROTATION_0 */ -+ if (parser->output->rotation == 0) -+ parser->output->rotation = RW_ROTATION_0; -+ -+ g_ptr_array_add (parser->outputs, parser->output); -+ -+ parser->output = NULL; -+ } -+ else if (strcmp (name, "configuration") == 0) -+ { -+ g_ptr_array_add (parser->outputs, NULL); -+ parser->configuration->outputs = -+ (Output **)g_ptr_array_free (parser->outputs, FALSE); -+ parser->outputs = g_ptr_array_new (); -+ g_ptr_array_add (parser->configurations, parser->configuration); -+ parser->configuration = NULL; -+ } -+ -+ g_free (g_queue_pop_tail (parser->stack)); -+} -+ -+#define TOPLEVEL_ELEMENT (parser->config_file_version > 0 ? "monitors" : NULL) -+ -+static void -+handle_text (GMarkupParseContext *context, -+ const gchar *text, -+ gsize text_len, -+ gpointer user_data, -+ GError **err) -+{ -+ Parser *parser = user_data; -+ -+ if (stack_is (parser, "vendor", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->connected = TRUE; -+ -+ strncpy (parser->output->vendor, text, 3); -+ parser->output->vendor[3] = 0; -+ } -+ else if (stack_is (parser, "clone", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ if (strcmp (text, "yes") == 0) -+ parser->configuration->clone = TRUE; -+ } -+ else if (stack_is (parser, "product", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->connected = TRUE; -+ -+ parser->output->product = parse_int (text); -+ } -+ else if (stack_is (parser, "serial", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->connected = TRUE; -+ -+ parser->output->serial = parse_uint (text); -+ } -+ else if (stack_is (parser, "width", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->on = TRUE; -+ -+ parser->output->width = parse_int (text); -+ } -+ else if (stack_is (parser, "x", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->on = TRUE; -+ -+ parser->output->x = parse_int (text); -+ } -+ else if (stack_is (parser, "y", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->on = TRUE; -+ -+ parser->output->y = parse_int (text); -+ } -+ else if (stack_is (parser, "height", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->on = TRUE; -+ -+ parser->output->height = parse_int (text); -+ } -+ else if (stack_is (parser, "rate", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ parser->output->on = TRUE; -+ -+ parser->output->rate = parse_int (text); -+ } -+ else if (stack_is (parser, "rotation", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ if (strcmp (text, "normal") == 0) -+ { -+ parser->output->rotation |= RW_ROTATION_0; -+ } -+ else if (strcmp (text, "left") == 0) -+ { -+ parser->output->rotation |= RW_ROTATION_90; -+ } -+ else if (strcmp (text, "upside_down") == 0) -+ { -+ parser->output->rotation |= RW_ROTATION_180; -+ } -+ else if (strcmp (text, "right") == 0) -+ { -+ parser->output->rotation |= RW_ROTATION_270; -+ } -+ } -+ else if (stack_is (parser, "reflect_x", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ if (strcmp (text, "yes") == 0) -+ { -+ parser->output->rotation |= RW_REFLECT_X; -+ } -+ } -+ else if (stack_is (parser, "reflect_y", "output", "configuration", TOPLEVEL_ELEMENT, NULL)) -+ { -+ if (strcmp (text, "yes") == 0) -+ { -+ parser->output->rotation |= RW_REFLECT_Y; -+ } -+ } -+ else -+ { -+ /* Ignore other properties so we can expand the format in the future */ -+ } -+} -+ -+static void -+parser_free (Parser *parser) -+{ -+ int i; -+ GList *list; -+ -+ g_assert (parser != NULL); -+ -+ if (parser->output) -+ output_free (parser->output); -+ -+ if (parser->configuration) -+ configuration_free (parser->configuration); -+ -+ for (i = 0; i < parser->outputs->len; ++i) -+ { -+ Output *output = parser->outputs->pdata[i]; -+ -+ output_free (output); -+ } -+ -+ g_ptr_array_free (parser->outputs, TRUE); -+ -+ for (i = 0; i < parser->configurations->len; ++i) -+ { -+ Configuration *config = parser->configurations->pdata[i]; -+ -+ configuration_free (config); -+ } -+ -+ g_ptr_array_free (parser->configurations, TRUE); -+ -+ for (list = parser->stack->head; list; list = list->next) -+ g_free (list->data); -+ g_queue_free (parser->stack); -+ -+ g_free (parser); -+} -+ -+static Configuration ** -+configurations_read_from_file (const gchar *filename, GError **error) -+{ -+ Parser *parser = g_new0 (Parser, 1); -+ Configuration **result; -+ GMarkupParser callbacks = { -+ handle_start_element, -+ handle_end_element, -+ handle_text, -+ NULL, /* passthrough */ -+ NULL, /* error */ -+ }; -+ -+ parser->config_file_version = 0; -+ parser->configurations = g_ptr_array_new (); -+ parser->outputs = g_ptr_array_new (); -+ parser->stack = g_queue_new (); -+ -+ if (!parse_file_gmarkup (filename, &callbacks, parser, error)) -+ { -+ result = NULL; -+ -+ g_assert (parser->outputs); -+ goto out; -+ } -+ -+ g_assert (parser->outputs); -+ -+ g_ptr_array_add (parser->configurations, NULL); -+ result = (Configuration **)g_ptr_array_free (parser->configurations, FALSE); -+ parser->configurations = g_ptr_array_new (); -+ -+ g_assert (parser->outputs); -+out: -+ parser_free (parser); -+ -+ return result; -+} -+ -+static Configuration ** -+configurations_read (GError **error) -+{ -+ char *filename; -+ Configuration **configs; -+ GError *err; -+ -+ /* Try the new configuration file... */ -+ -+ filename = get_config_filename (); -+ -+ err = NULL; -+ configs = configurations_read_from_file (filename, &err); -+ -+ g_free (filename); -+ -+ if (g_error_matches (err, G_FILE_ERROR, G_FILE_ERROR_NOENT)) -+ { -+ g_error_free (err); -+ -+ /* Okay, so try the old configuration file */ -+ filename = get_old_config_filename (); -+ configs = configurations_read_from_file (filename, error); -+ g_free (filename); -+ -+ return configs; -+ } -+ -+ g_propagate_error (error, err); -+ return configs; -+} -+ -+Configuration * -+configuration_new_current (RWScreen *screen) -+{ -+ Configuration *config = g_new0 (Configuration, 1); -+ GPtrArray *a = g_ptr_array_new (); -+ RWOutput **rw_outputs; -+ int i; -+ 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 = FALSE; -+ -+ for (i = 0; rw_outputs[i] != NULL; ++i) -+ { -+ RWOutput *rw_output = rw_outputs[i]; -+ Output *output = g_new0 (Output, 1); -+ RWMode *mode = NULL; -+ const guint8 *edid_data = rw_output_get_edid_data (rw_output); -+ RWCrtc *crtc; -+ -+ output->name = g_strdup (rw_output_get_name (rw_output)); -+ output->connected = rw_output_is_connected (rw_output); -+ -+ if (!output->connected) -+ { -+ output->x = -1; -+ output->y = -1; -+ output->width = -1; -+ output->height = -1; -+ output->rate = -1; -+ output->rotation = RW_ROTATION_0; -+ } -+ else -+ { -+ MonitorInfo *info = NULL; -+ -+ if (edid_data) -+ info = decode_edid (edid_data); -+ -+ if (info) -+ { -+ memcpy (output->vendor, info->manufacturer_code, -+ sizeof (output->vendor)); -+ -+ output->product = info->product_code; -+ output->serial = info->serial_number; -+ output->aspect = info->aspect_ratio; -+ } -+ else -+ { -+ strcpy (output->vendor, "???"); -+ output->product = 0; -+ output->serial = 0; -+ } -+ -+ output->display_name = make_display_name ( -+ rw_output_get_name (rw_output), info); -+ -+ g_free (info); -+ -+ crtc = rw_output_get_crtc (rw_output); -+ mode = crtc? rw_crtc_get_current_mode (crtc) : NULL; -+ -+ if (crtc && mode) -+ { -+ output->on = TRUE; -+ -+ rw_crtc_get_position (crtc, &output->x, &output->y); -+ output->width = rw_mode_get_width (mode); -+ output->height = rw_mode_get_height (mode); -+ output->rate = rw_mode_get_freq (mode); -+ output->rotation = rw_crtc_get_current_rotation (crtc); -+ -+ 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 -+ { -+ output->on = FALSE; -+ config->clone = FALSE; -+ } -+ -+ /* Get preferred size for the monitor */ -+ mode = rw_output_get_preferred_mode (rw_output); -+ -+ if (!mode) -+ { -+ RWMode **modes = rw_output_list_modes (rw_output); -+ -+ /* FIXME: we should pick the "best" mode here, where best is -+ * sorted wrt -+ * -+ * - closest aspect ratio -+ * - mode area -+ * - refresh rate -+ * - We may want to extend randrwrap so that get_preferred -+ * returns that - although that could also depend on -+ * the crtc. -+ */ -+ if (modes[0]) -+ mode = modes[0]; -+ } -+ -+ if (mode) -+ { -+ output->pref_width = rw_mode_get_width (mode); -+ output->pref_height = rw_mode_get_height (mode); -+ } -+ else -+ { -+ /* Pick some random numbers. This should basically never happen */ -+ output->pref_width = 1024; -+ output->pref_height = 768; -+ } -+ } -+ -+ g_ptr_array_add (a, output); -+ } -+ -+ g_ptr_array_add (a, NULL); -+ -+ config->outputs = (Output **)g_ptr_array_free (a, FALSE); -+ -+ g_assert (configuration_match (config, config)); -+ -+ return config; -+} -+ -+static void -+output_free (Output *output) -+{ -+ if (output->display_name) -+ g_free (output->display_name); -+ -+ if (output->name) -+ g_free (output->name); -+ -+ g_free (output); -+} -+ -+static Output * -+output_copy (Output *output) -+{ -+ Output *copy = g_new0 (Output, 1); -+ -+ *copy = *output; -+ -+ copy->name = g_strdup (output->name); -+ copy->display_name = g_strdup (output->display_name); -+ -+ return copy; -+} -+ -+static void -+outputs_free (Output **outputs) -+{ -+ int i; -+ -+ g_assert (outputs != NULL); -+ -+ for (i = 0; outputs[i] != NULL; ++i) -+ output_free (outputs[i]); -+} -+ -+void -+configuration_free (Configuration *config) -+{ -+ g_return_if_fail (config != NULL); -+ outputs_free (config->outputs); -+ -+ g_free (config); -+} -+ -+static void -+configurations_free (Configuration **configurations) -+{ -+ int i; -+ -+ g_assert (configurations != NULL); -+ -+ for (i = 0; configurations[i] != NULL; ++i) -+ configuration_free (configurations[i]); -+ -+ g_free (configurations); -+} -+ -+static gboolean -+parse_file_gmarkup (const gchar *filename, -+ const GMarkupParser *parser, -+ gpointer data, -+ GError **err) -+{ -+ GMarkupParseContext *context = NULL; -+ gchar *contents = NULL; -+ gboolean result = TRUE; -+ gsize len; -+ -+ if (!g_file_get_contents (filename, &contents, &len, err)) -+ { -+ result = FALSE; -+ goto out; -+ } -+ -+ context = g_markup_parse_context_new (parser, 0, data, NULL); -+ -+ if (!g_markup_parse_context_parse (context, contents, len, err)) -+ { -+ result = FALSE; -+ goto out; -+ } -+ -+ if (!g_markup_parse_context_end_parse (context, err)) -+ { -+ result = FALSE; -+ goto out; -+ } -+ -+out: -+ if (contents) -+ g_free (contents); -+ -+ if (context) -+ g_markup_parse_context_free (context); -+ -+ return result; -+} -+ -+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; -+ -+ if (strcmp (output1->vendor, output2->vendor) != 0) -+ return FALSE; -+ -+ if (output1->product != output2->product) -+ return FALSE; -+ -+ if (output1->serial != output2->serial) -+ return FALSE; -+ -+ if (output1->connected != output2->connected) -+ return FALSE; -+ -+ return TRUE; -+} -+ -+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 gchar * -+get_old_config_filename (void) -+{ -+ return g_build_filename (g_get_home_dir(), ".gnome2", CONFIG_BASENAME, NULL); -+} -+ -+static gchar * -+get_config_filename (void) -+{ -+ return g_build_filename (g_get_user_config_dir (), CONFIG_BASENAME, 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]; ++i) -+ { -+ Output *output = config->outputs[i]; -+ -+ if (output->on) -+ { -+ output->x -= x_offset; -+ output->y -= y_offset; -+ } -+ } -+} -+ -+ -+gboolean -+configuration_save (Configuration *configuration, GError **err) -+{ -+ Configuration **configurations; -+ GString *output = g_string_new(""); -+ int i; -+ gchar *filename; -+ gboolean result; -+ -+ configurations = configurations_read (NULL); /* NULL-GError */ -+ -+ g_string_append_printf (output, "\n"); -+ -+ if (configurations) -+ { -+ for (i = 0; configurations[i] != NULL; ++i) -+ { -+ if (!configuration_match (configurations[i], configuration)) -+ emit_configuration (configurations[i], output); -+ } -+ -+ configurations_free (configurations); -+ } -+ -+ emit_configuration (configuration, output); -+ -+ g_string_append_printf (output, "\n"); -+ -+ filename = get_config_filename (); -+ result = g_file_set_contents (filename, output->str, -1, err); -+ g_free (filename); -+ -+ if (result) -+ { -+ /* Only remove the old config file if we were successful in saving the new one */ -+ -+ filename = get_old_config_filename (); -+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) -+ g_unlink (filename); -+ -+ g_free (filename); -+ } -+ -+ return result; -+} -+ -+static gboolean -+apply_configuration (Configuration *conf, RWScreen *screen) -+{ -+ CrtcAssignment *assignment; -+ Output **outputs; -+ -+ outputs = make_outputs (conf); -+ -+ assignment = crtc_assignment_new (screen, outputs); -+ -+ outputs_free (outputs); -+ -+ if (assignment) -+ { -+ crtc_assignment_apply (assignment); -+ -+ crtc_assignment_free (assignment); -+ -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+gboolean -+configuration_apply_stored (RWScreen *screen) -+{ -+ Configuration **configs = configurations_read (NULL); /* NULL-GError */ -+ Configuration *current; -+ Configuration *found; -+ gboolean result; -+ -+ if (!screen) -+ return FALSE; -+ -+ rw_screen_refresh (screen); -+ -+ 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); -+ } -+ -+ configuration_free (current); -+ -+ return result; -+} -+ -+ -+/* -+ * 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; i < info->outputs->len; ++i) -+ { -+ RWOutput *clone = info->outputs->pdata[i]; -+ -+ if (!rw_output_can_clone (clone, output)) -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static gboolean -+crtc_assignment_assign (CrtcAssignment *assign, -+ RWCrtc *crtc, -+ RWMode *mode, -+ int x, -+ int y, -+ RWRotation rotation, -+ RWOutput *output) -+{ -+ /* 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 void -+crtc_assignment_unassign (CrtcAssignment *assign, -+ RWCrtc *crtc, -+ RWOutput *output) -+{ -+ CrtcInfo *info = g_hash_table_lookup (assign->info, crtc); -+ -+ if (info) -+ { -+ g_ptr_array_remove (info->outputs, output); -+ -+ if (info->outputs->len == 0) -+ g_hash_table_remove (assign->info, crtc); -+ } -+} -+ -+static void -+crtc_assignment_free (CrtcAssignment *assign) -+{ -+ g_hash_table_destroy (assign->info); -+ -+ g_free (assign); -+} -+ -+static void -+configure_crtc (gpointer key, -+ gpointer value, -+ gpointer data) -+{ -+ 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 gboolean -+mode_is_rotated (CrtcInfo *info) -+{ -+ if ((info->rotation & RW_ROTATION_270) || -+ (info->rotation & RW_ROTATION_90)) -+ { -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+static gboolean -+crtc_is_rotated (RWCrtc *crtc) -+{ -+ RWRotation r = rw_crtc_get_current_rotation (crtc); -+ -+ if ((r & RW_ROTATION_270) || -+ (r & RW_ROTATION_90)) -+ { -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+static void -+crtc_assignment_apply (CrtcAssignment *assign) -+{ -+ 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; -+ -+ /* Compute size of the screen */ -+ width = height = 1; -+ for (list = active_crtcs; list != NULL; list = list->next) -+ { -+ 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 (mode_is_rotated (info)) -+ { -+ int tmp = h; -+ h = w; -+ w = tmp; -+ } -+ -+ width = MAX (width, info->x + w); -+ height = MAX (height, info->y + h); -+ } -+ g_list_free (active_crtcs); -+ -+ rw_screen_get_ranges ( -+ assign->screen, &min_width, &max_width, &min_height, &max_height); -+ -+ 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) -+ { -+ RWCrtc *crtc = all_crtcs[i]; -+ RWMode *mode = rw_crtc_get_current_mode (crtc); -+ int x, y; -+ -+ if (mode) -+ { -+ 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); -+ } -+ } -+ -+ /* 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); -+ } -+ -+ /* 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); -+} -+ -+/* 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) -+{ -+ RWCrtc **crtcs = rw_screen_list_crtcs (screen); -+ Output *output; -+ int i; -+ -+ output = *outputs; -+ if (!output) -+ return TRUE; -+ -+ /* It is always allowed for an output to be turned off */ -+ if (!output->on) -+ { -+ 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) -+ { -+ 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); -+ } -+ } -+ } -+ } -+ } -+ -+ return FALSE; -+} -+ -+static void -+crtc_info_free (CrtcInfo *info) -+{ -+ g_ptr_array_free (info->outputs, TRUE); -+ g_free (info); -+} -+ -+static CrtcAssignment * -+crtc_assignment_new (RWScreen *screen, Output **outputs) -+{ -+ CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1); -+ -+ assignment->info = g_hash_table_new_full ( -+ g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free); -+ -+ if (real_assign_crtcs (screen, outputs, assignment)) -+ { -+ assignment->screen = screen; -+ -+ return assignment; -+ } -+ else -+ { -+ crtc_assignment_free (assignment); -+ -+ return NULL; -+ } -+} -diff --git a/libgnome-desktop/randrwrap.c b/libgnome-desktop/randrwrap.c -new file mode 100644 -index 0000000..bffeada ---- /dev/null -+++ b/libgnome-desktop/randrwrap.c -@@ -0,0 +1,1221 @@ -+/* randrwrap.c -+ * -+ * Copyright 2007, 2008, Red Hat, Inc. -+ * -+ * This file is part of the Gnome Library. -+ * -+ * The Gnome Library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Library General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * The Gnome Library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Library General Public License for more details. -+ * -+ * You should have received a copy of the GNU Library General Public -+ * License along with the Gnome Library; see the file COPYING.LIB. If not, -+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: Soren Sandmann -+ */ -+ -+#define GNOME_DESKTOP_USE_UNSTABLE_API -+ -+#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; -+}; -+ -+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; -+}; -+ -+struct RWOutputWrap -+{ -+ RROutput id; -+}; -+ -+struct RWCrtc -+{ -+ ScreenInfo * info; -+ RRCrtc id; -+ -+ RWMode * current_mode; -+ RWOutput ** current_outputs; -+ RWOutput ** possible_outputs; -+ int x; -+ int y; -+ -+ RWRotation current_rotation; -+ RWRotation rotations; -+}; -+ -+struct RWMode -+{ -+ 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); -+ -+ -+/* Screen */ -+static RWOutput * -+rw_output_by_id (ScreenInfo *info, RROutput id) -+{ -+ RWOutput **output; -+ -+ g_assert (info != NULL); -+ -+ 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; -+ -+ if (!info) -+ return NULL; -+ -+ 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; -+ -+ g_assert (info != NULL); -+ -+ 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; -+ -+ g_assert (info != NULL); -+ -+ 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; -+ -+ 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) -+ { -+ 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; -+ -+ 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 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_assert (screen != NULL); -+ -+ 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 && 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; -+} -+ -+/* Returns NULL if screen could not be created. For instance, if driver -+ * does not support Xrandr 1.2. -+ */ -+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); -+ -+ if (!screen->info) -+ return NULL; -+ -+ 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) -+{ -+ g_return_val_if_fail (screen != NULL, NULL); -+ g_return_val_if_fail (screen->info != NULL, NULL); -+ -+ return screen->info->modes; -+} -+ -+RWCrtc ** -+rw_screen_list_crtcs (RWScreen *screen) -+{ -+ g_return_val_if_fail (screen != NULL, NULL); -+ g_return_val_if_fail (screen->info != NULL, NULL); -+ -+ return screen->info->crtcs; -+} -+ -+RWOutput ** -+rw_screen_list_outputs (RWScreen *screen) -+{ -+ g_return_val_if_fail (screen != NULL, NULL); -+ g_return_val_if_fail (screen->info != NULL, NULL); -+ -+ return screen->info->outputs; -+} -+ -+RWCrtc * -+rw_screen_get_crtc_by_id (RWScreen *screen, -+ guint32 id) -+{ -+ int i; -+ -+ 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) -+ { -+ 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; -+ -+ 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) -+ { -+ 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 || !output->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) -+{ -+ 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) -+ { -+ RWOutput *output = screen->info->outputs[i]; -+ -+ if (strcmp (output->name, name) == 0) -+ return output; -+ } -+ -+ return NULL; -+} -+ -+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); -+ -+ if ((crtc = rw_output_get_crtc (output))) -+ return rw_crtc_get_current_mode (crtc); -+ -+ return NULL; -+} -+ -+void -+rw_output_get_position (RWOutput *output, -+ int *x, -+ int *y) -+{ -+ RWCrtc *crtc; -+ -+ g_return_if_fail (output != NULL); -+ -+ if ((crtc = rw_output_get_crtc (output))) -+ rw_crtc_get_position (crtc, x, y); -+} -+ -+const char * -+rw_output_get_name (RWOutput *output) -+{ -+ g_assert (output != NULL); -+ return output->name; -+} -+ -+int -+rw_output_get_width_mm (RWOutput *output) -+{ -+ g_assert (output != NULL); -+ return output->width_mm; -+} -+ -+int -+rw_output_get_height_mm (RWOutput *output) -+{ -+ g_assert (output != NULL); -+ return output->height_mm; -+} -+ -+RWMode * -+rw_output_get_preferred_mode (RWOutput *output) -+{ -+ g_return_val_if_fail (output != NULL, NULL); -+ if (output->n_preferred) -+ return output->modes[0]; -+ -+ return NULL; -+} -+ -+RWMode ** -+rw_output_list_modes (RWOutput *output) -+{ -+ g_return_val_if_fail (output != NULL, NULL); -+ return output->modes; -+} -+ -+gboolean -+rw_output_is_connected (RWOutput *output) -+{ -+ g_return_val_if_fail (output != NULL, FALSE); -+ 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); -+ -+ for (i = 0; output->modes[i] != NULL; ++i) -+ { -+ if (output->modes[i] == mode) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+gboolean -+rw_output_can_clone (RWOutput *output, -+ RWOutput *clone) -+{ -+ int 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 (output->clones[i] == clone) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/* RWCrtc */ -+typedef struct -+{ -+ 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 RWRotation -+rw_rotation_from_xrotation (Rotation r) -+{ -+ 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; -+} -+ -+static Rotation -+xrotation_from_rotation (RWRotation r) -+{ -+ int i; -+ Rotation result = 0; -+ -+ for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i) -+ { -+ if (r & rotation_map[i].rot) -+ result |= rotation_map[i].xrot; -+ } -+ -+ return result; -+} -+ -+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); -+ } -+ -+ output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput)); -+ -+ if (outputs) -+ { -+ 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; -+} -+ -+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; -+ -+ 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 (crtc->possible_outputs[i] == output) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/* 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; -+} -+ -+/* FIXME: merge with get_mode()? */ -+RWRotation -+rw_crtc_get_current_rotation (RWCrtc *crtc) -+{ -+ g_assert(crtc != NULL); -+ return crtc->current_rotation; -+} -+ -+RWRotation -+rw_crtc_get_rotations (RWCrtc *crtc) -+{ -+ g_assert(crtc != NULL); -+ return crtc->rotations; -+} -+ -+gboolean -+rw_crtc_supports_rotation (RWCrtc * crtc, -+ RWRotation rotation) -+{ -+ g_return_val_if_fail (crtc != NULL, FALSE); -+ return (crtc->rotations & rotation); -+} -+ -+static RWCrtc * -+crtc_new (ScreenInfo *info, RROutput id) -+{ -+ RWCrtc *crtc = g_new0 (RWCrtc, 1); -+ -+ crtc->id = id; -+ crtc->info = info; -+ -+ return crtc; -+} -+ -+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); -+ -+ /* Rotations */ -+ crtc->current_rotation = rw_rotation_from_xrotation (info->rotation); -+ crtc->rotations = rw_rotation_from_xrotation (info->rotations); -+ -+ XRRFreeCrtcInfo (info); -+} -+ -+static void -+crtc_free (RWCrtc *crtc) -+{ -+ g_free (crtc->current_outputs); -+ g_free (crtc->possible_outputs); -+ g_free (crtc); -+} -+ -+/* RWMode */ -+static RWMode * -+mode_new (ScreenInfo *info, RRMode id) -+{ -+ RWMode *mode = g_new0 (RWMode, 1); -+ -+ mode->id = id; -+ mode->info = info; -+ -+ return mode; -+} -+ -+guint32 -+rw_mode_get_id (RWMode *mode) -+{ -+ g_return_val_if_fail (mode != NULL, 0); -+ return mode->id; -+} -+ -+guint -+rw_mode_get_width (RWMode *mode) -+{ -+ g_return_val_if_fail (mode != NULL, 0); -+ return mode->width; -+} -+ -+int -+rw_mode_get_freq (RWMode *mode) -+{ -+ g_return_val_if_fail (mode != NULL, 0); -+ return (mode->freq) / 1000; -+} -+ -+guint -+rw_mode_get_height (RWMode *mode) -+{ -+ g_return_val_if_fail (mode != NULL, 0); -+ return mode->height; -+} -+ -+static void -+mode_initialize (RWMode *mode, XRRModeInfo *info) -+{ -+ g_assert (mode != NULL); -+ g_assert (info != NULL); -+ -+ 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) -+{ -+ g_free (mode->name); -+ g_free (mode); -+} -+ -+ -+#ifdef INCLUDE_MAIN -+static void -+on_screen_changed (RWScreen *screen, gpointer data) -+{ -+ g_print ("Changed\n"); -+} -+ -+static gboolean -+do_refresh (gpointer data) -+{ -+ RWScreen *screen = data; -+ -+ rw_screen_refresh (screen); -+ -+ return TRUE; -+} -+ -+int -+main (int argc, char **argv) -+{ -+ int i; -+ -+ 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) -+ { -+ RWCrtc *crtc = screen->info->crtcs[i]; -+ -+ if (crtc->current_mode) -+ { -+ g_print ("CRTC %p: (%d %d %d %d)\n", -+ crtc, crtc->x, crtc->y, -+ crtc->current_mode->width, crtc->current_mode->height); -+ } -+ else -+ { -+ g_print ("CRTC %p: turned off\n", crtc); -+ } -+ } -+ -+ 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; -+} -+#endif diff --git a/gnome-desktop.changes b/gnome-desktop.changes index 7a6281c..7f369c2 100644 --- a/gnome-desktop.changes +++ b/gnome-desktop.changes @@ -1,3 +1,20 @@ +------------------------------------------------------------------- +Tue Aug 5 18:43:47 CEST 2008 - rodrigo@suse.de + +- Update to version 2.23.6: + + Fix build with gcc 2.x (Jens Granseuer) + + GnomeBG: fix handling of empty filenames (Soren Sandmann) + + GnomeBG: word around non-atomic gconf for emitting changed signals + only once (Soren Sandmann) +- Remove upstreamed randr1.2 patch + +------------------------------------------------------------------- +Mon Jul 28 23:56:29 CEST 2008 - vuntz@novell.com + +- Add gnome-desktop-fate300461-desktop-gettext.patch to support + translation of desktop entries via gettext. This is part of + fate#300461 + ------------------------------------------------------------------- Mon Jul 7 15:41:10 CEST 2008 - ro@suse.de diff --git a/gnome-desktop.spec b/gnome-desktop.spec index 905d31b..d40185a 100644 --- a/gnome-desktop.spec +++ b/gnome-desktop.spec @@ -1,10 +1,17 @@ # -# spec file for package gnome-desktop (Version 2.23.4) +# spec file for package gnome-desktop (Version 2.23.6) # # Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany. -# This file and all modifications and additions to the pristine -# package are under the same license as the package itself. # +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + # Please submit bugfixes or comments via http://bugs.opensuse.org/ # @@ -16,8 +23,8 @@ BuildRequires: fdupes gnome-common gnome-doc-utils gnome-doc-utils-devel gtk-do License: GNU Free Documentation License, Version 1.1 (GFDL 1.1); GPL v2 or later; LGPL v2.1 or later Group: System/GUI/GNOME Obsoletes: gnome-core -Version: 2.23.4 -Release: 5 +Version: 2.23.6 +Release: 1 Summary: The GNOME Desktop API Library Source: %{name}-%{version}.tar.bz2 Url: http://www.gnome.org @@ -27,8 +34,8 @@ Patch1: X-KDE-SubstituteUID.dif Patch2: gnome-desktop-desktop.patch # PATCH-FEATURE-OPENSUSE gnome-desktop-recently-used-apps.patch -- Add launched .desktop files to recently used apps. Patch3: gnome-desktop-recently-used-apps.patch -# PATCH-FEATURE-UPSTREAM gnome-desktop-randr-1.2.diff -- Add support for RandR 1.2 to the libraries. federico@novell.com -Patch4: gnome-desktop-randr-1.2.diff +# PATCH-FEATURE-OPENSUSE gnome-desktop-fate300461-desktop-gettext.patch fate300461 vuntz@novell.com -- Look for translation of desktop entry strings via gettext +Patch5: gnome-desktop-fate300461-desktop-gettext.patch Requires: %{name}-lang = %{version} Requires: libgnome-desktop-2-7 = %{version} @@ -123,7 +130,7 @@ Authors: %patch1 %patch2 -p0 %patch3 -p1 -%patch4 -p1 +%patch5 -p1 %build autoreconf -f -i @@ -182,6 +189,17 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/gtk-doc/html/gnome-desktop %changelog +* Tue Aug 05 2008 rodrigo@suse.de +- Update to version 2.23.6: + + Fix build with gcc 2.x (Jens Granseuer) + + GnomeBG: fix handling of empty filenames (Soren Sandmann) + + GnomeBG: word around non-atomic gconf for emitting changed signals + only once (Soren Sandmann) +- Remove upstreamed randr1.2 patch +* Tue Jul 29 2008 vuntz@novell.com +- Add gnome-desktop-fate300461-desktop-gettext.patch to support + translation of desktop entries via gettext. This is part of + fate#300461 * Mon Jul 07 2008 ro@suse.de - update baselibs.conf (it is called libgnome-desktop-2-7 by now)