[gnome-flashback] backends: implement GfMonitorManagerXrandr
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] backends: implement GfMonitorManagerXrandr
- Date: Thu, 21 Sep 2017 00:08:54 +0000 (UTC)
commit 659728c32e6dcc8ab7bdbb4a9302447afdb6b962
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Thu Sep 21 00:41:40 2017 +0300
backends: implement GfMonitorManagerXrandr
backends/gf-monitor-manager-private.h | 70 ++-
backends/gf-monitor-manager-xrandr.c | 1465 ++++++++++++++++++++++++++++++++-
backends/gf-monitor-manager.c | 708 ++++++++++++++++-
configure.ac | 2 +
4 files changed, 2222 insertions(+), 23 deletions(-)
---
diff --git a/backends/gf-monitor-manager-private.h b/backends/gf-monitor-manager-private.h
index 4941c93..69a5b04 100644
--- a/backends/gf-monitor-manager-private.h
+++ b/backends/gf-monitor-manager-private.h
@@ -157,36 +157,68 @@ typedef struct
GType gf_monitor_manager_get_type (void);
-GfBackend *gf_monitor_manager_get_backend (GfMonitorManager *manager);
+GfBackend *gf_monitor_manager_get_backend (GfMonitorManager
*manager);
-GfMonitor *gf_monitor_manager_get_primary_monitor (GfMonitorManager *manager);
+void gf_monitor_manager_rebuild_derived (GfMonitorManager
*manager,
+ GfMonitorsConfig
*config);
-GfMonitor *gf_monitor_manager_get_laptop_panel (GfMonitorManager *manager);
+GfMonitor *gf_monitor_manager_get_primary_monitor (GfMonitorManager
*manager);
-GfMonitor *gf_monitor_manager_get_monitor_from_spec (GfMonitorManager *manager,
- GfMonitorSpec
*monitor_spec);
+GfMonitor *gf_monitor_manager_get_laptop_panel (GfMonitorManager
*manager);
-GList *gf_monitor_manager_get_monitors (GfMonitorManager *manager);
+GfMonitor *gf_monitor_manager_get_monitor_from_spec (GfMonitorManager
*manager,
+ GfMonitorSpec
*monitor_spec);
-void gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
- GfMonitor *monitor);
+GList *gf_monitor_manager_get_monitors (GfMonitorManager
*manager);
-void gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
- GfMonitor *monitor);
+gboolean gf_monitor_manager_has_hotplug_mode_update (GfMonitorManager
*manager);
+void gf_monitor_manager_read_current_state (GfMonitorManager
*manager);
+void gf_monitor_manager_on_hotplug (GfMonitorManager
*manager);
-gboolean gf_monitor_manager_is_transform_handled (GfMonitorManager *manager,
- GfCrtc *crtc,
- GfMonitorTransform transform);
+void gf_monitor_manager_tiled_monitor_added (GfMonitorManager
*manager,
+ GfMonitor
*monitor);
-gboolean gf_monitor_manager_is_lid_closed (GfMonitorManager *manager);
+void gf_monitor_manager_tiled_monitor_removed (GfMonitorManager
*manager,
+ GfMonitor
*monitor);
-gfloat gf_monitor_manager_calculate_monitor_mode_scale (GfMonitorManager *manager,
- GfMonitor *monitor,
- GfMonitorMode
*monitor_mode);
+gboolean gf_monitor_manager_is_transform_handled (GfMonitorManager
*manager,
+ GfCrtc
*crtc,
+ GfMonitorTransform
transform);
-GfMonitorManagerCapability gf_monitor_manager_get_capabilities (GfMonitorManager *manager);
+GfMonitorsConfig *gf_monitor_manager_ensure_configured (GfMonitorManager
*manager);
-GfLogicalMonitorLayoutMode gf_monitor_manager_get_default_layout_mode (GfMonitorManager *manager);
+void gf_monitor_manager_update_logical_state_derived (GfMonitorManager
*manager,
+ GfMonitorsConfig
*config);
+
+gboolean gf_monitor_manager_is_lid_closed (GfMonitorManager
*manager);
+
+gfloat gf_monitor_manager_calculate_monitor_mode_scale (GfMonitorManager
*manager,
+ GfMonitor
*monitor,
+ GfMonitorMode
*monitor_mode);
+
+gfloat *gf_monitor_manager_calculate_supported_scales (GfMonitorManager
*manager,
+ GfLogicalMonitorLayoutMode
layout_mode,
+ GfMonitor
*monitor,
+ GfMonitorMode
*monitor_mode,
+ gint
*n_supported_scales);
+
+gboolean gf_monitor_manager_is_scale_supported (GfMonitorManager
*manager,
+ GfLogicalMonitorLayoutMode
layout_mode,
+ GfMonitor
*monitor,
+ GfMonitorMode
*monitor_mode,
+ gfloat
scale);
+
+GfMonitorManagerCapability gf_monitor_manager_get_capabilities (GfMonitorManager
*manager);
+
+GfLogicalMonitorLayoutMode gf_monitor_manager_get_default_layout_mode (GfMonitorManager
*manager);
+
+GfMonitorConfigManager *gf_monitor_manager_get_config_manager (GfMonitorManager
*manager);
+
+void gf_monitor_manager_clear_output (GfOutput
*output);
+
+void gf_monitor_manager_clear_mode (GfCrtcMode
*mode);
+
+void gf_monitor_manager_clear_crtc (GfCrtc
*crtc);
static inline gboolean
gf_monitor_transform_is_rotated (GfMonitorTransform transform)
diff --git a/backends/gf-monitor-manager-xrandr.c b/backends/gf-monitor-manager-xrandr.c
index 3f1e63e..2d04a44 100644
--- a/backends/gf-monitor-manager-xrandr.c
+++ b/backends/gf-monitor-manager-xrandr.c
@@ -27,18 +27,32 @@
#include "config.h"
+#include <math.h>
+#include <stdlib.h>
#include <string.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 "gf-backend-x11-private.h"
#include "gf-crtc-private.h"
+#include "gf-monitor-config-manager-private.h"
#include "gf-monitor-manager-xrandr-private.h"
#include "gf-monitor-private.h"
#include "gf-monitor-tiled-private.h"
#include "gf-output-private.h"
+#define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)
+#define ALL_TRANSFORMS ((1 << (GF_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 _GfMonitorManagerXrandr
{
GfMonitorManager parent;
@@ -54,6 +68,8 @@ struct _GfMonitorManagerXrandr
XRRScreenResources *resources;
+ Time last_xrandr_set_timestamp;
+
gint max_screen_width;
gint max_screen_height;
};
@@ -65,6 +81,239 @@ typedef struct
G_DEFINE_TYPE (GfMonitorManagerXrandr, gf_monitor_manager_xrandr, GF_TYPE_MONITOR_MANAGER)
+static gboolean
+xrandr_set_crtc_config (GfMonitorManagerXrandr *xrandr,
+ gboolean save_timestamp,
+ xcb_randr_crtc_t crtc,
+ xcb_timestamp_t timestamp,
+ gint x,
+ gint y,
+ xcb_randr_mode_t mode,
+ xcb_randr_rotation_t rotation,
+ xcb_randr_output_t *outputs,
+ gint n_outputs)
+{
+ xcb_connection_t *xcb_conn;
+ xcb_timestamp_t config_timestamp;
+ xcb_randr_set_crtc_config_cookie_t cookie;
+ xcb_randr_set_crtc_config_reply_t *reply;
+ xcb_generic_error_t *xcb_error;
+
+ xcb_conn = XGetXCBConnection (xrandr->xdisplay);
+ config_timestamp = xrandr->resources->configTimestamp;
+ cookie = xcb_randr_set_crtc_config (xcb_conn, crtc,
+ timestamp, config_timestamp,
+ x, y, mode, rotation,
+ n_outputs, outputs);
+
+ xcb_error = NULL;
+ reply = xcb_randr_set_crtc_config_reply (xcb_conn, cookie, &xcb_error);
+ if (xcb_error || !reply)
+ {
+ g_free (xcb_error);
+ g_free (reply);
+
+ return FALSE;
+ }
+
+ if (save_timestamp)
+ xrandr->last_xrandr_set_timestamp = reply->timestamp;
+
+ g_free (reply);
+
+ return TRUE;
+}
+
+static void
+output_set_presentation_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output,
+ gboolean presentation)
+{
+ Atom atom;
+ gint value;
+
+ atom = XInternAtom (xrandr->xdisplay, "_GNOME_FLASHBACK_PRESENTATION_OUTPUT", False);
+ value= presentation;
+
+ xcb_randr_change_output_property (XGetXCBConnection (xrandr->xdisplay),
+ (XID) output->winsys_id,
+ atom, XCB_ATOM_CARDINAL, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &value);
+}
+
+static void
+output_set_underscanning_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output,
+ gboolean underscanning)
+{
+ Atom prop, valueatom;
+ const gchar *value;
+
+ prop = XInternAtom (xrandr->xdisplay, "underscan", False);
+
+ value = underscanning ? "on" : "off";
+ valueatom = XInternAtom (xrandr->xdisplay, value, False);
+
+ xcb_randr_change_output_property (XGetXCBConnection (xrandr->xdisplay),
+ (XID) output->winsys_id,
+ prop, XCB_ATOM_ATOM, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &valueatom);
+
+ /* Configure the border at the same time. Currently, we use a
+ * 5% of the width/height of the mode. In the future, we should
+ * make the border configurable.
+ */
+ if (underscanning)
+ {
+ uint32_t border_value;
+
+ prop = XInternAtom (xrandr->xdisplay, "underscan hborder", False);
+ border_value = output->crtc->current_mode->width * 0.05;
+
+ xcb_randr_change_output_property (XGetXCBConnection (xrandr->xdisplay),
+ (XID) output->winsys_id,
+ prop, XCB_ATOM_INTEGER, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &border_value);
+
+ prop = XInternAtom (xrandr->xdisplay, "underscan vborder", False);
+ border_value = output->crtc->current_mode->height * 0.05;
+
+ xcb_randr_change_output_property (XGetXCBConnection (xrandr->xdisplay),
+ (XID) output->winsys_id,
+ prop, XCB_ATOM_INTEGER, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &border_value);
+ }
+}
+
+static gboolean
+is_crtc_assignment_changed (GfCrtc *crtc,
+ GfCrtcInfo **crtc_infos,
+ guint n_crtc_infos)
+{
+ guint i;
+
+ for (i = 0; i < n_crtc_infos; i++)
+ {
+ GfCrtcInfo *crtc_info = crtc_infos[i];
+ guint j;
+
+ if (crtc_info->crtc != crtc)
+ continue;
+
+ if (crtc->current_mode != crtc_info->mode)
+ return TRUE;
+
+ if (crtc->rect.x != crtc_info->x)
+ return TRUE;
+
+ if (crtc->rect.y != crtc_info->y)
+ return TRUE;
+
+ if (crtc->transform != crtc_info->transform)
+ return TRUE;
+
+ for (j = 0; j < crtc_info->outputs->len; j++)
+ {
+ GfOutput *output = ((GfOutput**) crtc_info->outputs->pdata)[j];
+
+ if (output->crtc != crtc)
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ return crtc->current_mode != NULL;
+}
+
+static gboolean
+is_output_assignment_changed (GfOutput *output,
+ GfCrtcInfo **crtc_infos,
+ guint n_crtc_infos,
+ GfOutputInfo **output_infos,
+ guint n_output_infos)
+{
+ gboolean output_is_found = FALSE;
+ guint i;
+
+ for (i = 0; i < n_output_infos; i++)
+ {
+ GfOutputInfo *output_info = output_infos[i];
+
+ if (output_info->output != output)
+ continue;
+
+ if (output->is_primary != output_info->is_primary)
+ return TRUE;
+
+ if (output->is_presentation != output_info->is_presentation)
+ return TRUE;
+
+ if (output->is_underscanning != output_info->is_underscanning)
+ return TRUE;
+
+ output_is_found = TRUE;
+ }
+
+ if (!output_is_found)
+ return output->crtc != NULL;
+
+ for (i = 0; i < n_crtc_infos; i++)
+ {
+ GfCrtcInfo *crtc_info = crtc_infos[i];
+ guint j;
+
+ for (j = 0; j < crtc_info->outputs->len; j++)
+ {
+ GfOutput *crtc_info_output;
+
+ crtc_info_output = ((GfOutput**) crtc_info->outputs->pdata)[j];
+
+ if (crtc_info_output == output &&
+ crtc_info->crtc == output->crtc)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+is_assignments_changed (GfMonitorManager *manager,
+ GfCrtcInfo **crtc_infos,
+ guint n_crtc_infos,
+ GfOutputInfo **output_infos,
+ guint n_output_infos)
+{
+ guint i;
+
+ for (i = 0; i < manager->n_crtcs; i++)
+ {
+ GfCrtc *crtc = &manager->crtcs[i];
+
+ if (is_crtc_assignment_changed (crtc, crtc_infos, n_crtc_infos))
+ return TRUE;
+ }
+
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ GfOutput *output = &manager->outputs[i];
+
+ if (is_output_assignment_changed (output,
+ crtc_infos,
+ n_crtc_infos,
+ output_infos,
+ n_output_infos))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static guint8 *
get_edid_property (Display *xdisplay,
RROutput output,
@@ -128,6 +377,892 @@ read_output_edid (GfMonitorManagerXrandr *xrandr,
return NULL;
}
+static GfMonitorTransform
+gf_monitor_transform_from_xrandr (Rotation rotation)
+{
+ static const GfMonitorTransform y_reflected_map[4] = {
+ GF_MONITOR_TRANSFORM_FLIPPED_180,
+ GF_MONITOR_TRANSFORM_FLIPPED_90,
+ GF_MONITOR_TRANSFORM_FLIPPED,
+ GF_MONITOR_TRANSFORM_FLIPPED_270
+ };
+ GfMonitorTransform ret;
+
+ switch (rotation & 0x7F)
+ {
+ default:
+ case RR_Rotate_0:
+ ret = GF_MONITOR_TRANSFORM_NORMAL;
+ break;
+
+ case RR_Rotate_90:
+ ret = GF_MONITOR_TRANSFORM_90;
+ break;
+
+ case RR_Rotate_180:
+ ret = GF_MONITOR_TRANSFORM_180;
+ break;
+
+ case RR_Rotate_270:
+ ret = GF_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;
+}
+
+static xcb_randr_rotation_t
+gf_monitor_transform_to_xrandr (GfMonitorTransform transform)
+{
+ xcb_randr_rotation_t rotation;
+
+ rotation = XCB_RANDR_ROTATION_ROTATE_0;
+
+ switch (transform)
+ {
+ case GF_MONITOR_TRANSFORM_NORMAL:
+ rotation = XCB_RANDR_ROTATION_ROTATE_0;
+ break;
+
+ case GF_MONITOR_TRANSFORM_90:
+ rotation = XCB_RANDR_ROTATION_ROTATE_90;
+ break;
+
+ case GF_MONITOR_TRANSFORM_180:
+ rotation = XCB_RANDR_ROTATION_ROTATE_180;
+ break;
+
+ case GF_MONITOR_TRANSFORM_270:
+ rotation = XCB_RANDR_ROTATION_ROTATE_270;
+ break;
+
+ case GF_MONITOR_TRANSFORM_FLIPPED:
+ rotation = XCB_RANDR_ROTATION_REFLECT_X | XCB_RANDR_ROTATION_ROTATE_0;
+ break;
+
+ case GF_MONITOR_TRANSFORM_FLIPPED_90:
+ rotation = XCB_RANDR_ROTATION_REFLECT_X | XCB_RANDR_ROTATION_ROTATE_90;
+ break;
+
+ case GF_MONITOR_TRANSFORM_FLIPPED_180:
+ rotation = XCB_RANDR_ROTATION_REFLECT_X | XCB_RANDR_ROTATION_ROTATE_180;
+ break;
+
+ case GF_MONITOR_TRANSFORM_FLIPPED_270:
+ rotation = XCB_RANDR_ROTATION_REFLECT_X | XCB_RANDR_ROTATION_ROTATE_270;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return rotation;
+}
+
+static GfMonitorTransform
+gf_monitor_transform_from_xrandr_all (Rotation rotation)
+{
+ GfMonitorTransform ret;
+
+ /* Handle the common cases first (none or all) */
+ if (rotation == 0 || rotation == RR_Rotate_0)
+ return (1 << GF_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 << GF_MONITOR_TRANSFORM_NORMAL;
+ if (rotation & RR_Rotate_90)
+ ret |= 1 << GF_MONITOR_TRANSFORM_90;
+ if (rotation & RR_Rotate_180)
+ ret |= 1 << GF_MONITOR_TRANSFORM_180;
+ if (rotation & RR_Rotate_270)
+ ret |= 1 << GF_MONITOR_TRANSFORM_270;
+ if (rotation & (RR_Rotate_0 | RR_Reflect_X))
+ ret |= 1 << GF_MONITOR_TRANSFORM_FLIPPED;
+ if (rotation & (RR_Rotate_90 | RR_Reflect_X))
+ ret |= 1 << GF_MONITOR_TRANSFORM_FLIPPED_90;
+ if (rotation & (RR_Rotate_180 | RR_Reflect_X))
+ ret |= 1 << GF_MONITOR_TRANSFORM_FLIPPED_180;
+ if (rotation & (RR_Rotate_270 | RR_Reflect_X))
+ ret |= 1 << GF_MONITOR_TRANSFORM_FLIPPED_270;
+
+ return ret;
+}
+
+static gboolean
+output_get_property_exists (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output,
+ const gchar *propname)
+{
+ gboolean exists;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+
+ atom = XInternAtom (xrandr->xdisplay, propname, False);
+ XRRGetOutputProperty (xrandr->xdisplay, (XID) output->winsys_id, atom,
+ 0, G_MAXLONG, False, False, AnyPropertyType,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &buffer);
+
+ exists = (actual_type != None);
+
+ if (buffer)
+ XFree (buffer);
+
+ return exists;
+}
+
+static gboolean
+output_get_hotplug_mode_update (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ return output_get_property_exists (xrandr, output, "hotplug_mode_update");
+}
+
+static gboolean
+output_get_integer_property (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output,
+ const gchar *propname,
+ gint *value)
+{
+ gboolean exists;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+
+ atom = XInternAtom (xrandr->xdisplay, propname, False);
+ XRRGetOutputProperty (xrandr->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 = ((gint*) buffer)[0];
+
+ if (buffer)
+ XFree (buffer);
+
+ return exists;
+}
+
+static gint
+output_get_suggested_x (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ gint val;
+
+ if (output_get_integer_property (xrandr, output, "suggested X", &val))
+ return val;
+
+ return -1;
+}
+
+static gint
+output_get_suggested_y (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ gint val;
+
+ if (output_get_integer_property (xrandr, output, "suggested Y", &val))
+ return val;
+
+ return -1;
+}
+
+static GfConnectorType
+connector_type_from_atom (GfMonitorManagerXrandr *xrandr,
+ Atom atom)
+{
+ Display *xdisplay;
+
+ xdisplay = xrandr->xdisplay;
+
+ if (atom == XInternAtom (xdisplay, "HDMI", True))
+ return GF_CONNECTOR_TYPE_HDMIA;
+ if (atom == XInternAtom (xdisplay, "VGA", True))
+ return GF_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 (xdisplay, "Panel", True))
+ return GF_CONNECTOR_TYPE_LVDS;
+ if (atom == XInternAtom (xdisplay, "DVI", True) ||
+ atom == XInternAtom (xdisplay, "DVI-I", True))
+ return GF_CONNECTOR_TYPE_DVII;
+ if (atom == XInternAtom (xdisplay, "DVI-A", True))
+ return GF_CONNECTOR_TYPE_DVIA;
+ if (atom == XInternAtom (xdisplay, "DVI-D", True))
+ return GF_CONNECTOR_TYPE_DVID;
+ if (atom == XInternAtom (xdisplay, "DisplayPort", True))
+ return GF_CONNECTOR_TYPE_DisplayPort;
+ if (atom == XInternAtom (xdisplay, "TV", True))
+ return GF_CONNECTOR_TYPE_TV;
+ if (atom == XInternAtom (xdisplay, "TV-Composite", True))
+ return GF_CONNECTOR_TYPE_Composite;
+ if (atom == XInternAtom (xdisplay, "TV-SVideo", True))
+ return GF_CONNECTOR_TYPE_SVIDEO;
+ /* Another set of mismatches. */
+ if (atom == XInternAtom (xdisplay, "TV-SCART", True))
+ return GF_CONNECTOR_TYPE_TV;
+ if (atom == XInternAtom (xdisplay, "TV-C4", True))
+ return GF_CONNECTOR_TYPE_TV;
+
+ return GF_CONNECTOR_TYPE_Unknown;
+}
+
+static GfConnectorType
+output_get_connector_type_from_prop (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ Atom atom, actual_type, connector_type_atom;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ GfConnectorType ret;
+
+ atom = XInternAtom (xrandr->xdisplay, "ConnectorType", False);
+ XRRGetOutputProperty (xrandr->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)
+ {
+ if (buffer)
+ XFree (buffer);
+
+ return GF_CONNECTOR_TYPE_Unknown;
+ }
+
+ connector_type_atom = ((Atom *) buffer)[0];
+ ret = connector_type_from_atom (xrandr, connector_type_atom);
+ XFree (buffer);
+
+ return ret;
+}
+
+static GfConnectorType
+output_get_connector_type_from_name (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ const gchar *name;
+
+ 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 GF_CONNECTOR_TYPE_DVII;
+ if (g_str_has_prefix (name, "LVDS"))
+ return GF_CONNECTOR_TYPE_LVDS;
+ if (g_str_has_prefix (name, "HDMI"))
+ return GF_CONNECTOR_TYPE_HDMIA;
+ if (g_str_has_prefix (name, "VGA"))
+ return GF_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 GF_CONNECTOR_TYPE_DisplayPort;
+ if (g_str_has_prefix (name, "eDP"))
+ return GF_CONNECTOR_TYPE_eDP;
+ if (g_str_has_prefix (name, "Virtual"))
+ return GF_CONNECTOR_TYPE_VIRTUAL;
+ if (g_str_has_prefix (name, "Composite"))
+ return GF_CONNECTOR_TYPE_Composite;
+ if (g_str_has_prefix (name, "S-video"))
+ return GF_CONNECTOR_TYPE_SVIDEO;
+ if (g_str_has_prefix (name, "TV"))
+ return GF_CONNECTOR_TYPE_TV;
+ if (g_str_has_prefix (name, "CTV"))
+ return GF_CONNECTOR_TYPE_Composite;
+ if (g_str_has_prefix (name, "DSI"))
+ return GF_CONNECTOR_TYPE_DSI;
+ if (g_str_has_prefix (name, "DIN"))
+ return GF_CONNECTOR_TYPE_9PinDIN;
+
+ return GF_CONNECTOR_TYPE_Unknown;
+}
+
+static GfConnectorType
+output_get_connector_type (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ GfConnectorType 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 (xrandr, output);
+ if (ret != GF_CONNECTOR_TYPE_Unknown)
+ return ret;
+
+ /* Fall back to heuristics based on the output name. */
+ ret = output_get_connector_type_from_name (xrandr, output);
+ if (ret != GF_CONNECTOR_TYPE_Unknown)
+ return ret;
+
+ return GF_CONNECTOR_TYPE_Unknown;
+}
+
+static void
+output_get_tile_info (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ Atom tile_atom;
+ guchar *prop;
+ gulong nitems, bytes_after;
+ gint actual_format;
+ Atom actual_type;
+
+ if (xrandr->has_randr15 == FALSE)
+ return;
+
+ tile_atom = XInternAtom (xrandr->xdisplay, "TILE", FALSE);
+ XRRGetOutputProperty (xrandr->xdisplay, output->winsys_id,
+ tile_atom, 0, 100, False,
+ False, AnyPropertyType,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop);
+
+ if (actual_type == XA_INTEGER && actual_format == 32 && nitems == 8)
+ {
+ glong *values = (glong *) prop;
+ output->tile_info.group_id = values[0];
+ output->tile_info.flags = values[1];
+ output->tile_info.max_h_tiles = values[2];
+ output->tile_info.max_v_tiles = values[3];
+ output->tile_info.loc_h_tile = values[4];
+ output->tile_info.loc_v_tile = values[5];
+ output->tile_info.tile_w = values[6];
+ output->tile_info.tile_h = values[7];
+ }
+
+ if (prop)
+ XFree (prop);
+}
+
+static void
+output_get_modes (GfMonitorManager *manager,
+ GfOutput *output,
+ XRROutputInfo *xrandr_output)
+{
+ guint j, k;
+ guint n_actual_modes;
+
+ output->modes = g_new0 (GfCrtcMode *, xrandr_output->nmode);
+
+ n_actual_modes = 0;
+ for (j = 0; j < (guint) xrandr_output->nmode; j++)
+ {
+ for (k = 0; k < manager->n_modes; k++)
+ {
+ if (xrandr_output->modes[j] == (XID) manager->modes[k].mode_id)
+ {
+ output->modes[n_actual_modes] = &manager->modes[k];
+ n_actual_modes += 1;
+ break;
+ }
+ }
+ }
+
+ output->n_modes = n_actual_modes;
+ if (n_actual_modes > 0)
+ output->preferred_mode = output->modes[0];
+}
+
+static void
+output_get_crtcs (GfMonitorManager *manager,
+ GfOutput *output,
+ XRROutputInfo *xrandr_output)
+{
+ guint j, k;
+ guint n_actual_crtcs;
+
+ output->possible_crtcs = g_new0 (GfCrtc *, xrandr_output->ncrtc);
+
+ n_actual_crtcs = 0;
+ for (j = 0; j < (guint) xrandr_output->ncrtc; j++)
+ {
+ for (k = 0; k < manager->n_crtcs; k++)
+ {
+ if ((XID) manager->crtcs[k].crtc_id == xrandr_output->crtcs[j])
+ {
+ output->possible_crtcs[n_actual_crtcs] = &manager->crtcs[k];
+ n_actual_crtcs += 1;
+ break;
+ }
+ }
+ }
+ output->n_possible_crtcs = n_actual_crtcs;
+
+ output->crtc = NULL;
+ for (j = 0; j < manager->n_crtcs; j++)
+ {
+ if ((XID) manager->crtcs[j].crtc_id == xrandr_output->crtc)
+ {
+ output->crtc = &manager->crtcs[j];
+ break;
+ }
+ }
+}
+
+static gboolean
+output_get_boolean_property (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output,
+ const gchar *propname)
+{
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ gboolean value;
+
+ atom = XInternAtom (xrandr->xdisplay, propname, False);
+ XRRGetOutputProperty (xrandr->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)
+ {
+ if (buffer)
+ XFree (buffer);
+
+ return FALSE;
+ }
+
+ value = ((gint*) buffer)[0];
+ XFree (buffer);
+
+ return value;
+}
+
+static gboolean
+output_get_presentation_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ return output_get_boolean_property (xrandr, output, "_GNOME_FLASHBACK_PRESENTATION_OUTPUT");
+}
+
+static gboolean
+output_get_underscanning_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ gchar *str;
+ gboolean value;
+
+ atom = XInternAtom (xrandr->xdisplay, "underscan", False);
+ XRRGetOutputProperty (xrandr->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)
+ {
+ if (buffer)
+ XFree (buffer);
+
+ return FALSE;
+ }
+
+ str = XGetAtomName (xrandr->xdisplay, *(Atom *)buffer);
+ XFree (buffer);
+
+ value = !strcmp (str, "on");
+ XFree (str);
+
+ return value;
+}
+
+static gboolean
+output_get_supports_underscanning_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ Atom atom, actual_type;
+ gint actual_format, i;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ XRRPropertyInfo *property_info;
+ Atom *values;
+ gboolean supports_underscanning = FALSE;
+
+ atom = XInternAtom (xrandr->xdisplay, "underscan", False);
+ XRRGetOutputProperty (xrandr->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)
+ {
+ if (buffer)
+ XFree (buffer);
+
+ return FALSE;
+ }
+
+ property_info = XRRQueryOutputProperty (xrandr->xdisplay,
+ (XID) output->winsys_id,
+ atom);
+ values = (Atom *) property_info->values;
+
+ for (i = 0; i < property_info->num_values; i++)
+ {
+ /* The output supports underscanning if "on" is a valid value
+ * for the underscan property.
+ */
+ gchar *name = XGetAtomName (xrandr->xdisplay, values[i]);
+ if (strcmp (name, "on") == 0)
+ supports_underscanning = TRUE;
+
+ XFree (name);
+ }
+
+ XFree (property_info);
+
+ return supports_underscanning;
+}
+
+static int
+normalize_backlight (GfOutput *output,
+ gint hw_value)
+{
+ return round ((gdouble) (hw_value - output->backlight_min) /
+ (output->backlight_max - output->backlight_min) * 100.0);
+}
+
+static gint
+output_get_backlight_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ gint value = -1;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+
+ atom = XInternAtom (xrandr->xdisplay, "Backlight", False);
+ XRRGetOutputProperty (xrandr->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)
+ {
+ if (buffer)
+ XFree (buffer);
+
+ return FALSE;
+ }
+
+ value = ((gint*) buffer)[0];
+ XFree (buffer);
+
+ if (value > 0)
+ return normalize_backlight (output, value);
+ else
+ return -1;
+}
+
+static void
+output_get_backlight_limits_xrandr (GfMonitorManagerXrandr *xrandr,
+ GfOutput *output)
+{
+ Atom atom;
+ xcb_connection_t *xcb_conn;
+ xcb_randr_query_output_property_cookie_t cookie;
+ xcb_randr_query_output_property_reply_t *reply;
+ int32_t *values;
+
+ atom = XInternAtom (xrandr->xdisplay, "Backlight", False);
+
+ xcb_conn = XGetXCBConnection (xrandr->xdisplay);
+ cookie = xcb_randr_query_output_property (xcb_conn,
+ (xcb_randr_output_t) output->winsys_id,
+ (xcb_atom_t) atom);
+
+ reply = xcb_randr_query_output_property_reply (xcb_conn, cookie, 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);
+ g_free (reply);
+ return;
+ }
+
+ values = xcb_randr_query_output_property_valid_values (reply);
+
+ output->backlight_min = values[0];
+ output->backlight_max = values[1];
+
+ g_free (reply);
+}
+
+static gint
+compare_outputs (const void *one,
+ const void *two)
+{
+ const GfOutput *o_one = one, *o_two = two;
+
+ return strcmp (o_one->name, o_two->name);
+}
+
+static void
+apply_crtc_assignments (GfMonitorManager *manager,
+ gboolean save_timestamp,
+ GfCrtcInfo **crtcs,
+ guint n_crtcs,
+ GfOutputInfo **outputs,
+ guint n_outputs)
+{
+ GfMonitorManagerXrandr *xrandr;
+ gint width, height, width_mm, height_mm;
+ guint i;
+
+ xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+ XGrabServer (xrandr->xdisplay);
+
+ /* First compute the new size of the screen (framebuffer) */
+ width = 0; height = 0;
+ for (i = 0; i < n_crtcs; i++)
+ {
+ GfCrtcInfo *crtc_info = crtcs[i];
+ GfCrtc *crtc = crtc_info->crtc;
+
+ crtc->is_dirty = TRUE;
+
+ if (crtc_info->mode == NULL)
+ continue;
+
+ if (gf_monitor_transform_is_rotated (crtc_info->transform))
+ {
+ 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++)
+ {
+ GfCrtcInfo *crtc_info = crtcs[i];
+ GfCrtc *crtc = crtc_info->crtc;
+
+ if (crtc_info->mode == NULL ||
+ crtc->rect.x + crtc->rect.width > width ||
+ crtc->rect.y + crtc->rect.height > height)
+ {
+ xrandr_set_crtc_config (xrandr,
+ save_timestamp,
+ (xcb_randr_crtc_t) crtc->crtc_id,
+ XCB_CURRENT_TIME,
+ 0, 0, XCB_NONE,
+ XCB_RANDR_ROTATION_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++)
+ {
+ GfCrtc *crtc = &manager->crtcs[i];
+
+ if (crtc->is_dirty)
+ {
+ crtc->is_dirty = FALSE;
+ continue;
+ }
+
+ if (crtc->current_mode == NULL)
+ continue;
+
+ xrandr_set_crtc_config (xrandr,
+ save_timestamp,
+ (xcb_randr_crtc_t) crtc->crtc_id,
+ XCB_CURRENT_TIME,
+ 0, 0, XCB_NONE,
+ XCB_RANDR_ROTATION_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 (xrandr->xdisplay, xrandr->xroot,
+ width, height, width_mm, height_mm);
+
+ for (i = 0; i < n_crtcs; i++)
+ {
+ GfCrtcInfo *crtc_info = crtcs[i];
+ GfCrtc *crtc = crtc_info->crtc;
+
+ if (crtc_info->mode != NULL)
+ {
+ GfCrtcMode *mode;
+ xcb_randr_output_t *output_ids;
+ guint j, n_output_ids;
+ xcb_randr_rotation_t rotation;
+
+ mode = crtc_info->mode;
+
+ n_output_ids = crtc_info->outputs->len;
+ output_ids = g_new0 (xcb_randr_output_t, n_output_ids);
+
+ for (j = 0; j < n_output_ids; j++)
+ {
+ GfOutput *output;
+
+ output = ((GfOutput**) crtc_info->outputs->pdata)[j];
+
+ output->is_dirty = TRUE;
+ output->crtc = crtc;
+
+ output_ids[j] = output->winsys_id;
+ }
+
+ rotation = gf_monitor_transform_to_xrandr (crtc_info->transform);
+ if (!xrandr_set_crtc_config (xrandr,
+ save_timestamp,
+ (xcb_randr_crtc_t) crtc->crtc_id,
+ XCB_CURRENT_TIME,
+ crtc_info->x, crtc_info->y,
+ (xcb_randr_mode_t) mode->mode_id,
+ rotation,
+ output_ids, n_output_ids))
+ {
+ g_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transform
%u failed\n",
+ (guint) (crtc->crtc_id), (guint) (mode->mode_id),
+ mode->width, mode->height, (gfloat) mode->refresh_rate,
+ crtc_info->x, crtc_info->y, crtc_info->transform);
+
+ g_free (output_ids);
+ continue;
+ }
+
+ if (gf_monitor_transform_is_rotated (crtc_info->transform))
+ {
+ 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;
+
+ g_free (output_ids);
+ }
+ }
+
+ for (i = 0; i < n_outputs; i++)
+ {
+ GfOutputInfo *output_info = outputs[i];
+ GfOutput *output = output_info->output;
+
+ if (output_info->is_primary)
+ {
+ XRRSetOutputPrimary (xrandr->xdisplay, xrandr->xroot,
+ (XID)output_info->output->winsys_id);
+ }
+
+ output_set_presentation_xrandr (xrandr, output_info->output,
+ output_info->is_presentation);
+
+ if (output_get_supports_underscanning_xrandr (xrandr, output_info->output))
+ output_set_underscanning_xrandr (xrandr, output_info->output,
+ output_info->is_underscanning);
+
+ output->is_primary = output_info->is_primary;
+ output->is_presentation = output_info->is_presentation;
+ output->is_underscanning = output_info->is_underscanning;
+ }
+
+ /* Disable outputs not mentioned in the list */
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ GfOutput *output = &manager->outputs[i];
+
+ if (output->is_dirty)
+ {
+ output->is_dirty = FALSE;
+ continue;
+ }
+
+ output->crtc = NULL;
+ output->is_primary = FALSE;
+ }
+
+ XUngrabServer (xrandr->xdisplay);
+ XFlush (xrandr->xdisplay);
+}
+
static GQuark
gf_monitor_data_quark (void)
{
@@ -293,6 +1428,217 @@ gf_monitor_manager_xrandr_finalize (GObject *object)
static void
gf_monitor_manager_xrandr_read_current (GfMonitorManager *manager)
{
+ GfMonitorManagerXrandr *xrandr;
+ XRRScreenResources *resources;
+ CARD16 dpms_state;
+ BOOL dpms_enabled;
+ gint min_width;
+ gint min_height;
+ Screen *screen;
+ guint i, j, k;
+ RROutput primary_output;
+ guint n_actual_outputs;
+
+ xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+ if (DPMSCapable (xrandr->xdisplay) &&
+ DPMSInfo (xrandr->xdisplay, &dpms_state, &dpms_enabled) &&
+ dpms_enabled)
+ {
+ switch (dpms_state)
+ {
+ case DPMSModeOn:
+ manager->power_save_mode = GF_POWER_SAVE_ON;
+ break;
+
+ case DPMSModeStandby:
+ manager->power_save_mode = GF_POWER_SAVE_STANDBY;
+ break;
+
+ case DPMSModeSuspend:
+ manager->power_save_mode = GF_POWER_SAVE_SUSPEND;
+ break;
+
+ case DPMSModeOff:
+ manager->power_save_mode = GF_POWER_SAVE_OFF;
+ break;
+
+ default:
+ manager->power_save_mode = GF_POWER_SAVE_UNSUPPORTED;
+ break;
+ }
+ }
+ else
+ {
+ manager->power_save_mode = GF_POWER_SAVE_UNSUPPORTED;
+ }
+
+ XRRGetScreenSizeRange (xrandr->xdisplay, xrandr->xroot,
+ &min_width, &min_height,
+ &xrandr->max_screen_width,
+ &xrandr->max_screen_height);
+
+ /* This is updated because we called RRUpdateConfiguration below */
+ screen = ScreenOfDisplay (xrandr->xdisplay, DefaultScreen (xrandr->xdisplay));
+ manager->screen_width = WidthOfScreen (screen);
+ manager->screen_height = HeightOfScreen (screen);
+
+ g_clear_pointer (&xrandr->resources, XRRFreeScreenResources);
+ resources = XRRGetScreenResourcesCurrent (xrandr->xdisplay, xrandr->xroot);
+
+ if (!resources)
+ return;
+
+ xrandr->resources = resources;
+ manager->n_outputs = resources->noutput;
+ manager->n_crtcs = resources->ncrtc;
+ manager->n_modes = resources->nmode;
+ manager->outputs = g_new0 (GfOutput, manager->n_outputs);
+ manager->modes = g_new0 (GfCrtcMode, manager->n_modes);
+ manager->crtcs = g_new0 (GfCrtc, manager->n_crtcs);
+
+ for (i = 0; i < (guint) resources->nmode; i++)
+ {
+ XRRModeInfo *xmode;
+ GfCrtcMode *mode;
+
+ xmode = &resources->modes[i];
+ mode = &manager->modes[i];
+
+ mode->mode_id = xmode->id;
+ mode->width = xmode->width;
+ mode->height = xmode->height;
+ mode->refresh_rate = (xmode->dotClock / ((gfloat) xmode->hTotal * xmode->vTotal));
+ mode->flags = xmode->modeFlags;
+ mode->name = g_strdup_printf ("%dx%d", xmode->width, xmode->height);
+ }
+
+ for (i = 0; i < (guint) resources->ncrtc; i++)
+ {
+ XRRCrtcInfo *crtc;
+ GfCrtc *gf_crtc;
+
+ crtc = XRRGetCrtcInfo (xrandr->xdisplay, resources, resources->crtcs[i]);
+ gf_crtc = &manager->crtcs[i];
+
+ gf_crtc->crtc_id = resources->crtcs[i];
+ gf_crtc->rect.x = crtc->x;
+ gf_crtc->rect.y = crtc->y;
+ gf_crtc->rect.width = crtc->width;
+ gf_crtc->rect.height = crtc->height;
+ gf_crtc->is_dirty = FALSE;
+ gf_crtc->transform = gf_monitor_transform_from_xrandr (crtc->rotation);
+ gf_crtc->all_transforms = gf_monitor_transform_from_xrandr_all (crtc->rotations);
+
+ for (j = 0; j < (guint) resources->nmode; j++)
+ {
+ if (resources->modes[j].id == crtc->mode)
+ {
+ gf_crtc->current_mode = &manager->modes[j];
+ break;
+ }
+ }
+
+ XRRFreeCrtcInfo (crtc);
+ }
+
+ primary_output = XRRGetOutputPrimary (xrandr->xdisplay, xrandr->xroot);
+
+ n_actual_outputs = 0;
+ for (i = 0; i < (guint) resources->noutput; i++)
+ {
+ XRROutputInfo *xrandr_output;
+ GfOutput *output;
+
+ xrandr_output = XRRGetOutputInfo (xrandr->xdisplay, resources,
+ resources->outputs[i]);
+
+ if (!xrandr_output)
+ continue;
+
+ output = &manager->outputs[n_actual_outputs];
+
+ if (xrandr_output->connection != RR_Disconnected)
+ {
+ GBytes *edid;
+
+ output->winsys_id = resources->outputs[i];
+ output->name = g_strdup (xrandr_output->name);
+
+ edid = read_output_edid (xrandr, output->winsys_id);
+ gf_output_parse_edid (output, edid);
+ g_bytes_unref (edid);
+
+ output->width_mm = xrandr_output->mm_width;
+ output->height_mm = xrandr_output->mm_height;
+ output->hotplug_mode_update = output_get_hotplug_mode_update (xrandr, output);
+ output->suggested_x = output_get_suggested_x (xrandr, output);
+ output->suggested_y = output_get_suggested_y (xrandr, output);
+ output->connector_type = output_get_connector_type (xrandr, output);
+
+ output_get_tile_info (xrandr, output);
+ output_get_modes (manager, output, xrandr_output);
+ output_get_crtcs (manager, output, xrandr_output);
+
+ output->n_possible_clones = xrandr_output->nclone;
+ output->possible_clones = g_new0 (GfOutput *, 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 < (guint) xrandr_output->nclone; j++)
+ {
+ output->possible_clones[j] = GINT_TO_POINTER (xrandr_output->clones[j]);
+ }
+
+ output->is_primary = ((XID) output->winsys_id == primary_output);
+ output->is_presentation = output_get_presentation_xrandr (xrandr, output);
+ output->is_underscanning = output_get_underscanning_xrandr (xrandr, output);
+ output->supports_underscanning = output_get_supports_underscanning_xrandr (xrandr, output);
+
+ output_get_backlight_limits_xrandr (xrandr, output);
+
+ if (!(output->backlight_min == 0 && output->backlight_max == 0))
+ output->backlight = output_get_backlight_xrandr (xrandr, output);
+ else
+ output->backlight = -1;
+
+ if (output->n_modes == 0 || output->n_possible_crtcs == 0)
+ gf_monitor_manager_clear_output (output);
+ else
+ n_actual_outputs++;
+ }
+
+ XRRFreeOutputInfo (xrandr_output);
+ }
+
+ manager->n_outputs = n_actual_outputs;
+
+ /* Sort the outputs for easier handling in GfMonitorConfig */
+ qsort (manager->outputs, manager->n_outputs, sizeof (GfOutput), compare_outputs);
+
+ /* Now fix the clones */
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ GfOutput *output;
+
+ output = &manager->outputs[i];
+
+ for (j = 0; j < output->n_possible_clones; j++)
+ {
+ RROutput clone = GPOINTER_TO_INT (output->possible_clones[j]);
+
+ for (k = 0; k < manager->n_outputs; k++)
+ {
+ if (clone == (XID) manager->outputs[k].winsys_id)
+ {
+ output->possible_clones[j] = &manager->outputs[k];
+ break;
+ }
+ }
+ }
+ }
}
static GBytes *
@@ -309,6 +1655,21 @@ gf_monitor_manager_xrandr_read_edid (GfMonitorManager *manager,
static void
gf_monitor_manager_xrandr_ensure_initial_config (GfMonitorManager *manager)
{
+ GfMonitorConfigManager *config_manager;
+ GfMonitorsConfig *config;
+
+ gf_monitor_manager_ensure_configured (manager);
+
+ /* Normally 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.
+ */
+ gf_monitor_manager_read_current_state (manager);
+
+ config_manager = gf_monitor_manager_get_config_manager (manager);
+ config = gf_monitor_config_manager_get_current (config_manager);
+
+ gf_monitor_manager_update_logical_state_derived (manager, config);
}
static gboolean
@@ -317,8 +1678,53 @@ gf_monitor_manager_xrandr_apply_monitors_config (GfMonitorManager *manage
GfMonitorsConfigMethod method,
GError **error)
{
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not implemented");
- return FALSE;
+ GPtrArray *crtc_infos;
+ GPtrArray *output_infos;
+
+ if (!config)
+ {
+ gf_monitor_manager_rebuild_derived (manager, NULL);
+ return TRUE;
+ }
+
+ if (!gf_monitor_config_manager_assign (manager, config,
+ &crtc_infos, &output_infos,
+ error))
+ return FALSE;
+
+ if (method != GF_MONITORS_CONFIG_METHOD_VERIFY)
+ {
+ /*
+ * If the assignment has not changed, we won't get any notification about
+ * any new configuration from the X server; but we still need to update
+ * our own configuration, as something not applicable in Xrandr might
+ * have changed locally, such as the logical monitors scale. This means we
+ * must check that our new assignment actually changes anything, otherwise
+ * just update the logical state.
+ */
+ if (is_assignments_changed (manager,
+ (GfCrtcInfo **) crtc_infos->pdata,
+ crtc_infos->len,
+ (GfOutputInfo **) output_infos->pdata,
+ output_infos->len))
+ {
+ apply_crtc_assignments (manager,
+ TRUE,
+ (GfCrtcInfo **) crtc_infos->pdata,
+ crtc_infos->len,
+ (GfOutputInfo **) output_infos->pdata,
+ output_infos->len);
+ }
+ else
+ {
+ gf_monitor_manager_rebuild_derived (manager, config);
+ }
+ }
+
+ g_ptr_array_free (crtc_infos, TRUE);
+ g_ptr_array_free (output_infos, TRUE);
+
+ return TRUE;
}
static void
@@ -362,6 +1768,23 @@ gf_monitor_manager_xrandr_change_backlight (GfMonitorManager *manager,
GfOutput *output,
gint value)
{
+ GfMonitorManagerXrandr *xrandr;
+ gint hw_value;
+ Atom atom;
+
+ xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+ hw_value = round ((gdouble) value / 100.0 * output->backlight_max + output->backlight_min);
+ atom = XInternAtom (xrandr->xdisplay, "Backlight", False);
+
+ xcb_randr_change_output_property (XGetXCBConnection (xrandr->xdisplay),
+ (XID)output->winsys_id,
+ atom, XCB_ATOM_INTEGER, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &hw_value);
+
+ /* We're not selecting for property notifies, so update the value immediately */
+ output->backlight = normalize_backlight (output, hw_value);
}
static void
@@ -594,5 +2017,41 @@ gboolean
gf_monitor_manager_xrandr_handle_xevent (GfMonitorManagerXrandr *xrandr,
XEvent *event)
{
- return FALSE;
+ GfMonitorManager *manager;
+ XRRScreenResources *resources;
+
+ manager = GF_MONITOR_MANAGER (xrandr);
+
+ if ((event->type - xrandr->rr_event_base) != RRScreenChangeNotify)
+ return FALSE;
+
+ XRRUpdateConfiguration (event);
+ gf_monitor_manager_read_current_state (manager);
+
+ resources = xrandr->resources;
+ if (!resources)
+ return TRUE;
+
+ if (resources->timestamp < resources->configTimestamp)
+ {
+ gf_monitor_manager_on_hotplug (manager);
+ }
+ else
+ {
+ GfMonitorsConfig *config;
+
+ config = NULL;
+
+ if (resources->timestamp == xrandr->last_xrandr_set_timestamp)
+ {
+ GfMonitorConfigManager *config_manager;
+
+ config_manager = gf_monitor_manager_get_config_manager (manager);
+ config = gf_monitor_config_manager_get_current (config_manager);
+ }
+
+ gf_monitor_manager_rebuild_derived (manager, config);
+ }
+
+ return TRUE;
}
diff --git a/backends/gf-monitor-manager.c b/backends/gf-monitor-manager.c
index 5d2dea4..1f8e18e 100644
--- a/backends/gf-monitor-manager.c
+++ b/backends/gf-monitor-manager.c
@@ -26,14 +26,26 @@
*/
#include "config.h"
+
+#include <string.h>
+
+#include "gf-crtc-private.h"
+#include "gf-logical-monitor-private.h"
+#include "gf-monitor-config-manager-private.h"
#include "gf-monitor-manager-private.h"
-#include "gf-monitor-spec-private.h"
+#include "gf-monitor-normal-private.h"
#include "gf-monitor-private.h"
+#include "gf-monitor-spec-private.h"
+#include "gf-monitor-tiled-private.h"
+#include "gf-monitors-config-private.h"
+#include "gf-output-private.h"
typedef struct
{
GfBackend *backend;
+ gboolean in_init;
+
guint bus_name_id;
} GfMonitorManagerPrivate;
@@ -65,6 +77,25 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GfMonitorManager, gf_monitor_manager, GF_DBUS_
G_ADD_PRIVATE (GfMonitorManager)
G_IMPLEMENT_INTERFACE (GF_DBUS_TYPE_DISPLAY_CONFIG,
gf_monitor_manager_display_config_init))
+static void
+gf_monitor_manager_update_monitor_modes_derived (GfMonitorManager *manager)
+{
+ GList *l;
+
+ for (l = manager->monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+
+ gf_monitor_derive_current_mode (monitor);
+ }
+}
+
+static void
+gf_monitor_manager_notify_monitors_changed (GfMonitorManager *manager)
+{
+ g_signal_emit_by_name (manager, "monitors-changed");
+}
+
static GfMonitor *
find_monitor (GfMonitorManager *monitor_manager,
MonitorMatchFunc match_func)
@@ -85,6 +116,373 @@ find_monitor (GfMonitorManager *monitor_manager,
}
static gboolean
+gf_monitor_manager_is_config_applicable (GfMonitorManager *manager,
+ GfMonitorsConfig *config,
+ GError **error)
+{
+ GList *l;
+
+ for (l = config->logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *logical_monitor_config = l->data;
+ gfloat scale = logical_monitor_config->scale;
+ GList *k;
+
+ for (k = logical_monitor_config->monitor_configs; k; k = k->next)
+ {
+ GfMonitorConfig *monitor_config = k->data;
+ GfMonitorSpec *monitor_spec = monitor_config->monitor_spec;
+ GfMonitorModeSpec *mode_spec = monitor_config->mode_spec;
+ GfMonitor *monitor;
+ GfMonitorMode *monitor_mode;
+
+ monitor = gf_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
+ if (!monitor)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Specified monitor not found");
+
+ return FALSE;
+ }
+
+ monitor_mode = gf_monitor_get_mode_from_spec (monitor, mode_spec);
+ if (!monitor_mode)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Specified monitor mode not available");
+
+ return FALSE;
+ }
+
+ if (!gf_monitor_manager_is_scale_supported (manager, config->layout_mode,
+ monitor, monitor_mode, scale))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Scale not supported by backend");
+
+ return FALSE;
+ }
+
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gf_monitor_manager_is_config_complete (GfMonitorManager *manager,
+ GfMonitorsConfig *config)
+{
+ GList *l;
+ guint configured_monitor_count = 0;
+ guint expected_monitor_count = 0;
+
+ for (l = config->logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *logical_monitor_config = l->data;
+ GList *k;
+
+ for (k = logical_monitor_config->monitor_configs; k; k = k->next)
+ configured_monitor_count++;
+ }
+
+ for (l = manager->monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+
+ if (gf_monitor_is_laptop_panel (monitor))
+ {
+ if (!gf_monitor_manager_is_lid_closed (manager))
+ expected_monitor_count++;
+ }
+ else
+ {
+ expected_monitor_count++;
+ }
+ }
+
+ if (configured_monitor_count != expected_monitor_count)
+ return FALSE;
+
+ return gf_monitor_manager_is_config_applicable (manager, config, NULL);
+}
+
+static gboolean
+should_use_stored_config (GfMonitorManager *manager)
+{
+ GfMonitorManagerPrivate *priv;
+
+ priv = gf_monitor_manager_get_instance_private (manager);
+
+ return (priv->in_init || !gf_monitor_manager_has_hotplug_mode_update (manager));
+}
+
+static gfloat
+derive_configured_global_scale (GfMonitorManager *manager,
+ GfMonitorsConfig *config)
+{
+ GfLogicalMonitorConfig *logical_monitor_config;
+
+ logical_monitor_config = config->logical_monitor_configs->data;
+
+ return logical_monitor_config->scale;
+}
+
+static gfloat
+calculate_monitor_scale (GfMonitorManager *manager,
+ GfMonitor *monitor)
+{
+ GfMonitorMode *monitor_mode;
+
+ monitor_mode = gf_monitor_get_current_mode (monitor);
+ return gf_monitor_manager_calculate_monitor_mode_scale (manager, monitor,
+ monitor_mode);
+}
+
+static gfloat
+derive_calculated_global_scale (GfMonitorManager *manager)
+{
+ GfMonitor *primary_monitor;
+
+ primary_monitor = gf_monitor_manager_get_primary_monitor (manager);
+ if (!primary_monitor)
+ return 1.0;
+
+ return calculate_monitor_scale (manager, primary_monitor);
+}
+
+static GfLogicalMonitor *
+logical_monitor_from_layout (GfMonitorManager *manager,
+ GList *logical_monitors,
+ GfRectangle *layout)
+{
+ GList *l;
+
+ for (l = logical_monitors; l; l = l->next)
+ {
+ GfLogicalMonitor *logical_monitor = l->data;
+
+ if (gf_rectangle_equal (layout, &logical_monitor->rect))
+ return logical_monitor;
+ }
+
+ return NULL;
+}
+
+static gfloat
+derive_scale_from_config (GfMonitorManager *manager,
+ GfMonitorsConfig *config,
+ GfRectangle *layout)
+{
+ GList *l;
+
+ for (l = config->logical_monitor_configs; l; l = l->next)
+ {
+ GfLogicalMonitorConfig *logical_monitor_config = l->data;
+
+ if (gf_rectangle_equal (layout, &logical_monitor_config->layout))
+ return logical_monitor_config->scale;
+ }
+
+ g_warning ("Missing logical monitor, using scale 1");
+ return 1.0;
+}
+
+static void
+gf_monitor_manager_set_primary_logical_monitor (GfMonitorManager *manager,
+ GfLogicalMonitor *logical_monitor)
+{
+ manager->primary_logical_monitor = logical_monitor;
+ if (logical_monitor)
+ gf_logical_monitor_make_primary (logical_monitor);
+}
+
+static void
+gf_monitor_manager_rebuild_logical_monitors_derived (GfMonitorManager *manager,
+ GfMonitorsConfig *config)
+{
+ GList *logical_monitors = NULL;
+ GList *l;
+ gint monitor_number;
+ GfLogicalMonitor *primary_logical_monitor = NULL;
+ gboolean use_global_scale;
+ gfloat global_scale = 0.0;
+ GfMonitorManagerCapability capabilities;
+
+ monitor_number = 0;
+
+ capabilities = gf_monitor_manager_get_capabilities (manager);
+ use_global_scale = !!(capabilities & GF_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED);
+
+ if (use_global_scale)
+ {
+ if (config)
+ global_scale = derive_configured_global_scale (manager, config);
+ else
+ global_scale = derive_calculated_global_scale (manager);
+ }
+
+ for (l = manager->monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfLogicalMonitor *logical_monitor;
+ GfRectangle layout;
+
+ if (!gf_monitor_is_active (monitor))
+ continue;
+
+ gf_monitor_derive_layout (monitor, &layout);
+ logical_monitor = logical_monitor_from_layout (manager, logical_monitors,
+ &layout);
+ if (logical_monitor)
+ {
+ gf_logical_monitor_add_monitor (logical_monitor, monitor);
+ }
+ else
+ {
+ gfloat scale;
+
+ if (use_global_scale)
+ scale = global_scale;
+ else if (config)
+ scale = derive_scale_from_config (manager, config, &layout);
+ else
+ scale = calculate_monitor_scale (manager, monitor);
+
+ g_assert (scale > 0);
+
+ logical_monitor = gf_logical_monitor_new_derived (manager, monitor,
+ &layout, scale,
+ monitor_number);
+
+ logical_monitors = g_list_append (logical_monitors, logical_monitor);
+ monitor_number++;
+ }
+
+ if (gf_monitor_is_primary (monitor))
+ primary_logical_monitor = logical_monitor;
+ }
+
+ manager->logical_monitors = logical_monitors;
+
+ /*
+ * If no monitor was marked as primary, fall back on marking the first
+ * logical monitor the primary one.
+ */
+ if (!primary_logical_monitor && manager->logical_monitors)
+ primary_logical_monitor = g_list_first (manager->logical_monitors)->data;
+
+ gf_monitor_manager_set_primary_logical_monitor (manager, primary_logical_monitor);
+}
+
+static gboolean
+gf_monitor_manager_apply_monitors_config (GfMonitorManager *manager,
+ GfMonitorsConfig *config,
+ GfMonitorsConfigMethod method,
+ GError **error)
+{
+ GfMonitorManagerClass *manager_class;
+
+ g_assert (!config || !(config->flags & GF_MONITORS_CONFIG_FLAG_MIGRATED));
+
+ manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+ if (!manager_class->apply_monitors_config (manager, config, method, error))
+ return FALSE;
+
+ switch (method)
+ {
+ case GF_MONITORS_CONFIG_METHOD_TEMPORARY:
+ case GF_MONITORS_CONFIG_METHOD_PERSISTENT:
+ gf_monitor_config_manager_set_current (manager->config_manager, config);
+ break;
+
+ case GF_MONITORS_CONFIG_METHOD_VERIFY:
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+is_main_tiled_monitor_output (GfOutput *output)
+{
+ return output->tile_info.loc_h_tile == 0 && output->tile_info.loc_v_tile == 0;
+}
+
+static void
+rebuild_monitors (GfMonitorManager *manager)
+{
+ guint i;
+
+ if (manager->monitors)
+ {
+ g_list_free_full (manager->monitors, g_object_unref);
+ manager->monitors = NULL;
+ }
+
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ GfOutput *output = &manager->outputs[i];
+
+ if (output->tile_info.group_id)
+ {
+ if (is_main_tiled_monitor_output (output))
+ {
+ GfMonitorTiled *monitor_tiled;
+
+ monitor_tiled = gf_monitor_tiled_new (manager, output);
+ manager->monitors = g_list_append (manager->monitors, monitor_tiled);
+ }
+ }
+ else
+ {
+ GfMonitorNormal *monitor_normal;
+
+ monitor_normal = gf_monitor_normal_new (manager, output);
+ manager->monitors = g_list_append (manager->monitors, monitor_normal);
+ }
+ }
+}
+
+static void
+free_output_array (GfOutput *old_outputs,
+ gint n_old_outputs)
+{
+ gint i;
+
+ for (i = 0; i < n_old_outputs; i++)
+ gf_monitor_manager_clear_output (&old_outputs[i]);
+
+ g_free (old_outputs);
+}
+
+static void
+free_mode_array (GfCrtcMode *old_modes,
+ gint n_old_modes)
+{
+ gint i;
+
+ for (i = 0; i < n_old_modes; i++)
+ gf_monitor_manager_clear_mode (&old_modes[i]);
+
+ g_free (old_modes);
+}
+
+static void
+free_crtc_array (GfCrtc *old_crtcs,
+ gint n_old_crtcs)
+{
+ gint i;
+
+ for (i = 0; i < n_old_crtcs; i++)
+ gf_monitor_manager_clear_crtc (&old_crtcs[i]);
+
+ g_free (old_crtcs);
+}
+
+static gboolean
gf_monitor_manager_handle_get_resources (GfDBusDisplayConfig *skeleton,
GDBusMethodInvocation *invocation)
{
@@ -225,6 +623,8 @@ gf_monitor_manager_constructed (GObject *object)
name_lost_cb,
g_object_ref (manager),
g_object_unref);
+
+ priv->in_init = FALSE;
}
static void
@@ -339,6 +739,11 @@ gf_monitor_manager_class_init (GfMonitorManagerClass *manager_class)
static void
gf_monitor_manager_init (GfMonitorManager *manager)
{
+ GfMonitorManagerPrivate *priv;
+
+ priv = gf_monitor_manager_get_instance_private (manager);
+
+ priv->in_init = TRUE;
}
GfBackend *
@@ -351,6 +756,28 @@ gf_monitor_manager_get_backend (GfMonitorManager *manager)
return priv->backend;
}
+void
+gf_monitor_manager_rebuild_derived (GfMonitorManager *manager,
+ GfMonitorsConfig *config)
+{
+ GfMonitorManagerPrivate *priv;
+ GList *old_logical_monitors;
+
+ priv = gf_monitor_manager_get_instance_private (manager);
+
+ gf_monitor_manager_update_monitor_modes_derived (manager);
+
+ if (priv->in_init)
+ return;
+
+ old_logical_monitors = manager->logical_monitors;
+
+ gf_monitor_manager_update_logical_state_derived (manager, config);
+ gf_monitor_manager_notify_monitors_changed (manager);
+
+ g_list_free_full (old_logical_monitors, g_object_unref);
+}
+
GfMonitor *
gf_monitor_manager_get_primary_monitor (GfMonitorManager *manager)
{
@@ -386,6 +813,59 @@ gf_monitor_manager_get_monitors (GfMonitorManager *manager)
return manager->monitors;
}
+gboolean
+gf_monitor_manager_has_hotplug_mode_update (GfMonitorManager *manager)
+{
+ guint i;
+
+ for (i = 0; i < manager->n_outputs; i++)
+ {
+ GfOutput *output = &manager->outputs[i];
+
+ if (output->hotplug_mode_update)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+gf_monitor_manager_read_current_state (GfMonitorManager *manager)
+{
+ GfOutput *old_outputs;
+ GfCrtc *old_crtcs;
+ GfCrtcMode *old_modes;
+ guint n_old_outputs;
+ guint n_old_crtcs;
+ guint 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_crtcs = manager->crtcs;
+ n_old_crtcs = manager->n_crtcs;
+ old_modes = manager->modes;
+ n_old_modes = manager->n_modes;
+
+ manager->serial++;
+ GF_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
+
+ rebuild_monitors (manager);
+
+ free_output_array (old_outputs, n_old_outputs);
+ free_mode_array (old_modes, n_old_modes);
+ free_crtc_array (old_crtcs, n_old_crtcs);
+}
+
+void
+gf_monitor_manager_on_hotplug (GfMonitorManager *manager)
+{
+ gf_monitor_manager_ensure_configured (manager);
+}
+
void
gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
GfMonitor *monitor)
@@ -422,6 +902,145 @@ gf_monitor_manager_is_transform_handled (GfMonitorManager *manager,
return manager_class->is_transform_handled (manager, crtc, transform);
}
+GfMonitorsConfig *
+gf_monitor_manager_ensure_configured (GfMonitorManager *manager)
+{
+ gboolean use_stored_config;
+ GfMonitorsConfigMethod method;
+ GfMonitorsConfigMethod fallback_method;
+ GfMonitorsConfig *config;
+ GError *error;
+
+ use_stored_config = should_use_stored_config (manager);
+ if (use_stored_config)
+ method = GF_MONITORS_CONFIG_METHOD_PERSISTENT;
+ else
+ method = GF_MONITORS_CONFIG_METHOD_TEMPORARY;
+
+ fallback_method = GF_MONITORS_CONFIG_METHOD_TEMPORARY;
+ config = NULL;
+ error = NULL;
+
+ if (use_stored_config)
+ {
+ config = gf_monitor_config_manager_get_stored (manager->config_manager);
+
+ if (config)
+ {
+ if (!gf_monitor_manager_apply_monitors_config (manager, config,
+ method, &error))
+ {
+ config = NULL;
+ g_warning ("Failed to use stored monitor configuration: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ g_object_ref (config);
+ goto done;
+ }
+ }
+ }
+
+ config = gf_monitor_config_manager_create_suggested (manager->config_manager);
+ if (config)
+ {
+ if (!gf_monitor_manager_apply_monitors_config (manager, config,
+ method, &error))
+ {
+ g_clear_object (&config);
+ g_warning ("Failed to use suggested monitor configuration: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ goto done;
+ }
+ }
+
+ config = gf_monitor_config_manager_get_previous (manager->config_manager);
+ if (config)
+ {
+ config = g_object_ref (config);
+
+ if (gf_monitor_manager_is_config_complete (manager, config))
+ {
+ if (!gf_monitor_manager_apply_monitors_config (manager, config,
+ method, &error))
+ {
+ g_warning ("Failed to use suggested monitor configuration: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ goto done;
+ }
+ }
+
+ g_clear_object (&config);
+ }
+
+ config = gf_monitor_config_manager_create_linear (manager->config_manager);
+ if (config)
+ {
+ if (!gf_monitor_manager_apply_monitors_config (manager, config,
+ method, &error))
+ {
+ g_clear_object (&config);
+ g_warning ("Failed to use linear monitor configuration: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ goto done;
+ }
+ }
+
+ config = gf_monitor_config_manager_create_fallback (manager->config_manager);
+ if (config)
+ {
+ if (!gf_monitor_manager_apply_monitors_config (manager, config,
+ fallback_method,
+ &error))
+ {
+ g_clear_object (&config);
+ g_warning ("Failed to use fallback monitor configuration: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ goto done;
+ }
+ }
+
+done:
+ if (!config)
+ {
+ gf_monitor_manager_apply_monitors_config (manager, NULL,
+ fallback_method,
+ &error);
+ return NULL;
+ }
+
+ g_object_unref (config);
+
+ return config;
+}
+
+void
+gf_monitor_manager_update_logical_state_derived (GfMonitorManager *manager,
+ GfMonitorsConfig *config)
+{
+ manager->layout_mode = GF_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
+
+ gf_monitor_manager_rebuild_logical_monitors_derived (manager, config);
+}
+
gboolean
gf_monitor_manager_is_lid_closed (GfMonitorManager *manager)
{
@@ -440,6 +1059,50 @@ gf_monitor_manager_calculate_monitor_mode_scale (GfMonitorManager *manager,
return manager_class->calculate_monitor_mode_scale (manager, monitor, monitor_mode);
}
+gfloat *
+gf_monitor_manager_calculate_supported_scales (GfMonitorManager *manager,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GfMonitor *monitor,
+ GfMonitorMode *monitor_mode,
+ gint *n_supported_scales)
+{
+ GfMonitorManagerClass *manager_class;
+
+ manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+ return manager_class->calculate_supported_scales (manager, layout_mode,
+ monitor, monitor_mode,
+ n_supported_scales);
+}
+
+gboolean
+gf_monitor_manager_is_scale_supported (GfMonitorManager *manager,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GfMonitor *monitor,
+ GfMonitorMode *monitor_mode,
+ gfloat scale)
+{
+ gfloat *supported_scales;
+ gint n_supported_scales;
+ gint i;
+
+ supported_scales = gf_monitor_manager_calculate_supported_scales (manager, layout_mode,
+ monitor, monitor_mode,
+ &n_supported_scales);
+
+ for (i = 0; i < n_supported_scales; i++)
+ {
+ if (supported_scales[i] == scale)
+ {
+ g_free (supported_scales);
+ return TRUE;
+ }
+ }
+
+ g_free (supported_scales);
+ return FALSE;
+}
+
GfMonitorManagerCapability
gf_monitor_manager_get_capabilities (GfMonitorManager *manager)
{
@@ -460,6 +1123,49 @@ gf_monitor_manager_get_default_layout_mode (GfMonitorManager *manager)
return manager_class->get_default_layout_mode (manager);
}
+GfMonitorConfigManager *
+gf_monitor_manager_get_config_manager (GfMonitorManager *manager)
+{
+ return manager->config_manager;
+}
+
+void
+gf_monitor_manager_clear_output (GfOutput *output)
+{
+ g_free (output->name);
+ g_free (output->vendor);
+ g_free (output->product);
+ g_free (output->serial);
+ g_free (output->modes);
+ g_free (output->possible_crtcs);
+ g_free (output->possible_clones);
+
+ if (output->driver_notify)
+ output->driver_notify (output);
+
+ memset (output, 0, sizeof (*output));
+}
+
+void
+gf_monitor_manager_clear_mode (GfCrtcMode *mode)
+{
+ g_free (mode->name);
+
+ if (mode->driver_notify)
+ mode->driver_notify (mode);
+
+ memset (mode, 0, sizeof (*mode));
+}
+
+void
+gf_monitor_manager_clear_crtc (GfCrtc *crtc)
+{
+ if (crtc->driver_notify)
+ crtc->driver_notify (crtc);
+
+ memset (crtc, 0, sizeof (*crtc));
+}
+
gboolean
gf_monitor_manager_get_is_builtin_display_on (GfMonitorManager *manager)
{
diff --git a/configure.ac b/configure.ac
index 896021c..b0ca8a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,7 +105,9 @@ PKG_CHECK_MODULES([BACKENDS], [
glib-2.0 >= $GLIB_REQUIRED
gnome-desktop-3.0 >= $LIBGNOME_DESKTOP_REQUIRED
upower-glib >= $UPOWER_GLIB_REQUIRED
+ xcb-randr
xrandr >= $XRANDR_REQUIRED
+ x11-xcb
x11
])
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]