[gnome-flashback] display-config: implement configration changeing
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] display-config: implement configration changeing
- Date: Fri, 27 Mar 2015 00:36:18 +0000 (UTC)
commit 89469c79a138b530b904859fd193198ef34e98c3
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Fri Mar 27 02:33:34 2015 +0200
display-config: implement configration changeing
This commit makes possible to change display configuration from
gnome-control-center without mutter. Code are based on mutter
3.16.0 release.
Still missing configuration loading and saving...
configure.ac | 2 +-
gnome-flashback/libdisplay-config/Makefile.am | 3 +
gnome-flashback/libdisplay-config/edid-parse.c | 539 ++++++++
gnome-flashback/libdisplay-config/edid.h | 191 +++
.../libdisplay-config/flashback-display-config.c | 54 +-
.../libdisplay-config/flashback-monitor-config.c | 17 +
.../libdisplay-config/flashback-monitor-config.h | 7 +
.../libdisplay-config/flashback-monitor-manager.c | 1367 +++++++++++++++++++-
.../libdisplay-config/flashback-monitor-manager.h | 50 +-
.../libdisplay-config/meta-display-config-shared.h | 37 +
10 files changed, 2224 insertions(+), 43 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 481417f..e4cc8fe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,7 +49,7 @@ PKG_CHECK_MODULES(DESKTOP_BACKGROUND, gtk+-3.0 >= $GTK_REQUIRED gnome-desktop-3.
AC_SUBST(DESKTOP_BACKGROUND_CFLAGS)
AC_SUBST(DESKTOP_BACKGROUND_LIBS)
-PKG_CHECK_MODULES(DISPLAY_CONFIG, gtk+-3.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED gnome-desktop-3.0 >=
$LIBGNOME_DESKTOP_REQUIRED)
+PKG_CHECK_MODULES(DISPLAY_CONFIG, gtk+-3.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED gnome-desktop-3.0 >=
$LIBGNOME_DESKTOP_REQUIRED x11 xext xrandr x11-xcb xcb-randr)
AC_SUBST(DISPLAY_CONFIG_CFLAGS)
AC_SUBST(DISPLAY_CONFIG_LIBS)
diff --git a/gnome-flashback/libdisplay-config/Makefile.am b/gnome-flashback/libdisplay-config/Makefile.am
index 52b3f1a..640ce05 100644
--- a/gnome-flashback/libdisplay-config/Makefile.am
+++ b/gnome-flashback/libdisplay-config/Makefile.am
@@ -7,8 +7,11 @@ AM_CPPFLAGS = \
-DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
libdisplay_config_la_SOURCES = \
+ edid-parse.c \
+ edid.h \
meta-dbus-display-config.c \
meta-dbus-display-config.h \
+ meta-display-config-shared.h \
flashback-display-config.c \
flashback-display-config.h \
flashback-monitor-config.c \
diff --git a/gnome-flashback/libdisplay-config/edid-parse.c b/gnome-flashback/libdisplay-config/edid-parse.c
new file mode 100644
index 0000000..52bc51e
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/edid-parse.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright 2007 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Author: Soren Sandmann <sandmann redhat com> */
+
+#include "edid.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+
+static int
+get_bit (int in, int bit)
+{
+ return (in & (1 << bit)) >> bit;
+}
+
+static int
+get_bits (int in, int begin, int end)
+{
+ int mask = (1 << (end - begin + 1)) - 1;
+
+ return (in >> begin) & mask;
+}
+
+static int
+decode_header (const uchar *edid)
+{
+ if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static int
+decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
+{
+ int is_model_year;
+
+ /* Manufacturer Code */
+ info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
+ info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
+ info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
+ info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
+ info->manufacturer_code[3] = '\0';
+
+ info->manufacturer_code[0] += 'A' - 1;
+ info->manufacturer_code[1] += 'A' - 1;
+ info->manufacturer_code[2] += 'A' - 1;
+
+ /* Product Code */
+ info->product_code = edid[0x0b] << 8 | edid[0x0a];
+
+ /* Serial Number */
+ info->serial_number =
+ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
+
+ /* Week and Year */
+ is_model_year = FALSE;
+ switch (edid[0x10])
+ {
+ case 0x00:
+ info->production_week = -1;
+ break;
+
+ case 0xff:
+ info->production_week = -1;
+ is_model_year = TRUE;
+ break;
+
+ default:
+ info->production_week = edid[0x10];
+ break;
+ }
+
+ if (is_model_year)
+ {
+ info->production_year = -1;
+ info->model_year = 1990 + edid[0x11];
+ }
+ else
+ {
+ info->production_year = 1990 + edid[0x11];
+ info->model_year = -1;
+ }
+
+ return TRUE;
+}
+
+static int
+decode_edid_version (const uchar *edid, MonitorInfo *info)
+{
+ info->major_version = edid[0x12];
+ info->minor_version = edid[0x13];
+
+ return TRUE;
+}
+
+static int
+decode_display_parameters (const uchar *edid, MonitorInfo *info)
+{
+ /* Digital vs Analog */
+ info->is_digital = get_bit (edid[0x14], 7);
+
+ if (info->is_digital)
+ {
+ int bits;
+
+ static const int bit_depth[8] =
+ {
+ -1, 6, 8, 10, 12, 14, 16, -1
+ };
+
+ static const Interface interfaces[6] =
+ {
+ UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
+ };
+
+ bits = get_bits (edid[0x14], 4, 6);
+ info->connector.digital.bits_per_primary = bit_depth[bits];
+
+ bits = get_bits (edid[0x14], 0, 3);
+
+ if (bits <= 5)
+ info->connector.digital.interface = interfaces[bits];
+ else
+ info->connector.digital.interface = UNDEFINED;
+ }
+ else
+ {
+ int bits = get_bits (edid[0x14], 5, 6);
+
+ static const double levels[][3] =
+ {
+ { 0.7, 0.3, 1.0 },
+ { 0.714, 0.286, 1.0 },
+ { 1.0, 0.4, 1.4 },
+ { 0.7, 0.0, 0.7 },
+ };
+
+ info->connector.analog.video_signal_level = levels[bits][0];
+ info->connector.analog.sync_signal_level = levels[bits][1];
+ info->connector.analog.total_signal_level = levels[bits][2];
+
+ info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
+
+ info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
+ info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
+ info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
+
+ info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
+ }
+
+ /* Screen Size / Aspect Ratio */
+ if (edid[0x15] == 0 && edid[0x16] == 0)
+ {
+ info->width_mm = -1;
+ info->height_mm = -1;
+ info->aspect_ratio = -1.0;
+ }
+ else if (edid[0x16] == 0)
+ {
+ info->width_mm = -1;
+ info->height_mm = -1;
+ info->aspect_ratio = 100.0 / (edid[0x15] + 99);
+ }
+ else if (edid[0x15] == 0)
+ {
+ info->width_mm = -1;
+ info->height_mm = -1;
+ info->aspect_ratio = 100.0 / (edid[0x16] + 99);
+ info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
+ }
+ else
+ {
+ info->width_mm = 10 * edid[0x15];
+ info->height_mm = 10 * edid[0x16];
+ }
+
+ /* Gamma */
+ if (edid[0x17] == 0xFF)
+ info->gamma = -1.0;
+ else
+ info->gamma = (edid[0x17] + 100.0) / 100.0;
+
+ /* Features */
+ info->standby = get_bit (edid[0x18], 7);
+ info->suspend = get_bit (edid[0x18], 6);
+ info->active_off = get_bit (edid[0x18], 5);
+
+ if (info->is_digital)
+ {
+ info->connector.digital.rgb444 = TRUE;
+ if (get_bit (edid[0x18], 3))
+ info->connector.digital.ycrcb444 = 1;
+ if (get_bit (edid[0x18], 4))
+ info->connector.digital.ycrcb422 = 1;
+ }
+ else
+ {
+ int bits = get_bits (edid[0x18], 3, 4);
+ ColorType color_type[4] =
+ {
+ MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
+ };
+
+ info->connector.analog.color_type = color_type[bits];
+ }
+
+ info->srgb_is_standard = get_bit (edid[0x18], 2);
+
+ /* In 1.3 this is called "has preferred timing" */
+ info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
+
+ /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
+ info->continuous_frequency = get_bit (edid[0x18], 0);
+ return TRUE;
+}
+
+static double
+decode_fraction (int high, int low)
+{
+ double result = 0.0;
+ int i;
+
+ high = (high << 2) | low;
+
+ for (i = 0; i < 10; ++i)
+ result += get_bit (high, i) * pow (2, i - 10);
+
+ return result;
+}
+
+static int
+decode_color_characteristics (const uchar *edid, MonitorInfo *info)
+{
+ info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
+ info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
+ info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
+ info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
+ info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
+ info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
+ info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
+ info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
+
+ return TRUE;
+}
+
+static int
+decode_established_timings (const uchar *edid, MonitorInfo *info)
+{
+ static const Timing established[][8] =
+ {
+ {
+ { 800, 600, 60 },
+ { 800, 600, 56 },
+ { 640, 480, 75 },
+ { 640, 480, 72 },
+ { 640, 480, 67 },
+ { 640, 480, 60 },
+ { 720, 400, 88 },
+ { 720, 400, 70 }
+ },
+ {
+ { 1280, 1024, 75 },
+ { 1024, 768, 75 },
+ { 1024, 768, 70 },
+ { 1024, 768, 60 },
+ { 1024, 768, 87 },
+ { 832, 624, 75 },
+ { 800, 600, 75 },
+ { 800, 600, 72 }
+ },
+ {
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 1152, 870, 75 }
+ },
+ };
+
+ int i, j, idx;
+
+ idx = 0;
+ for (i = 0; i < 3; ++i)
+ {
+ for (j = 0; j < 8; ++j)
+ {
+ int byte = edid[0x23 + i];
+
+ if (get_bit (byte, j) && established[i][j].frequency != 0)
+ info->established[idx++] = established[i][j];
+ }
+ }
+ return TRUE;
+}
+
+static int
+decode_standard_timings (const uchar *edid, MonitorInfo *info)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ int first = edid[0x26 + 2 * i];
+ int second = edid[0x27 + 2 * i];
+
+ if (first != 0x01 && second != 0x01)
+ {
+ int w = 8 * (first + 31);
+ int h = 0;
+
+ switch (get_bits (second, 6, 7))
+ {
+ case 0x00: h = (w / 16) * 10; break;
+ case 0x01: h = (w / 4) * 3; break;
+ case 0x02: h = (w / 5) * 4; break;
+ case 0x03: h = (w / 16) * 9; break;
+ }
+
+ info->standard[i].width = w;
+ info->standard[i].height = h;
+ info->standard[i].frequency = get_bits (second, 0, 5) + 60;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+decode_lf_string (const uchar *s, int n_chars, char *result)
+{
+ int i;
+ for (i = 0; i < n_chars; ++i)
+ {
+ if (s[i] == 0x0a)
+ {
+ *result++ = '\0';
+ break;
+ }
+ else if (s[i] == 0x00)
+ {
+ /* Convert embedded 0's to spaces */
+ *result++ = ' ';
+ }
+ else
+ {
+ *result++ = s[i];
+ }
+ }
+}
+
+static void
+decode_display_descriptor (const uchar *desc,
+ MonitorInfo *info)
+{
+ switch (desc[0x03])
+ {
+ case 0xFC:
+ decode_lf_string (desc + 5, 13, info->dsc_product_name);
+ break;
+ case 0xFF:
+ decode_lf_string (desc + 5, 13, info->dsc_serial_number);
+ break;
+ case 0xFE:
+ decode_lf_string (desc + 5, 13, info->dsc_string);
+ break;
+ case 0xFD:
+ /* Range Limits */
+ break;
+ case 0xFB:
+ /* Color Point */
+ break;
+ case 0xFA:
+ /* Timing Identifications */
+ break;
+ case 0xF9:
+ /* Color Management */
+ break;
+ case 0xF8:
+ /* Timing Codes */
+ break;
+ case 0xF7:
+ /* Established Timings */
+ break;
+ case 0x10:
+ break;
+ }
+}
+
+static void
+decode_detailed_timing (const uchar *timing,
+ DetailedTiming *detailed)
+{
+ int bits;
+ StereoType stereo[] =
+ {
+ NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
+ TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
+ FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
+ };
+
+ detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
+ detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
+ detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
+ detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
+ detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
+ detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
+ detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
+ detailed->v_front_porch =
+ get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
+ detailed->v_sync =
+ get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
+ detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
+ detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
+ detailed->right_border = timing[0x0f];
+ detailed->top_border = timing[0x10];
+
+ detailed->interlaced = get_bit (timing[0x11], 7);
+
+ /* Stereo */
+ bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
+ detailed->stereo = stereo[bits];
+
+ /* Sync */
+ bits = timing[0x11];
+
+ detailed->digital_sync = get_bit (bits, 4);
+ if (detailed->digital_sync)
+ {
+ detailed->connector.digital.composite = !get_bit (bits, 3);
+
+ if (detailed->connector.digital.composite)
+ {
+ detailed->connector.digital.serrations = get_bit (bits, 2);
+ detailed->connector.digital.negative_vsync = FALSE;
+ }
+ else
+ {
+ detailed->connector.digital.serrations = FALSE;
+ detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
+ }
+
+ detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
+ }
+ else
+ {
+ detailed->connector.analog.bipolar = get_bit (bits, 3);
+ detailed->connector.analog.serrations = get_bit (bits, 2);
+ detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
+ }
+}
+
+static int
+decode_descriptors (const uchar *edid, MonitorInfo *info)
+{
+ int i;
+ int timing_idx;
+
+ timing_idx = 0;
+
+ for (i = 0; i < 4; ++i)
+ {
+ int 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 = g_new0 (MonitorInfo, 1);
+
+ decode_check_sum (edid, info);
+
+ if (decode_header (edid)
+ && decode_vendor_and_product_identification (edid, info)
+ && decode_edid_version (edid, info)
+ && decode_display_parameters (edid, info)
+ && decode_color_characteristics (edid, info)
+ && decode_established_timings (edid, info)
+ && decode_standard_timings (edid, info)
+ && decode_descriptors (edid, info))
+ {
+ return info;
+ }
+ else
+ {
+ g_free (info);
+ return NULL;
+ }
+}
diff --git a/gnome-flashback/libdisplay-config/edid.h b/gnome-flashback/libdisplay-config/edid.h
new file mode 100644
index 0000000..37f2be7
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/edid.h
@@ -0,0 +1,191 @@
+/* edid.h
+ *
+ * Copyright 2007, 2008, Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Soren Sandmann <sandmann redhat com>
+ */
+
+#ifndef EDID_H
+#define EDID_H
+
+typedef unsigned char uchar;
+typedef struct MonitorInfo MonitorInfo;
+typedef struct Timing Timing;
+typedef struct DetailedTiming DetailedTiming;
+
+typedef enum
+{
+ UNDEFINED,
+ DVI,
+ HDMI_A,
+ HDMI_B,
+ MDDI,
+ DISPLAY_PORT
+} Interface;
+
+typedef enum
+{
+ UNDEFINED_COLOR,
+ MONOCHROME,
+ RGB,
+ OTHER_COLOR
+} ColorType;
+
+typedef enum
+{
+ NO_STEREO,
+ FIELD_RIGHT,
+ FIELD_LEFT,
+ TWO_WAY_RIGHT_ON_EVEN,
+ TWO_WAY_LEFT_ON_EVEN,
+ FOUR_WAY_INTERLEAVED,
+ SIDE_BY_SIDE
+} StereoType;
+
+struct Timing
+{
+ int width;
+ int height;
+ int frequency;
+};
+
+struct DetailedTiming
+{
+ int pixel_clock;
+ int h_addr;
+ int h_blank;
+ int h_sync;
+ int h_front_porch;
+ int v_addr;
+ int v_blank;
+ int v_sync;
+ int v_front_porch;
+ int width_mm;
+ int height_mm;
+ int right_border;
+ int top_border;
+ int interlaced;
+ StereoType stereo;
+
+ int digital_sync;
+ union
+ {
+ struct
+ {
+ int bipolar;
+ int serrations;
+ int sync_on_green;
+ } analog;
+
+ struct
+ {
+ int composite;
+ int serrations;
+ int negative_vsync;
+ int negative_hsync;
+ } digital;
+ } connector;
+};
+
+struct MonitorInfo
+{
+ int checksum;
+ char manufacturer_code[4];
+ int product_code;
+ unsigned int serial_number;
+
+ int production_week; /* -1 if not specified */
+ int production_year; /* -1 if not specified */
+ int model_year; /* -1 if not specified */
+
+ int major_version;
+ int minor_version;
+
+ int is_digital;
+
+ union
+ {
+ struct
+ {
+ int bits_per_primary;
+ Interface interface;
+ int rgb444;
+ int ycrcb444;
+ int ycrcb422;
+ } digital;
+
+ struct
+ {
+ double video_signal_level;
+ double sync_signal_level;
+ double total_signal_level;
+
+ int blank_to_black;
+
+ int separate_hv_sync;
+ int composite_sync_on_h;
+ int composite_sync_on_green;
+ int serration_on_vsync;
+ ColorType color_type;
+ } analog;
+ } connector;
+
+ int width_mm; /* -1 if not specified */
+ int height_mm; /* -1 if not specified */
+ double aspect_ratio; /* -1.0 if not specififed */
+
+ double gamma; /* -1.0 if not specified */
+
+ int standby;
+ int suspend;
+ int active_off;
+
+ int srgb_is_standard;
+ int preferred_timing_includes_native;
+ int continuous_frequency;
+
+ double red_x;
+ double red_y;
+ double green_x;
+ double green_y;
+ double blue_x;
+ double blue_y;
+ double white_x;
+ double white_y;
+
+ Timing established[24]; /* Terminated by 0x0x0 */
+ Timing standard[8];
+
+ int n_detailed_timings;
+ DetailedTiming detailed_timings[4]; /* If monitor has a preferred
+ * mode, it is the first one
+ * (whether it has, is
+ * determined by the
+ * preferred_timing_includes
+ * bit.
+ */
+
+ /* Optional product description */
+ char dsc_serial_number[14];
+ char dsc_product_name[14];
+ char dsc_string[14]; /* Unspecified ASCII data */
+};
+
+MonitorInfo *decode_edid (const uchar *data);
+
+#endif
diff --git a/gnome-flashback/libdisplay-config/flashback-display-config.c
b/gnome-flashback/libdisplay-config/flashback-display-config.c
index 2db195e..8a5563b 100644
--- a/gnome-flashback/libdisplay-config/flashback-display-config.c
+++ b/gnome-flashback/libdisplay-config/flashback-display-config.c
@@ -46,6 +46,33 @@ G_DEFINE_TYPE (FlashbackDisplayConfig, flashback_display_config, G_TYPE_OBJECT)
static const double known_diagonals[] = { 12.1, 13.3, 15.6 };
+static void
+power_save_mode_changed (MetaDBusDisplayConfig *skeleton,
+ gpointer user_data)
+{
+ FlashbackDisplayConfig *config;
+ FlashbackMonitorManager *manager;
+ int mode;
+
+ config = FLASHBACK_DISPLAY_CONFIG (user_data);
+ manager = config->manager;
+
+ mode = meta_dbus_display_config_get_power_save_mode (skeleton);
+
+ if (mode == META_POWER_SAVE_UNSUPPORTED)
+ return;
+
+ /* If DPMS is unsupported, force the property back. */
+ if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED)
+ {
+ meta_dbus_display_config_set_power_save_mode (META_DBUS_DISPLAY_CONFIG (manager),
META_POWER_SAVE_UNSUPPORTED);
+ return;
+ }
+
+ flashback_monitor_manager_set_power_save_mode (manager, mode);
+ manager->power_save_mode = mode;
+}
+
static gboolean
save_config_timeout (gpointer user_data)
{
@@ -273,7 +300,6 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton,
GVariantBuilder clones;
GVariantBuilder properties;
GBytes *edid;
- char *edid_file;
output = &manager->outputs[i];
@@ -317,23 +343,14 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_builder_add (&properties, "{sv}", "connector-type",
g_variant_new_string (get_connector_type_name (output->connector_type)));
- edid_file = flashback_monitor_manager_get_edid_file (manager, output);
- if (edid_file)
- {
- g_variant_builder_add (&properties, "{sv}", "edid-file",
- g_variant_new_take_string (edid_file));
- }
- else
- {
- edid = flashback_monitor_manager_read_edid (manager, output);
+ edid = flashback_monitor_manager_read_edid (manager, output);
- if (edid)
- {
- g_variant_builder_add (&properties, "{sv}", "edid",
- g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
- edid, TRUE));
- g_bytes_unref (edid);
- }
+ if (edid)
+ {
+ g_variant_builder_add (&properties, "{sv}", "edid",
+ g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
+ edid, TRUE));
+ g_bytes_unref (edid);
}
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
@@ -837,6 +854,9 @@ on_bus_acquired (GDBusConnection *connection,
g_signal_connect (skeleton, "handle-set-crtc-gamma",
G_CALLBACK (handle_set_crtc_gamma), config);
+ g_signal_connect (skeleton, "notify::power-save-mode",
+ G_CALLBACK (power_save_mode_changed), config);
+
config->iface = G_DBUS_INTERFACE_SKELETON (skeleton);
error = NULL;
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-config.c
b/gnome-flashback/libdisplay-config/flashback-monitor-config.c
index dde6f0d..aeaa894 100644
--- a/gnome-flashback/libdisplay-config/flashback-monitor-config.c
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-config.c
@@ -60,6 +60,18 @@ flashback_monitor_config_new (void)
NULL);
}
+gboolean
+flashback_monitor_config_apply_stored (FlashbackMonitorConfig *config,
+ FlashbackMonitorManager *manager)
+{
+}
+
+void
+flashback_monitor_config_make_default (FlashbackMonitorConfig *config,
+ FlashbackMonitorManager *manager)
+{
+}
+
void
flashback_monitor_config_update_current (FlashbackMonitorConfig *config,
FlashbackMonitorManager *manager)
@@ -67,6 +79,11 @@ flashback_monitor_config_update_current (FlashbackMonitorConfig *config,
}
void
+flashback_monitor_config_make_persistent (FlashbackMonitorConfig *config)
+{
+}
+
+void
flashback_monitor_config_restore_previous (FlashbackMonitorConfig *config,
FlashbackMonitorManager *manager)
{
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-config.h
b/gnome-flashback/libdisplay-config/flashback-monitor-config.h
index cf4d109..933995c 100644
--- a/gnome-flashback/libdisplay-config/flashback-monitor-config.h
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-config.h
@@ -36,8 +36,15 @@ G_DECLARE_FINAL_TYPE (FlashbackMonitorConfig, flashback_monitor_config,
FlashbackMonitorConfig *flashback_monitor_config_new (void);
+gboolean flashback_monitor_config_apply_stored (FlashbackMonitorConfig *config,
+ FlashbackMonitorManager *manager);
+
+void flashback_monitor_config_make_default (FlashbackMonitorConfig *config,
+ FlashbackMonitorManager *manager);
+
void flashback_monitor_config_update_current (FlashbackMonitorConfig *config,
FlashbackMonitorManager *manager);
+void flashback_monitor_config_make_persistent (FlashbackMonitorConfig *config);
void flashback_monitor_config_restore_previous (FlashbackMonitorConfig *config,
FlashbackMonitorManager *manager);
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-manager.c
b/gnome-flashback/libdisplay-config/flashback-monitor-manager.c
index 6e35307..4b29618 100644
--- a/gnome-flashback/libdisplay-config/flashback-monitor-manager.c
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-manager.c
@@ -23,16 +23,1017 @@
*
* Adapted from mutter 3.16.0:
* - /src/backends/meta-monitor-manager.c
+ * - /src/backends/x11/meta-monitor-manager-xrandr.c
*/
#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gdk/gdkx.h>
+#include <math.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/dpms.h>
+#include <X11/Xlib-xcb.h>
+#include <xcb/randr.h>
+#include "edid.h"
+#include "flashback-monitor-config.h"
#include "flashback-monitor-manager.h"
-G_DEFINE_TYPE (FlashbackMonitorManager, flashback_monitor_manager, G_TYPE_OBJECT)
+#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
+
+/* Look for DPI_FALLBACK in:
+ * http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
+ * for the reasoning */
+#define DPI_FALLBACK 96.0
+
+struct _FlashbackMonitorManagerPrivate
+{
+ Display *xdisplay;
+ XRRScreenResources *resources;
+ int rr_event_base;
+ int rr_error_base;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (FlashbackMonitorManager, flashback_monitor_manager, G_TYPE_OBJECT)
+
+static Rotation
+meta_monitor_transform_to_xrandr (MetaMonitorTransform transform)
+{
+ switch (transform)
+ {
+ case META_MONITOR_TRANSFORM_NORMAL:
+ return RR_Rotate_0;
+ case META_MONITOR_TRANSFORM_90:
+ return RR_Rotate_90;
+ case META_MONITOR_TRANSFORM_180:
+ return RR_Rotate_180;
+ case META_MONITOR_TRANSFORM_270:
+ return RR_Rotate_270;
+ case META_MONITOR_TRANSFORM_FLIPPED:
+ return RR_Reflect_X | RR_Rotate_0;
+ case META_MONITOR_TRANSFORM_FLIPPED_90:
+ return RR_Reflect_X | RR_Rotate_90;
+ case META_MONITOR_TRANSFORM_FLIPPED_180:
+ return RR_Reflect_X | RR_Rotate_180;
+ case META_MONITOR_TRANSFORM_FLIPPED_270:
+ return RR_Reflect_X | RR_Rotate_270;
+ }
+
+ g_assert_not_reached ();
+}
+
+static MetaMonitorTransform
+meta_monitor_transform_from_xrandr (Rotation rotation)
+{
+ static const MetaMonitorTransform y_reflected_map[4] = {
+ META_MONITOR_TRANSFORM_FLIPPED_180,
+ META_MONITOR_TRANSFORM_FLIPPED_90,
+ META_MONITOR_TRANSFORM_FLIPPED,
+ META_MONITOR_TRANSFORM_FLIPPED_270
+ };
+ MetaMonitorTransform ret;
+
+ switch (rotation & 0x7F)
+ {
+ default:
+ case RR_Rotate_0:
+ ret = META_MONITOR_TRANSFORM_NORMAL;
+ break;
+ case RR_Rotate_90:
+ ret = META_MONITOR_TRANSFORM_90;
+ break;
+ case RR_Rotate_180:
+ ret = META_MONITOR_TRANSFORM_180;
+ break;
+ case RR_Rotate_270:
+ ret = META_MONITOR_TRANSFORM_270;
+ break;
+ }
+
+ if (rotation & RR_Reflect_X)
+ return ret + 4;
+ else if (rotation & RR_Reflect_Y)
+ return y_reflected_map[ret];
+ else
+ return ret;
+}
+
+#define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)
+
+static MetaMonitorTransform
+meta_monitor_transform_from_xrandr_all (Rotation rotation)
+{
+ unsigned ret;
+
+ /* Handle the common cases first (none or all) */
+ if (rotation == 0 || rotation == RR_Rotate_0)
+ return (1 << META_MONITOR_TRANSFORM_NORMAL);
+
+ /* All rotations and one reflection -> all of them by composition */
+ if ((rotation & ALL_ROTATIONS) &&
+ ((rotation & RR_Reflect_X) || (rotation & RR_Reflect_Y)))
+ return ALL_TRANSFORMS;
+
+ ret = 1 << META_MONITOR_TRANSFORM_NORMAL;
+ if (rotation & RR_Rotate_90)
+ ret |= 1 << META_MONITOR_TRANSFORM_90;
+ if (rotation & RR_Rotate_180)
+ ret |= 1 << META_MONITOR_TRANSFORM_180;
+ if (rotation & RR_Rotate_270)
+ ret |= 1 << META_MONITOR_TRANSFORM_270;
+ if (rotation & (RR_Rotate_0 | RR_Reflect_X))
+ ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED;
+ if (rotation & (RR_Rotate_90 | RR_Reflect_X))
+ ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED_90;
+ if (rotation & (RR_Rotate_180 | RR_Reflect_X))
+ ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED_180;
+ if (rotation & (RR_Rotate_270 | RR_Reflect_X))
+ ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED_270;
+
+ return ret;
+}
+
+static gboolean
+output_get_integer_property (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output,
+ const char *propname,
+ gint *value)
+{
+ gboolean exists = FALSE;
+ Atom atom, actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *buffer;
+
+ atom = XInternAtom (priv->xdisplay, propname, False);
+ XRRGetOutputProperty (priv->xdisplay,
+ (XID) output->winsys_id,
+ atom,
+ 0, G_MAXLONG, False, False, XA_INTEGER,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &buffer);
+
+ exists = (actual_type == XA_INTEGER && actual_format == 32 && nitems == 1);
+
+ if (exists && value != NULL)
+ *value = ((int*)buffer)[0];
+
+ XFree (buffer);
+ return exists;
+}
+
+static gboolean
+output_get_property_exists (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output,
+ const char *propname)
+{
+ gboolean exists = FALSE;
+ Atom atom, actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *buffer;
+
+ atom = XInternAtom (priv->xdisplay, propname, False);
+ XRRGetOutputProperty (priv->xdisplay,
+ (XID)output->winsys_id,
+ atom,
+ 0, G_MAXLONG, False, False, AnyPropertyType,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &buffer);
+
+ exists = (actual_type != None);
+
+ XFree (buffer);
+ return exists;
+}
+
+static gboolean
+output_get_boolean_property (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output,
+ const char *propname)
+{
+ gboolean value = FALSE;
+ Atom atom, actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *buffer;
+
+ atom = XInternAtom (priv->xdisplay, propname, False);
+ XRRGetOutputProperty (priv->xdisplay,
+ (XID) output->winsys_id,
+ atom,
+ 0, G_MAXLONG, False, False, XA_CARDINAL,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &buffer);
+
+ if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1)
+ goto out;
+
+ value = ((int*)buffer)[0];
+
+ out:
+ XFree (buffer);
+ return value;
+}
+
+static gboolean
+output_get_presentation_xrandr (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ return output_get_boolean_property (priv, output, "_GNOME_FLASHBACK_PRESENTATION_OUTPUT");
+}
+
+static void
+output_set_presentation_xrandr (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output,
+ gboolean presentation)
+{
+ Atom atom;
+ int value;
+
+ value = presentation;
+ atom = XInternAtom (priv->xdisplay, "_GNOME_FLASHBACK_PRESENTATION_OUTPUT", False);
+ XRRChangeOutputProperty (priv->xdisplay,
+ (XID) output->winsys_id,
+ atom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char*) &value, 1);
+}
+
+static int
+normalize_backlight (MetaOutput *output,
+ int hw_value)
+{
+ return round ((double)(hw_value - output->backlight_min) /
+ (output->backlight_max - output->backlight_min) * 100.0);
+}
+
+static int
+output_get_backlight_xrandr (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ int value = -1;
+ Atom atom, actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *buffer;
+
+ atom = XInternAtom (priv->xdisplay, "Backlight", False);
+ XRRGetOutputProperty (priv->xdisplay,
+ (XID) output->winsys_id,
+ atom,
+ 0, G_MAXLONG, False, False, XA_INTEGER,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &buffer);
+
+ if (actual_type != XA_INTEGER || actual_format != 32 || nitems < 1)
+ goto out;
+
+ value = ((int*)buffer)[0];
+
+ out:
+ XFree (buffer);
+ if (value > 0)
+ return normalize_backlight (output, value);
+ else
+ return -1;
+}
+
+static void
+output_get_backlight_limits_xrandr (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ Atom atom;
+ xcb_connection_t *xcb_conn;
+ xcb_randr_query_output_property_reply_t *reply;
+
+ atom = XInternAtom (priv->xdisplay, "Backlight", False);
+
+ xcb_conn = XGetXCBConnection (priv->xdisplay);
+ reply = xcb_randr_query_output_property_reply (xcb_conn,
+ xcb_randr_query_output_property (xcb_conn,
+ (xcb_randr_output_t)
output->winsys_id,
+ (xcb_atom_t) atom),
+ NULL);
+
+ /* This can happen on systems without backlights. */
+ if (reply == NULL)
+ return;
+
+ if (!reply->range || reply->length != 2)
+ {
+ g_warning ("backlight %s was not range\n", output->name);
+ goto out;
+ }
+
+ int32_t *values = xcb_randr_query_output_property_valid_values (reply);
+ output->backlight_min = values[0];
+ output->backlight_max = values[1];
+
+out:
+ free (reply);
+}
+
+static gboolean
+output_get_hotplug_mode_update (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ return output_get_property_exists (priv, output, "hotplug_mode_update");
+}
+
+static gint
+output_get_suggested_x (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ gint val;
+ if (output_get_integer_property (priv, output, "suggested X", &val))
+ return val;
+
+ return -1;
+}
+
+static gint
+output_get_suggested_y (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ gint val;
+ if (output_get_integer_property (priv, output, "suggested Y", &val))
+ return val;
+
+ return -1;
+}
+
+static MetaConnectorType
+connector_type_from_atom (FlashbackMonitorManagerPrivate *priv,
+ Atom atom)
+{
+ Display *xdpy = priv->xdisplay;
+
+ if (atom == XInternAtom (xdpy, "HDMI", True))
+ return META_CONNECTOR_TYPE_HDMIA;
+ if (atom == XInternAtom (xdpy, "VGA", True))
+ return META_CONNECTOR_TYPE_VGA;
+ /* Doesn't have a DRM equivalent, but means an internal panel.
+ * We could pick either LVDS or eDP here. */
+ if (atom == XInternAtom (xdpy, "Panel", True))
+ return META_CONNECTOR_TYPE_LVDS;
+ if (atom == XInternAtom (xdpy, "DVI", True) || atom == XInternAtom (xdpy, "DVI-I", True))
+ return META_CONNECTOR_TYPE_DVII;
+ if (atom == XInternAtom (xdpy, "DVI-A", True))
+ return META_CONNECTOR_TYPE_DVIA;
+ if (atom == XInternAtom (xdpy, "DVI-D", True))
+ return META_CONNECTOR_TYPE_DVID;
+ if (atom == XInternAtom (xdpy, "DisplayPort", True))
+ return META_CONNECTOR_TYPE_DisplayPort;
+
+ if (atom == XInternAtom (xdpy, "TV", True))
+ return META_CONNECTOR_TYPE_TV;
+ if (atom == XInternAtom (xdpy, "TV-Composite", True))
+ return META_CONNECTOR_TYPE_Composite;
+ if (atom == XInternAtom (xdpy, "TV-SVideo", True))
+ return META_CONNECTOR_TYPE_SVIDEO;
+ /* Another set of mismatches. */
+ if (atom == XInternAtom (xdpy, "TV-SCART", True))
+ return META_CONNECTOR_TYPE_TV;
+ if (atom == XInternAtom (xdpy, "TV-C4", True))
+ return META_CONNECTOR_TYPE_TV;
+
+ return META_CONNECTOR_TYPE_Unknown;
+}
+
+static MetaConnectorType
+output_get_connector_type_from_prop (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ MetaConnectorType ret = META_CONNECTOR_TYPE_Unknown;
+ Atom atom, actual_type, connector_type_atom;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *buffer;
+
+ atom = XInternAtom (priv->xdisplay, "ConnectorType", False);
+ XRRGetOutputProperty (priv->xdisplay,
+ (XID) output->winsys_id,
+ atom,
+ 0, G_MAXLONG, False, False, XA_ATOM,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &buffer);
+
+ if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
+ goto out;
+
+ connector_type_atom = ((Atom *) buffer)[0];
+ ret = connector_type_from_atom (priv, connector_type_atom);
+
+ out:
+ if (buffer)
+ XFree (buffer);
+ return ret;
+}
+
+static MetaConnectorType
+output_get_connector_type_from_name (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ const char *name = output->name;
+
+ /* drmmode_display.c, which was copy/pasted across all the FOSS
+ * xf86-video-* drivers, seems to name its outputs based on the
+ * connector type, so look for that....
+ *
+ * SNA has its own naming scheme, because what else did you expect
+ * from SNA, but it's not too different, so we can thankfully use
+ * that with minor changes.
+ *
+ * http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesetting/drmmode_display.c#n953
+ * http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/sna/sna_display.c#n3486
+ */
+
+ if (g_str_has_prefix (name, "DVI"))
+ return META_CONNECTOR_TYPE_DVII;
+ if (g_str_has_prefix (name, "LVDS"))
+ return META_CONNECTOR_TYPE_LVDS;
+ if (g_str_has_prefix (name, "HDMI"))
+ return META_CONNECTOR_TYPE_HDMIA;
+ if (g_str_has_prefix (name, "VGA"))
+ return META_CONNECTOR_TYPE_VGA;
+ /* SNA uses DP, not DisplayPort. Test for both. */
+ if (g_str_has_prefix (name, "DP") || g_str_has_prefix (name, "DisplayPort"))
+ return META_CONNECTOR_TYPE_DisplayPort;
+ if (g_str_has_prefix (name, "eDP"))
+ return META_CONNECTOR_TYPE_eDP;
+ if (g_str_has_prefix (name, "Virtual"))
+ return META_CONNECTOR_TYPE_VIRTUAL;
+ if (g_str_has_prefix (name, "Composite"))
+ return META_CONNECTOR_TYPE_VGA;
+ if (g_str_has_prefix (name, "S-video"))
+ return META_CONNECTOR_TYPE_SVIDEO;
+ if (g_str_has_prefix (name, "TV"))
+ return META_CONNECTOR_TYPE_TV;
+ if (g_str_has_prefix (name, "CTV"))
+ return META_CONNECTOR_TYPE_Composite;
+ if (g_str_has_prefix (name, "DSI"))
+ return META_CONNECTOR_TYPE_DSI;
+ if (g_str_has_prefix (name, "DIN"))
+ return META_CONNECTOR_TYPE_9PinDIN;
+
+ return META_CONNECTOR_TYPE_Unknown;
+}
+
+static MetaConnectorType
+output_get_connector_type (FlashbackMonitorManagerPrivate *priv,
+ MetaOutput *output)
+{
+ MetaConnectorType ret;
+
+ /* The "ConnectorType" property is considered mandatory since RandR 1.3,
+ * but none of the FOSS drivers support it, because we're a bunch of
+ * professional software developers.
+ *
+ * Try poking it first, without any expectations that it will work.
+ * If it's not there, we thankfully have other bonghits to try next.
+ */
+ ret = output_get_connector_type_from_prop (priv, output);
+ if (ret != META_CONNECTOR_TYPE_Unknown)
+ return ret;
+
+ /* Fall back to heuristics based on the output name. */
+ ret = output_get_connector_type_from_name (priv, output);
+ if (ret != META_CONNECTOR_TYPE_Unknown)
+ return ret;
+
+ return META_CONNECTOR_TYPE_Unknown;
+}
+
+static int
+compare_outputs (const void *one,
+ const void *two)
+{
+ const MetaOutput *o_one = one, *o_two = two;
+
+ return strcmp (o_one->name, o_two->name);
+}
+
+static char *
+get_xmode_name (XRRModeInfo *xmode)
+{
+ int width = xmode->width;
+ int height = xmode->height;
+
+ return g_strdup_printf ("%dx%d", width, height);
+}
+
+static gboolean
+gdk_rectangle_equal (const GdkRectangle *src1,
+ const GdkRectangle *src2)
+{
+ return ((src1->x == src2->x) && (src1->y == src2->y) &&
+ (src1->width == src2->width) && (src1->height == src2->height));
+}
+
+/*
+ * make_logical_config:
+ *
+ * Turn outputs and CRTCs into logical MetaMonitorInfo,
+ * that will be used by the core and API layer (MetaScreen
+ * and friends)
+ */
+static void
+make_logical_config (FlashbackMonitorManager *manager)
+{
+ GArray *monitor_infos;
+ unsigned int i, j;
+
+ monitor_infos = g_array_sized_new (FALSE, TRUE, sizeof (MetaMonitorInfo),
+ manager->n_outputs);
+
+ /* Walk the list of MetaCRTCs, and build a MetaMonitorInfo
+ for each of them, unless they reference a rectangle that
+ is already there.
+ */
+ for (i = 0; i < manager->n_crtcs; i++)
+ {
+ MetaCRTC *crtc = &manager->crtcs[i];
+
+ /* Ignore CRTCs not in use */
+ if (crtc->current_mode == NULL)
+ continue;
+
+ for (j = 0; j < monitor_infos->len; j++)
+ {
+ MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, j);
+ if (gdk_rectangle_equal (&crtc->rect, &info->rect))
+ {
+ crtc->logical_monitor = info;
+ break;
+ }
+ }
+
+ if (crtc->logical_monitor == NULL)
+ {
+ MetaMonitorInfo info;
+
+ info.number = monitor_infos->len;
+ info.rect = crtc->rect;
+ info.is_primary = FALSE;
+ /* This starts true because we want
+ is_presentation only if all outputs are
+ marked as such (while for primary it's enough
+ that any is marked)
+ */
+ info.is_presentation = TRUE;
+ info.in_fullscreen = -1;
+ info.winsys_id = 0;
+
+ g_array_append_val (monitor_infos, info);
+
+ crtc->logical_monitor = &g_array_index (monitor_infos, MetaMonitorInfo,
+ info.number);
+ }
+ }
+
+ /* Now walk the list of outputs applying extended properties (primary
+ and presentation)
+ */
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ MetaOutput *output;
+ MetaMonitorInfo *info;
+
+ output = &manager->outputs[i];
+
+ /* Ignore outputs that are not active */
+ if (output->crtc == NULL)
+ continue;
+
+ /* We must have a logical monitor on every CRTC at this point */
+ g_assert (output->crtc->logical_monitor != NULL);
+
+ info = output->crtc->logical_monitor;
+
+ info->is_primary = info->is_primary || output->is_primary;
+ info->is_presentation = info->is_presentation && output->is_presentation;
+
+ if (output->is_primary || info->winsys_id == 0)
+ info->winsys_id = output->winsys_id;
+
+ if (info->is_primary)
+ manager->primary_monitor_index = info->number;
+ }
+
+ manager->n_monitor_infos = monitor_infos->len;
+ manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
+}
+
+static void
+free_output_array (MetaOutput *old_outputs,
+ int n_old_outputs)
+{
+ int i;
+
+ for (i = 0; i < n_old_outputs; i++)
+ {
+ g_free (old_outputs[i].name);
+ g_free (old_outputs[i].vendor);
+ g_free (old_outputs[i].product);
+ g_free (old_outputs[i].serial);
+ g_free (old_outputs[i].modes);
+ g_free (old_outputs[i].possible_crtcs);
+ g_free (old_outputs[i].possible_clones);
+
+ if (old_outputs[i].driver_notify)
+ old_outputs[i].driver_notify (&old_outputs[i]);
+ }
+
+ g_free (old_outputs);
+}
+
+static void
+free_mode_array (MetaMonitorMode *old_modes,
+ int n_old_modes)
+{
+ int i;
+
+ for (i = 0; i < n_old_modes; i++)
+ {
+ g_free (old_modes[i].name);
+
+ if (old_modes[i].driver_notify)
+ old_modes[i].driver_notify (&old_modes[i]);
+ }
+
+ g_free (old_modes);
+}
+
+static guint8 *
+get_edid_property (Display *dpy,
+ RROutput output,
+ Atom atom,
+ gsize *len)
+{
+ unsigned char *prop;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long 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 GBytes *
+read_output_edid (FlashbackMonitorManager *manager,
+ XID winsys_id)
+{
+ Atom edid_atom;
+ guint8 *result;
+ gsize len;
+
+ edid_atom = XInternAtom (manager->priv->xdisplay, "EDID", FALSE);
+ result = get_edid_property (manager->priv->xdisplay, winsys_id, edid_atom, &len);
+
+ if (!result)
+ {
+ edid_atom = XInternAtom (manager->priv->xdisplay, "EDID_DATA", FALSE);
+ result = get_edid_property (manager->priv->xdisplay, winsys_id, edid_atom, &len);
+ }
+
+ if (!result)
+ {
+ edid_atom = XInternAtom (manager->priv->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE);
+ result = get_edid_property (manager->priv->xdisplay, winsys_id, edid_atom, &len);
+ }
+
+ if (result)
+ {
+ if (len > 0 && len % 128 == 0)
+ return g_bytes_new_take (result, len);
+ else
+ g_free (result);
+ }
+
+ return NULL;
+}
+
+static void
+read_current_config (FlashbackMonitorManager *manager)
+{
+ FlashbackMonitorManagerPrivate *priv;
+ XRRScreenResources *resources;
+ RROutput primary_output;
+ unsigned int i;
+ unsigned int j;
+ unsigned int k;
+ unsigned int n_actual_outputs;
+ int min_width;
+ int min_height;
+ Screen *screen;
+ BOOL dpms_capable;
+ BOOL dpms_enabled;
+ CARD16 dpms_state;
+
+ priv = manager->priv;
+
+ if (priv->resources)
+ XRRFreeScreenResources (priv->resources);
+ priv->resources = NULL;
+
+ dpms_capable = DPMSCapable (priv->xdisplay);
+
+ if (dpms_capable &&
+ DPMSInfo (priv->xdisplay, &dpms_state, &dpms_enabled) &&
+ dpms_enabled)
+ {
+ switch (dpms_state)
+ {
+ case DPMSModeOn:
+ manager->power_save_mode = META_POWER_SAVE_ON;
+ break;
+ case DPMSModeStandby:
+ manager->power_save_mode = META_POWER_SAVE_STANDBY;
+ break;
+ case DPMSModeSuspend:
+ manager->power_save_mode = META_POWER_SAVE_SUSPEND;
+ break;
+ case DPMSModeOff:
+ manager->power_save_mode = META_POWER_SAVE_OFF;
+ break;
+ default:
+ manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
+ break;
+ }
+ }
+ else
+ {
+ manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
+ }
+
+ XRRGetScreenSizeRange (priv->xdisplay, DefaultRootWindow (priv->xdisplay),
+ &min_width, &min_height,
+ &manager->max_screen_width,
+ &manager->max_screen_height);
+
+ screen = ScreenOfDisplay (priv->xdisplay, DefaultScreen (priv->xdisplay));
+
+ /* This is updated because we called RRUpdateConfiguration below */
+ manager->screen_width = WidthOfScreen (screen);
+ manager->screen_height = HeightOfScreen (screen);
+
+ resources = XRRGetScreenResourcesCurrent (priv->xdisplay, DefaultRootWindow (priv->xdisplay));
+ if (!resources)
+ return;
+
+ priv->resources = resources;
+ manager->n_outputs = resources->noutput;
+ manager->n_crtcs = resources->ncrtc;
+ manager->n_modes = resources->nmode;
+ manager->outputs = g_new0 (MetaOutput, manager->n_outputs);
+ manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
+ manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
+
+ for (i = 0; i < (unsigned) resources->nmode; i++)
+ {
+ XRRModeInfo *xmode = &resources->modes[i];
+ MetaMonitorMode *mode;
+
+ mode = &manager->modes[i];
+
+ mode->mode_id = xmode->id;
+ mode->width = xmode->width;
+ mode->height = xmode->height;
+ mode->refresh_rate = (xmode->dotClock / ((float)xmode->hTotal * xmode->vTotal));
+ mode->name = get_xmode_name (xmode);
+ }
+
+ for (i = 0; i < (unsigned) resources->ncrtc; i++)
+ {
+ XRRCrtcInfo *crtc;
+ MetaCRTC *meta_crtc;
+
+ crtc = XRRGetCrtcInfo (priv->xdisplay, resources, resources->crtcs[i]);
+
+ meta_crtc = &manager->crtcs[i];
+
+ meta_crtc->crtc_id = resources->crtcs[i];
+ meta_crtc->rect.x = crtc->x;
+ meta_crtc->rect.y = crtc->y;
+ meta_crtc->rect.width = crtc->width;
+ meta_crtc->rect.height = crtc->height;
+ meta_crtc->is_dirty = FALSE;
+ meta_crtc->transform = meta_monitor_transform_from_xrandr (crtc->rotation);
+ meta_crtc->all_transforms = meta_monitor_transform_from_xrandr_all (crtc->rotations);
+
+ for (j = 0; j < (unsigned) resources->nmode; j++)
+ {
+ if (resources->modes[j].id == crtc->mode)
+ {
+ meta_crtc->current_mode = &manager->modes[j];
+ break;
+ }
+ }
+
+ XRRFreeCrtcInfo (crtc);
+ }
+
+ primary_output = XRRGetOutputPrimary (priv->xdisplay, DefaultRootWindow (priv->xdisplay));
+
+ n_actual_outputs = 0;
+ for (i = 0; i < (unsigned) resources->noutput; i++)
+ {
+ XRROutputInfo *output;
+ MetaOutput *meta_output;
+
+ output = XRRGetOutputInfo (priv->xdisplay, resources, resources->outputs[i]);
+
+ meta_output = &manager->outputs[n_actual_outputs];
+
+ if (output->connection != RR_Disconnected)
+ {
+ GBytes *edid;
+
+ meta_output->winsys_id = resources->outputs[i];
+ meta_output->name = g_strdup (output->name);
+
+ edid = read_output_edid (manager, meta_output->winsys_id);
+ meta_output_parse_edid (meta_output, edid);
+ g_bytes_unref (edid);
+
+ meta_output->width_mm = output->mm_width;
+ meta_output->height_mm = output->mm_height;
+ meta_output->hotplug_mode_update = output_get_hotplug_mode_update (priv, meta_output);
+ meta_output->suggested_x = output_get_suggested_x (priv, meta_output);
+ meta_output->suggested_y = output_get_suggested_y (priv, meta_output);
+ meta_output->connector_type = output_get_connector_type (priv, meta_output);
+
+ meta_output->n_modes = output->nmode;
+ meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
+
+ for (j = 0; j < meta_output->n_modes; j++)
+ {
+ for (k = 0; k < manager->n_modes; k++)
+ {
+ if (output->modes[j] == (XID)manager->modes[k].mode_id)
+ {
+ meta_output->modes[j] = &manager->modes[k];
+ break;
+ }
+ }
+ }
+
+ meta_output->preferred_mode = meta_output->modes[0];
+
+ meta_output->n_possible_crtcs = output->ncrtc;
+ meta_output->possible_crtcs = g_new0 (MetaCRTC *, meta_output->n_possible_crtcs);
+
+ for (j = 0; j < (unsigned)output->ncrtc; j++)
+ {
+ for (k = 0; k < manager->n_crtcs; k++)
+ {
+ if ((XID)manager->crtcs[k].crtc_id == output->crtcs[j])
+ {
+ meta_output->possible_crtcs[j] = &manager->crtcs[k];
+ break;
+ }
+ }
+ }
+
+ meta_output->crtc = NULL;
+
+ for (j = 0; j < manager->n_crtcs; j++)
+ {
+ if ((XID)manager->crtcs[j].crtc_id == output->crtc)
+ {
+ meta_output->crtc = &manager->crtcs[j];
+ break;
+ }
+ }
+
+ meta_output->n_possible_clones = output->nclone;
+ meta_output->possible_clones = g_new0 (MetaOutput *, meta_output->n_possible_clones);
+ /* We can build the list of clones now, because we don't have the list of outputs
+ yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them
+ in a second pass
+ */
+ for (j = 0; j < (unsigned)output->nclone; j++)
+ {
+ meta_output->possible_clones[j] = GINT_TO_POINTER (output->clones[j]);
+ }
+
+ meta_output->is_primary = ((XID)meta_output->winsys_id == primary_output);
+ meta_output->is_presentation = output_get_presentation_xrandr (priv, meta_output);
+ output_get_backlight_limits_xrandr (priv, meta_output);
+
+ if (!(meta_output->backlight_min == 0 && meta_output->backlight_max == 0))
+ meta_output->backlight = output_get_backlight_xrandr (priv, meta_output);
+ else
+ meta_output->backlight = -1;
+
+ n_actual_outputs++;
+ }
+
+ XRRFreeOutputInfo (output);
+ }
+
+ manager->n_outputs = n_actual_outputs;
+
+ /* Sort the outputs for easier handling in MetaMonitorConfig */
+ qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
+
+ /* Now fix the clones */
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ MetaOutput *meta_output;
+
+ meta_output = &manager->outputs[i];
+
+ for (j = 0; j < meta_output->n_possible_clones; j++)
+ {
+ RROutput clone;
+
+ clone = GPOINTER_TO_INT (meta_output->possible_clones[j]);
+
+ for (k = 0; k < manager->n_outputs; k++)
+ {
+ if (clone == (XID)manager->outputs[k].winsys_id)
+ {
+ meta_output->possible_clones[j] = &manager->outputs[k];
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void
+flashback_monitor_manager_constructed (GObject *object)
+{
+ FlashbackMonitorManager *manager;
+
+ manager = FLASHBACK_MONITOR_MANAGER (object);
+
+ manager->in_init = TRUE;
+
+ manager->config = flashback_monitor_config_new ();
+
+ flashback_monitor_manager_read_current_config (manager);
+
+ if (!flashback_monitor_config_apply_stored (manager->config, manager))
+ flashback_monitor_config_make_default (manager->config, manager);
+
+ /* Under XRandR, we don't rebuild our data structures until we see
+ the RRScreenNotify event, but at least at startup we want to have
+ the right configuration immediately.
+
+ The other backends keep the data structures always updated,
+ so this is not needed.
+ */
+ flashback_monitor_manager_read_current_config (manager);
+
+ make_logical_config (manager);
+
+ manager->in_init = FALSE;
+}
static void
flashback_monitor_manager_finalize (GObject *object)
{
+ FlashbackMonitorManager *manager;
+
+ manager = FLASHBACK_MONITOR_MANAGER (object);
+
+ if (manager->priv->resources)
+ XRRFreeScreenResources (manager->priv->resources);
+ manager->priv->resources = NULL;
+
+ free_output_array (manager->outputs, manager->n_outputs);
+ free_mode_array (manager->modes, manager->n_modes);
+ g_free (manager->monitor_infos);
+ g_free (manager->crtcs);
+
G_OBJECT_CLASS (flashback_monitor_manager_parent_class)->finalize (object);
}
@@ -43,12 +1044,28 @@ flashback_monitor_manager_class_init (FlashbackMonitorManagerClass *manager_clas
object_class = G_OBJECT_CLASS (manager_class);
+ object_class->constructed = flashback_monitor_manager_constructed;
object_class->finalize = flashback_monitor_manager_finalize;
}
static void
flashback_monitor_manager_init (FlashbackMonitorManager *manager)
{
+ FlashbackMonitorManagerPrivate *priv;
+
+ priv = flashback_monitor_manager_get_instance_private (manager);
+ manager->priv = priv;
+
+ priv->xdisplay = gdk_x11_display_get_xdisplay (gdk_display_get_default ());
+
+ if (!XRRQueryExtension (priv->xdisplay, &priv->rr_event_base, &priv->rr_error_base))
+ return;
+
+ /* We only use ScreenChangeNotify, but GDK uses the others,
+ and we don't want to step on its toes */
+ XRRSelectInput (priv->xdisplay, DefaultRootWindow (priv->xdisplay),
+ RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask |
+ RROutputPropertyNotifyMask);
}
FlashbackMonitorManager *
@@ -65,6 +1082,220 @@ flashback_monitor_manager_apply_configuration (FlashbackMonitorManager *manager
MetaOutputInfo **outputs,
unsigned int n_outputs)
{
+ FlashbackMonitorManagerPrivate *priv;
+ unsigned i;
+ int width;
+ int height;
+ int width_mm;
+ int height_mm;
+
+ priv = manager->priv;
+
+ XGrabServer (priv->xdisplay);
+
+ /* First compute the new size of the screen (framebuffer) */
+ width = 0; height = 0;
+ for (i = 0; i < n_crtcs; i++)
+ {
+ MetaCRTCInfo *crtc_info = crtcs[i];
+ MetaCRTC *crtc = crtc_info->crtc;
+ crtc->is_dirty = TRUE;
+
+ if (crtc_info->mode == NULL)
+ continue;
+
+ if (crtc_info->transform % 2)
+ {
+ width = MAX (width, crtc_info->x + crtc_info->mode->height);
+ height = MAX (height, crtc_info->y + crtc_info->mode->width);
+ }
+ else
+ {
+ width = MAX (width, crtc_info->x + crtc_info->mode->width);
+ height = MAX (height, crtc_info->y + crtc_info->mode->height);
+ }
+ }
+
+ /* Second disable all newly disabled CRTCs, or CRTCs that in the previous
+ configuration would be outside the new framebuffer (otherwise X complains
+ loudly when resizing)
+ CRTC will be enabled again after resizing the FB
+ */
+ for (i = 0; i < n_crtcs; i++)
+ {
+ MetaCRTCInfo *crtc_info = crtcs[i];
+ MetaCRTC *crtc = crtc_info->crtc;
+
+ if (crtc_info->mode == NULL ||
+ crtc->rect.x + crtc->rect.width > width ||
+ crtc->rect.y + crtc->rect.height > height)
+ {
+ XRRSetCrtcConfig (priv->xdisplay,
+ priv->resources,
+ (XID) crtc->crtc_id,
+ CurrentTime,
+ 0, 0,
+ None,
+ RR_Rotate_0,
+ NULL, 0);
+
+ crtc->rect.x = 0;
+ crtc->rect.y = 0;
+ crtc->rect.width = 0;
+ crtc->rect.height = 0;
+ crtc->current_mode = NULL;
+ }
+ }
+
+ /* Disable CRTCs not mentioned in the list */
+ for (i = 0; i < manager->n_crtcs; i++)
+ {
+ MetaCRTC *crtc = &manager->crtcs[i];
+
+ if (crtc->is_dirty)
+ {
+ crtc->is_dirty = FALSE;
+ continue;
+ }
+ if (crtc->current_mode == NULL)
+ continue;
+
+ XRRSetCrtcConfig (priv->xdisplay,
+ priv->resources,
+ (XID) crtc->crtc_id,
+ CurrentTime,
+ 0, 0,
+ None,
+ RR_Rotate_0,
+ NULL, 0);
+
+ crtc->rect.x = 0;
+ crtc->rect.y = 0;
+ crtc->rect.width = 0;
+ crtc->rect.height = 0;
+ crtc->current_mode = NULL;
+ }
+
+ g_assert (width > 0 && height > 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 / DPI_FALLBACK) * 25.4 + 0.5;
+ height_mm = (height / DPI_FALLBACK) * 25.4 + 0.5;
+ XRRSetScreenSize (priv->xdisplay, DefaultRootWindow (priv->xdisplay),
+ width, height, width_mm, height_mm);
+
+ for (i = 0; i < n_crtcs; i++)
+ {
+ MetaCRTCInfo *crtc_info = crtcs[i];
+ MetaCRTC *crtc = crtc_info->crtc;
+
+ if (crtc_info->mode != NULL)
+ {
+ MetaMonitorMode *mode;
+ XID *outputs;
+ unsigned int j, n_outputs;
+ int width, height;
+ Status ok;
+
+ mode = crtc_info->mode;
+
+ n_outputs = crtc_info->outputs->len;
+ outputs = g_new (XID, n_outputs);
+
+ for (j = 0; j < n_outputs; j++)
+ {
+ MetaOutput *output;
+
+ output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
+
+ output->is_dirty = TRUE;
+ output->crtc = crtc;
+
+ outputs[j] = output->winsys_id;
+ }
+
+ ok = XRRSetCrtcConfig (priv->xdisplay,
+ priv->resources,
+ (XID) crtc->crtc_id,
+ CurrentTime,
+ crtc_info->x, crtc_info->y,
+ (XID) mode->mode_id,
+ meta_monitor_transform_to_xrandr (crtc_info->transform),
+ outputs, n_outputs);
+
+ if (ok != Success)
+ {
+ g_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transform
%u failed\n",
+ (unsigned) (crtc->crtc_id), (unsigned) (mode->mode_id),
+ mode->width, mode->height, (float) mode->refresh_rate,
+ crtc_info->x, crtc_info->y, crtc_info->transform);
+ goto next;
+ }
+
+ if (crtc_info->transform % 2)
+ {
+ width = mode->height;
+ height = mode->width;
+ }
+ else
+ {
+ width = mode->width;
+ height = mode->height;
+ }
+
+ crtc->rect.x = crtc_info->x;
+ crtc->rect.y = crtc_info->y;
+ crtc->rect.width = width;
+ crtc->rect.height = height;
+ crtc->current_mode = mode;
+ crtc->transform = crtc_info->transform;
+
+ next:
+ g_free (outputs);
+ }
+ }
+
+ for (i = 0; i < n_outputs; i++)
+ {
+ MetaOutputInfo *output_info = outputs[i];
+ MetaOutput *output = output_info->output;
+
+ if (output_info->is_primary)
+ {
+ XRRSetOutputPrimary (priv->xdisplay,
+ DefaultRootWindow (priv->xdisplay),
+ (XID)output_info->output->winsys_id);
+ }
+
+ output_set_presentation_xrandr (priv,
+ output_info->output,
+ output_info->is_presentation);
+
+ output->is_primary = output_info->is_primary;
+ output->is_presentation = output_info->is_presentation;
+ }
+
+ /* Disable outputs not mentioned in the list */
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ MetaOutput *output = &manager->outputs[i];
+
+ if (output->is_dirty)
+ {
+ output->is_dirty = FALSE;
+ continue;
+ }
+
+ output->crtc = NULL;
+ output->is_primary = FALSE;
+ }
+
+ XUngrabServer (priv->xdisplay);
+ XFlush (priv->xdisplay);
}
void
@@ -72,6 +1303,22 @@ flashback_monitor_manager_change_backlight (FlashbackMonitorManager *manager,
MetaOutput *output,
gint value)
{
+ FlashbackMonitorManagerPrivate *priv;
+ Atom atom;
+ int hw_value;
+
+ priv = manager->priv;
+ hw_value = round ((double)value / 100.0 * output->backlight_max + output->backlight_min);
+
+ atom = XInternAtom (priv->xdisplay, "Backlight", False);
+ XRRChangeOutputProperty (priv->xdisplay,
+ (XID) output->winsys_id,
+ atom,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *) &hw_value, 1);
+
+ /* We're not selecting for property notifies, so update the value immediately */
+ output->backlight = normalize_backlight (output, hw_value);
}
void
@@ -82,10 +1329,16 @@ flashback_monitor_manager_get_crtc_gamma (FlashbackMonitorManager *manager,
unsigned short **green,
unsigned short **blue)
{
- *size = 0;
- *red = NULL;
- *green = NULL;
- *blue = NULL;
+ XRRCrtcGamma *gamma;
+
+ gamma = XRRGetCrtcGamma (manager->priv->xdisplay, (XID) crtc->crtc_id);
+
+ *size = gamma->size;
+ *red = g_memdup (gamma->red, sizeof (unsigned short) * gamma->size);
+ *green = g_memdup (gamma->green, sizeof (unsigned short) * gamma->size);
+ *blue = g_memdup (gamma->blue, sizeof (unsigned short) * gamma->size);
+
+ XRRFreeGamma (gamma);
}
void
@@ -96,18 +1349,112 @@ flashback_monitor_manager_set_crtc_gamma (FlashbackMonitorManager *manager,
unsigned short *green,
unsigned short *blue)
{
+ XRRCrtcGamma *gamma;
+
+ gamma = XRRAllocGamma (size);
+ memcpy (gamma->red, red, sizeof (unsigned short) * size);
+ memcpy (gamma->green, green, sizeof (unsigned short) * size);
+ memcpy (gamma->blue, blue, sizeof (unsigned short) * size);
+
+ XRRSetCrtcGamma (manager->priv->xdisplay, (XID) crtc->crtc_id, gamma);
+
+ XRRFreeGamma (gamma);
}
-char *
-flashback_monitor_manager_get_edid_file (FlashbackMonitorManager *manager,
- MetaOutput *output)
+void
+flashback_monitor_manager_set_power_save_mode (FlashbackMonitorManager *manager,
+ MetaPowerSave mode)
{
- return NULL;
+ CARD16 state;
+
+ switch (mode)
+ {
+ case META_POWER_SAVE_ON:
+ state = DPMSModeOn;
+ break;
+ case META_POWER_SAVE_STANDBY:
+ state = DPMSModeStandby;
+ break;
+ case META_POWER_SAVE_SUSPEND:
+ state = DPMSModeSuspend;
+ break;
+ case META_POWER_SAVE_OFF:
+ state = DPMSModeOff;
+ break;
+ default:
+ return;
+ }
+
+ DPMSForceLevel (manager->priv->xdisplay, state);
+ DPMSSetTimeouts (manager->priv->xdisplay, 0, 0, 0);
}
GBytes *
flashback_monitor_manager_read_edid (FlashbackMonitorManager *manager,
MetaOutput *output)
{
- return NULL;
+ return read_output_edid (manager, output->winsys_id);
+}
+
+void
+flashback_monitor_manager_read_current_config (FlashbackMonitorManager *manager)
+{
+ MetaOutput *old_outputs;
+ MetaCRTC *old_crtcs;
+ MetaMonitorMode *old_modes;
+ unsigned int n_old_outputs;
+ unsigned int n_old_modes;
+
+ /* Some implementations of read_current use the existing information
+ * we have available, so don't free the old configuration until after
+ * read_current finishes. */
+ old_outputs = manager->outputs;
+ n_old_outputs = manager->n_outputs;
+ old_modes = manager->modes;
+ n_old_modes = manager->n_modes;
+ old_crtcs = manager->crtcs;
+
+ manager->serial++;
+
+ read_current_config (manager);
+
+ free_output_array (old_outputs, n_old_outputs);
+ free_mode_array (old_modes, n_old_modes);
+ g_free (old_crtcs);
+}
+
+void
+meta_output_parse_edid (MetaOutput *meta_output,
+ GBytes *edid)
+{
+ MonitorInfo *parsed_edid;
+ gsize len;
+
+ if (!edid)
+ goto out;
+
+ parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
+
+ if (parsed_edid)
+ {
+ meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
+ if (parsed_edid->dsc_product_name[0])
+ meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14);
+ else
+ meta_output->product = g_strdup_printf ("0x%04x", (unsigned) parsed_edid->product_code);
+ if (parsed_edid->dsc_serial_number[0])
+ meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
+ else
+ meta_output->serial = g_strdup_printf ("0x%08x", parsed_edid->serial_number);
+
+ g_free (parsed_edid);
+ }
+
+ out:
+ if (!meta_output->vendor)
+ {
+ meta_output->vendor = g_strdup ("unknown");
+ meta_output->product = g_strdup ("unknown");
+ meta_output->serial = g_strdup ("unknown");
+ }
}
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-manager.h
b/gnome-flashback/libdisplay-config/flashback-monitor-manager.h
index 30f12c0..398671c 100644
--- a/gnome-flashback/libdisplay-config/flashback-monitor-manager.h
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-manager.h
@@ -28,6 +28,7 @@
#include <glib-object.h>
#include <gdk/gdk.h>
#include <libgnome-desktop/gnome-pnp-ids.h>
+#include "meta-display-config-shared.h"
G_BEGIN_DECLS
@@ -215,33 +216,46 @@ G_DECLARE_FINAL_TYPE (FlashbackMonitorManager, flashback_monitor_manager,
FLASHBACK, MONITOR_MANAGER,
GObject)
+typedef struct _FlashbackMonitorManagerPrivate FlashbackMonitorManagerPrivate;
+
struct _FlashbackMonitorManager
{
- GObject parnet;
+ GObject parnet;
+
+ gboolean in_init;
+ unsigned int serial;
- unsigned int serial;
+ MetaPowerSave power_save_mode;
- int max_screen_width;
- int max_screen_height;
+ int max_screen_width;
+ int max_screen_height;
+ int screen_width;
+ int screen_height;
/* Outputs refer to physical screens,
CRTCs refer to stuff that can drive outputs
(like encoders, but less tied to the HW),
while monitor_infos refer to logical ones.
*/
- MetaOutput *outputs;
- unsigned int n_outputs;
+ MetaOutput *outputs;
+ unsigned int n_outputs;
+
+ MetaMonitorMode *modes;
+ unsigned int n_modes;
+
+ MetaCRTC *crtcs;
+ unsigned int n_crtcs;
- MetaMonitorMode *modes;
- unsigned int n_modes;
+ MetaMonitorInfo *monitor_infos;
+ unsigned int n_monitor_infos;
+ int primary_monitor_index;
- MetaCRTC *crtcs;
- unsigned int n_crtcs;
+ int persistent_timeout_id;
+ FlashbackMonitorConfig *config;
- GnomePnpIds *pnp_ids;
+ GnomePnpIds *pnp_ids;
- int persistent_timeout_id;
- FlashbackMonitorConfig *config;
+ FlashbackMonitorManagerPrivate *priv;
};
FlashbackMonitorManager *flashback_monitor_manager_new (void);
@@ -269,14 +283,20 @@ void flashback_monitor_manager_set_crtc_gamma (Flashbac
unsigned short *green,
unsigned short *blue);
-char *flashback_monitor_manager_get_edid_file (FlashbackMonitorManager *manager,
- MetaOutput *output);
GBytes *flashback_monitor_manager_read_edid (FlashbackMonitorManager *manager,
MetaOutput *output);
+void flashback_monitor_manager_set_power_save_mode (FlashbackMonitorManager *manager,
+ MetaPowerSave mode);
+
+void meta_output_parse_edid (MetaOutput *output,
+ GBytes *edid);
+
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
+void flashback_monitor_manager_read_current_config (FlashbackMonitorManager *manager);
+
G_END_DECLS
#endif
diff --git a/gnome-flashback/libdisplay-config/meta-display-config-shared.h
b/gnome-flashback/libdisplay-config/meta-display-config-shared.h
new file mode 100644
index 0000000..95f662b
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/meta-display-config-shared.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file is shared between mutter (src/core/meta-display-config-shared.h)
+ and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h).
+
+ The canonical place for all changes is mutter.
+
+ There should be no includes in this file.
+*/
+
+#ifndef META_DISPLAY_CONFIG_SHARED_H
+#define META_DISPLAY_CONFIG_SHARED_H
+
+typedef enum {
+ META_POWER_SAVE_UNSUPPORTED = -1,
+ META_POWER_SAVE_ON = 0,
+ META_POWER_SAVE_STANDBY,
+ META_POWER_SAVE_SUSPEND,
+ META_POWER_SAVE_OFF,
+} MetaPowerSave;
+
+#endif /* META_DISPLAY_CONFIG_SHARED_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]