[gnome-flashback] backends: move output code to its own file
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] backends: move output code to its own file
- Date: Mon, 15 Jul 2019 11:52:56 +0000 (UTC)
commit 73a4e6d7c7ad33306bc740b6e367a0edc7676c39
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sun Jul 7 13:40:51 2019 +0300
backends: move output code to its own file
Based on mutter commit:
https://gitlab.gnome.org/GNOME/mutter/commit/e32d52b9b8eca6c82747
backends/Makefile.am | 2 +
backends/gf-monitor-manager-xrandr-private.h | 4 +-
backends/gf-monitor-manager-xrandr.c | 781 +------------------------
backends/gf-output-xrandr-private.h | 43 ++
backends/gf-output-xrandr.c | 828 +++++++++++++++++++++++++++
5 files changed, 898 insertions(+), 760 deletions(-)
---
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 8fb7432..e6b9fc4 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -74,6 +74,8 @@ libbackends_la_SOURCES = \
gf-orientation-manager-private.h \
gf-orientation-manager.c \
gf-output-private.h \
+ gf-output-xrandr-private.h \
+ gf-output-xrandr.c \
gf-output.c \
gf-rectangle-private.h \
gf-rectangle.c \
diff --git a/backends/gf-monitor-manager-xrandr-private.h b/backends/gf-monitor-manager-xrandr-private.h
index e76699f..d439083 100644
--- a/backends/gf-monitor-manager-xrandr-private.h
+++ b/backends/gf-monitor-manager-xrandr-private.h
@@ -3,7 +3,7 @@
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
- * Copyright (C) 2017 Alberts Muktupāvels
+ * Copyright (C) 2017-2019 Alberts Muktupāvels
*
* 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
@@ -38,6 +38,8 @@ G_DECLARE_FINAL_TYPE (GfMonitorManagerXrandr, gf_monitor_manager_xrandr,
Display *gf_monitor_manager_xrandr_get_xdisplay (GfMonitorManagerXrandr *xrandr);
+gboolean gf_monitor_manager_xrandr_has_randr15 (GfMonitorManagerXrandr *xrandr);
+
XRRScreenResources *gf_monitor_manager_xrandr_get_resources (GfMonitorManagerXrandr *xrandr);
gboolean gf_monitor_manager_xrandr_handle_xevent (GfMonitorManagerXrandr *xrandr,
diff --git a/backends/gf-monitor-manager-xrandr.c b/backends/gf-monitor-manager-xrandr.c
index 780dbd7..d221354 100644
--- a/backends/gf-monitor-manager-xrandr.c
+++ b/backends/gf-monitor-manager-xrandr.c
@@ -6,7 +6,7 @@
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
- * Copyright (C) 2017 Alberts Muktupāvels
+ * Copyright (C) 2017-2019 Alberts Muktupāvels
*
* 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
@@ -30,8 +30,7 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
-#include <X11/Xatom.h>
-#include <X11/extensions/Xrandr.h>
+#include <X11/Xlibint.h>
#include <X11/extensions/dpms.h>
#include <X11/Xlib-xcb.h>
#include <xcb/randr.h>
@@ -42,7 +41,7 @@
#include "gf-monitor-manager-xrandr-private.h"
#include "gf-monitor-private.h"
#include "gf-monitor-tiled-private.h"
-#include "gf-output-private.h"
+#include "gf-output-xrandr-private.h"
/* Look for DPI_FALLBACK in:
* http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
@@ -199,71 +198,6 @@ xrandr_set_crtc_config (GfMonitorManagerXrandr *xrandr,
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,
@@ -389,69 +323,6 @@ is_assignments_changed (GfMonitorManager *manager,
return FALSE;
}
-static guint8 *
-get_edid_property (Display *xdisplay,
- RROutput output,
- Atom atom,
- gsize *len)
-{
- guchar *prop;
- gint actual_format;
- gulong nitems, bytes_after;
- Atom actual_type;
- guint8 *result;
-
- XRRGetOutputProperty (xdisplay, 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;
- }
-
- if (prop)
- XFree (prop);
-
- return result;
-}
-
-static GBytes *
-read_output_edid (GfMonitorManagerXrandr *xrandr,
- XID winsys_id)
-{
- Atom edid_atom;
- guint8 *result;
- gsize len;
-
- edid_atom = XInternAtom (xrandr->xdisplay, "EDID", FALSE);
- result = get_edid_property (xrandr->xdisplay, winsys_id, edid_atom, &len);
-
- if (!result)
- {
- edid_atom = XInternAtom (xrandr->xdisplay, "EDID_DATA", FALSE);
- result = get_edid_property (xrandr->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 xcb_randr_rotation_t
gf_monitor_transform_to_xrandr (GfMonitorTransform transform)
{
@@ -501,548 +372,6 @@ gf_monitor_transform_to_xrandr (GfMonitorTransform transform)
return rotation;
}
-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;
- 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++)
- {
- GList *l;
-
- for (l = manager->modes; l; l = l->next)
- {
- GfCrtcMode *mode = l->data;
-
- if (xrandr_output->modes[j] == (XID) mode->mode_id)
- {
- output->modes[n_actual_modes] = mode;
- 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;
- guint n_actual_crtcs;
- GList *l;
-
- output->possible_crtcs = g_new0 (GfCrtc *, xrandr_output->ncrtc);
-
- n_actual_crtcs = 0;
- for (j = 0; j < (guint) xrandr_output->ncrtc; j++)
- {
- for (l = manager->crtcs; l; l = l->next)
- {
- GfCrtc *crtc = l->data;
-
- if ((XID) crtc->crtc_id == xrandr_output->crtcs[j])
- {
- output->possible_crtcs[n_actual_crtcs] = crtc;
- n_actual_crtcs += 1;
- break;
- }
- }
- }
- output->n_possible_crtcs = n_actual_crtcs;
-
- output->crtc = NULL;
- for (l = manager->crtcs; l; l = l->next)
- {
- GfCrtc *crtc = l->data;
-
- if ((XID) crtc->crtc_id == xrandr_output->crtc)
- {
- output->crtc = crtc;
- 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)
@@ -1242,22 +571,11 @@ apply_crtc_assignments (GfMonitorManager *manager,
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;
+
+ gf_output_xrandr_apply_mode (output);
}
/* Disable outputs not mentioned in the list */
@@ -1547,67 +865,26 @@ gf_monitor_manager_xrandr_read_current (GfMonitorManager *manager)
for (i = 0; i < (guint) resources->noutput; i++)
{
+ RROutput output_id;
XRROutputInfo *xrandr_output;
- GfOutput *output;
+ output_id = resources->outputs[i];
xrandr_output = XRRGetOutputInfo (xrandr->xdisplay, resources,
- resources->outputs[i]);
+ output_id);
if (!xrandr_output)
continue;
if (xrandr_output->connection != RR_Disconnected)
{
- GBytes *edid;
-
- output = g_object_new (GF_TYPE_OUTPUT, NULL);
- output->monitor_manager = manager;
-
- 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);
+ GfOutput *output;
- if (!(output->backlight_min == 0 && output->backlight_max == 0))
- output->backlight = output_get_backlight_xrandr (xrandr, output);
- else
- output->backlight = -1;
+ output = gf_create_xrandr_output (manager,
+ xrandr_output,
+ output_id,
+ primary_output);
- if (output->n_modes == 0 || output->n_possible_crtcs == 0)
- g_object_unref (output);
- else
+ if (output)
manager->outputs = g_list_prepend (manager->outputs, output);
}
@@ -1647,11 +924,7 @@ static GBytes *
gf_monitor_manager_xrandr_read_edid (GfMonitorManager *manager,
GfOutput *output)
{
- GfMonitorManagerXrandr *xrandr;
-
- xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
-
- return read_output_edid (xrandr, output->winsys_id);
+ return gf_output_xrandr_read_edid (output);
}
static void
@@ -1770,23 +1043,7 @@ 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);
+ gf_output_xrandr_change_backlight (output, value);
}
static void
@@ -2023,6 +1280,12 @@ gf_monitor_manager_xrandr_get_xdisplay (GfMonitorManagerXrandr *xrandr)
return xrandr->xdisplay;
}
+gboolean
+gf_monitor_manager_xrandr_has_randr15 (GfMonitorManagerXrandr *xrandr)
+{
+ return xrandr->has_randr15;
+}
+
XRRScreenResources *
gf_monitor_manager_xrandr_get_resources (GfMonitorManagerXrandr *xrandr)
{
diff --git a/backends/gf-output-xrandr-private.h b/backends/gf-output-xrandr-private.h
new file mode 100644
index 0000000..01e55b8
--- /dev/null
+++ b/backends/gf-output-xrandr-private.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 Red Hat
+ * Copyright (C) 2019 Alberts Muktupāvels
+ *
+ * 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/>.
+ */
+
+#ifndef GF_OUTPUT_XRANDR_PRIVATE_H
+#define GF_OUTPUT_XRANDR_PRIVATE_H
+
+#include <X11/extensions/Xrandr.h>
+
+#include "gf-monitor-manager-xrandr-private.h"
+#include "gf-output-private.h"
+
+G_BEGIN_DECLS
+
+GfOutput *gf_create_xrandr_output (GfMonitorManager *monitor_manager,
+ XRROutputInfo *xrandr_output,
+ RROutput output_id,
+ RROutput primary_output);
+
+GBytes *gf_output_xrandr_read_edid (GfOutput *output);
+
+void gf_output_xrandr_apply_mode (GfOutput *output);
+
+void gf_output_xrandr_change_backlight (GfOutput *output,
+ int value);
+
+G_END_DECLS
+
+#endif
diff --git a/backends/gf-output-xrandr.c b/backends/gf-output-xrandr.c
new file mode 100644
index 0000000..c266644
--- /dev/null
+++ b/backends/gf-output-xrandr.c
@@ -0,0 +1,828 @@
+/*
+ * Copyright (C) 2001, 2002 Havoc Pennington
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ * Some ICCCM manager selection code derived from fvwm2,
+ * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013-2017 Red Hat Inc.
+ * Copyright (C) 2017-2019 Alberts Muktupāvels
+ *
+ * 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/>.
+ */
+
+#include "config.h"
+#include "gf-output-xrandr-private.h"
+
+#include <math.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/Xlib-xcb.h>
+#include <xcb/randr.h>
+
+#include "gf-crtc-private.h"
+
+static Display *
+xdisplay_from_output (GfOutput *output)
+{
+ GfMonitorManager *monitor_manager;
+ GfMonitorManagerXrandr *monitor_manager_xrandr;
+
+ monitor_manager = gf_output_get_monitor_manager (output);
+ monitor_manager_xrandr = GF_MONITOR_MANAGER_XRANDR (monitor_manager);
+
+ return gf_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
+}
+
+static void
+output_set_presentation_xrandr (GfOutput *output,
+ gboolean presentation)
+{
+ Display *xdisplay;
+ Atom atom;
+ gint value;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, "_GNOME_FLASHBACK_PRESENTATION_OUTPUT", False);
+ value= presentation;
+
+ xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+ (XID) output->winsys_id,
+ atom, XCB_ATOM_CARDINAL, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &value);
+}
+
+static void
+output_set_underscanning_xrandr (GfOutput *output,
+ gboolean underscanning)
+{
+ Display *xdisplay;
+ Atom prop, valueatom;
+ const gchar *value;
+
+ xdisplay = xdisplay_from_output (output);
+ prop = XInternAtom (xdisplay, "underscan", False);
+
+ value = underscanning ? "on" : "off";
+ valueatom = XInternAtom (xdisplay, value, False);
+
+ xcb_randr_change_output_property (XGetXCBConnection (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 (xdisplay, "underscan hborder", False);
+ border_value = output->crtc->current_mode->width * 0.05;
+
+ xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+ (XID) output->winsys_id,
+ prop, XCB_ATOM_INTEGER, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &border_value);
+
+ prop = XInternAtom (xdisplay, "underscan vborder", False);
+ border_value = output->crtc->current_mode->height * 0.05;
+
+ xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+ (XID) output->winsys_id,
+ prop, XCB_ATOM_INTEGER, 32,
+ XCB_PROP_MODE_REPLACE,
+ 1, &border_value);
+ }
+}
+
+static guint8 *
+get_edid_property (Display *xdisplay,
+ RROutput output,
+ Atom atom,
+ gsize *len)
+{
+ guchar *prop;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ Atom actual_type;
+ guint8 *result;
+
+ XRRGetOutputProperty (xdisplay, 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;
+ }
+
+ if (prop)
+ XFree (prop);
+
+ return result;
+}
+
+static gboolean
+output_get_property_exists (GfOutput *output,
+ const gchar *propname)
+{
+ Display *xdisplay;
+ gboolean exists;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, propname, False);
+ XRRGetOutputProperty (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 (GfOutput *output)
+{
+ return output_get_property_exists (output, "hotplug_mode_update");
+}
+
+static gboolean
+output_get_integer_property (GfOutput *output,
+ const gchar *propname,
+ gint *value)
+{
+ Display *xdisplay;
+ gboolean exists;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, propname, False);
+ XRRGetOutputProperty (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 (GfOutput *output)
+{
+ gint val;
+
+ if (output_get_integer_property (output, "suggested X", &val))
+ return val;
+
+ return -1;
+}
+
+static gint
+output_get_suggested_y (GfOutput *output)
+{
+ gint val;
+
+ if (output_get_integer_property (output, "suggested Y", &val))
+ return val;
+
+ return -1;
+}
+
+static GfConnectorType
+connector_type_from_atom (Display *xdisplay,
+ Atom atom)
+{
+ 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 (GfOutput *output)
+{
+ Display *xdisplay;
+ Atom atom, actual_type, connector_type_atom;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ GfConnectorType ret;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, "ConnectorType", False);
+ XRRGetOutputProperty (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 (xdisplay, connector_type_atom);
+ XFree (buffer);
+
+ return ret;
+}
+
+static GfConnectorType
+output_get_connector_type_from_name (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 (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 (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 (output);
+ if (ret != GF_CONNECTOR_TYPE_Unknown)
+ return ret;
+
+ return GF_CONNECTOR_TYPE_Unknown;
+}
+
+static void
+output_get_tile_info (GfOutput *output)
+{
+ GfMonitorManager *monitor_manager;
+ GfMonitorManagerXrandr *monitor_manager_xrandr;
+ Display *xdisplay;
+ Atom tile_atom;
+ guchar *prop;
+ gulong nitems, bytes_after;
+ gint actual_format;
+ Atom actual_type;
+
+ monitor_manager = gf_output_get_monitor_manager (output);
+ monitor_manager_xrandr = GF_MONITOR_MANAGER_XRANDR (monitor_manager);
+
+ if (!gf_monitor_manager_xrandr_has_randr15 (monitor_manager_xrandr))
+ return;
+
+ xdisplay = gf_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
+ tile_atom = XInternAtom (xdisplay, "TILE", FALSE);
+ XRRGetOutputProperty (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;
+ 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++)
+ {
+ GList *l;
+
+ for (l = manager->modes; l; l = l->next)
+ {
+ GfCrtcMode *mode = l->data;
+
+ if (xrandr_output->modes[j] == (XID) mode->mode_id)
+ {
+ output->modes[n_actual_modes] = mode;
+ 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;
+ guint n_actual_crtcs;
+ GList *l;
+
+ output->possible_crtcs = g_new0 (GfCrtc *, xrandr_output->ncrtc);
+
+ n_actual_crtcs = 0;
+ for (j = 0; j < (guint) xrandr_output->ncrtc; j++)
+ {
+ for (l = manager->crtcs; l; l = l->next)
+ {
+ GfCrtc *crtc = l->data;
+
+ if ((XID) crtc->crtc_id == xrandr_output->crtcs[j])
+ {
+ output->possible_crtcs[n_actual_crtcs] = crtc;
+ n_actual_crtcs += 1;
+ break;
+ }
+ }
+ }
+ output->n_possible_crtcs = n_actual_crtcs;
+
+ output->crtc = NULL;
+ for (l = manager->crtcs; l; l = l->next)
+ {
+ GfCrtc *crtc = l->data;
+
+ if ((XID) crtc->crtc_id == xrandr_output->crtc)
+ {
+ output->crtc = crtc;
+ break;
+ }
+ }
+}
+
+static gboolean
+output_get_boolean_property (GfOutput *output,
+ const gchar *propname)
+{
+ Display *xdisplay;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ gboolean value;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, propname, False);
+ XRRGetOutputProperty (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 (GfOutput *output)
+{
+ return output_get_boolean_property (output, "_GNOME_FLASHBACK_PRESENTATION_OUTPUT");
+}
+
+static gboolean
+output_get_underscanning_xrandr (GfOutput *output)
+{
+ Display *xdisplay;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ gchar *str;
+ gboolean value;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, "underscan", False);
+ XRRGetOutputProperty (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 (xdisplay, *(Atom *)buffer);
+ XFree (buffer);
+
+ value = !strcmp (str, "on");
+ XFree (str);
+
+ return value;
+}
+
+static gboolean
+output_get_supports_underscanning_xrandr (GfOutput *output)
+{
+ Display *xdisplay;
+ Atom atom, actual_type;
+ gint actual_format, i;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+ XRRPropertyInfo *property_info;
+ Atom *values;
+ gboolean supports_underscanning = FALSE;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, "underscan", False);
+ XRRGetOutputProperty (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 (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 (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 (GfOutput *output)
+{
+ Display *xdisplay;
+ gint value = -1;
+ Atom atom, actual_type;
+ gint actual_format;
+ gulong nitems, bytes_after;
+ guchar *buffer;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, "Backlight", False);
+ XRRGetOutputProperty (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 (GfOutput *output)
+{
+ Display *xdisplay;
+ 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;
+
+ xdisplay = xdisplay_from_output (output);
+ atom = XInternAtom (xdisplay, "Backlight", False);
+
+ xcb_conn = XGetXCBConnection (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);
+}
+
+GfOutput *
+gf_create_xrandr_output (GfMonitorManager *monitor_manager,
+ XRROutputInfo *xrandr_output,
+ RROutput output_id,
+ RROutput primary_output)
+{
+ GfOutput *output;
+ GBytes *edid;
+ unsigned int i;
+
+ output = g_object_new (GF_TYPE_OUTPUT, NULL);
+ output->monitor_manager = monitor_manager;
+
+ output->winsys_id = output_id;
+ output->name = g_strdup (xrandr_output->name);
+
+ edid = gf_output_xrandr_read_edid (output);
+ 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 (output);
+ output->suggested_x = output_get_suggested_x (output);
+ output->suggested_y = output_get_suggested_y (output);
+ output->connector_type = output_get_connector_type (output);
+
+ output_get_tile_info (output);
+ output_get_modes (monitor_manager, output, xrandr_output);
+ output_get_crtcs (monitor_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 (i = 0; i < (unsigned int) xrandr_output->nclone; i++)
+ {
+ output->possible_clones[i] = GINT_TO_POINTER (xrandr_output->clones[i]);
+ }
+
+ output->is_primary = ((XID) output->winsys_id == primary_output);
+ output->is_presentation = output_get_presentation_xrandr (output);
+ output->is_underscanning = output_get_underscanning_xrandr (output);
+ output->supports_underscanning = output_get_supports_underscanning_xrandr (output);
+
+ output_get_backlight_limits_xrandr (output);
+
+ if (!(output->backlight_min == 0 && output->backlight_max == 0))
+ output->backlight = output_get_backlight_xrandr (output);
+ else
+ output->backlight = -1;
+
+ if (output->n_modes == 0 || output->n_possible_crtcs == 0)
+ {
+ g_object_unref (output);
+ return NULL;
+ }
+
+ return output;
+}
+
+GBytes *
+gf_output_xrandr_read_edid (GfOutput *output)
+{
+ Display *xdisplay;
+ Atom edid_atom;
+ guint8 *result;
+ gsize len;
+
+ xdisplay = xdisplay_from_output (output);
+ edid_atom = XInternAtom (xdisplay, "EDID", FALSE);
+ result = get_edid_property (xdisplay, output->winsys_id, edid_atom, &len);
+
+ if (!result)
+ {
+ edid_atom = XInternAtom (xdisplay, "EDID_DATA", FALSE);
+ result = get_edid_property (xdisplay, output->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;
+}
+
+void
+gf_output_xrandr_apply_mode (GfOutput *output)
+{
+ Display *xdisplay;
+
+ xdisplay = xdisplay_from_output (output);
+
+ if (output->is_primary)
+ {
+ XRRSetOutputPrimary (xdisplay, DefaultRootWindow (xdisplay),
+ (XID) output->winsys_id);
+ }
+
+ output_set_presentation_xrandr (output, output->is_presentation);
+
+ if (output->supports_underscanning)
+ output_set_underscanning_xrandr (output, output->is_underscanning);
+}
+
+void
+gf_output_xrandr_change_backlight (GfOutput *output,
+ int value)
+{
+ Display *xdisplay;
+ gint hw_value;
+ Atom atom;
+
+ xdisplay = xdisplay_from_output (output);
+ hw_value = round ((gdouble) value / 100.0 * output->backlight_max + output->backlight_min);
+ atom = XInternAtom (xdisplay, "Backlight", False);
+
+ xcb_randr_change_output_property (XGetXCBConnection (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);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]