backends/x11: Move output code to its own file
Move code dealing with X11 MetaOutputs and related functionality to its own file. Eventually, a MetaOutputXrandr should be introduced, based on MetaOutput, and this commit is in preparation for that. https://bugzilla.gnome.org/show_bug.cgi?id=785381
This commit is contained in:
parent
de40ced8b4
commit
e32d52b9b8
@ -171,6 +171,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
backends/x11/meta-input-settings-x11.h \
|
||||
backends/x11/meta-monitor-manager-xrandr.c \
|
||||
backends/x11/meta-monitor-manager-xrandr.h \
|
||||
backends/x11/meta-output-xrandr.c \
|
||||
backends/x11/meta-output-xrandr.h \
|
||||
backends/x11/meta-renderer-x11.c \
|
||||
backends/x11/meta-renderer-x11.h \
|
||||
backends/x11/meta-stage-x11-nested.c \
|
||||
|
@ -32,11 +32,8 @@
|
||||
#include <math.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlibint.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/dpms.h>
|
||||
#include <X11/extensions/extutil.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <xcb/randr.h>
|
||||
|
||||
@ -47,6 +44,7 @@
|
||||
#include "backends/meta-monitor-config-manager.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-output.h"
|
||||
#include "backends/x11/meta-output-xrandr.h"
|
||||
|
||||
#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
@ -91,6 +89,18 @@ typedef struct _MetaMonitorXrandrData
|
||||
GQuark quark_meta_monitor_xrandr_data;
|
||||
#endif /* HAVE_RANDR15 */
|
||||
|
||||
Display *
|
||||
meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr)
|
||||
{
|
||||
return manager_xrandr->xdisplay;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr)
|
||||
{
|
||||
return manager_xrandr->has_randr15;
|
||||
}
|
||||
|
||||
static MetaMonitorTransform
|
||||
meta_monitor_transform_from_xrandr (Rotation rotation)
|
||||
{
|
||||
@ -162,226 +172,6 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_integer_property (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output, const char *propname,
|
||||
gint *value)
|
||||
{
|
||||
gboolean exists = FALSE;
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
unsigned char *buffer;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
|
||||
XRRGetOutputProperty (manager_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 = ((int*)buffer)[0];
|
||||
|
||||
XFree (buffer);
|
||||
return exists;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output, const char *propname)
|
||||
{
|
||||
gboolean exists = FALSE;
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
unsigned char *buffer;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
|
||||
XRRGetOutputProperty (manager_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);
|
||||
|
||||
XFree (buffer);
|
||||
return exists;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output, const char *propname)
|
||||
{
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
|
||||
XRRGetOutputProperty (manager_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)
|
||||
return FALSE;
|
||||
|
||||
return ((int*)buffer)[0];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return output_get_boolean_property (manager_xrandr, output, "_MUTTER_PRESENTATION_OUTPUT");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
g_autofree char *str = NULL;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
|
||||
XRRGetOutputProperty (manager_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)
|
||||
return FALSE;
|
||||
|
||||
str = XGetAtomName (manager_xrandr->xdisplay, *(Atom *)buffer);
|
||||
return (strcmp (str, "on") == 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_supports_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom atom, actual_type;
|
||||
int actual_format, i;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
XRRPropertyInfo *property_info;
|
||||
Atom *values;
|
||||
gboolean supports_underscanning = FALSE;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
|
||||
XRRGetOutputProperty (manager_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)
|
||||
return FALSE;
|
||||
|
||||
property_info = XRRQueryOutputProperty (manager_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.
|
||||
*/
|
||||
char *name = XGetAtomName (manager_xrandr->xdisplay, values[i]);
|
||||
if (strcmp (name, "on") == 0)
|
||||
supports_underscanning = TRUE;
|
||||
|
||||
XFree (name);
|
||||
}
|
||||
|
||||
XFree (property_info);
|
||||
|
||||
return supports_underscanning;
|
||||
}
|
||||
|
||||
static int
|
||||
normalize_backlight (MetaOutput *output,
|
||||
int hw_value)
|
||||
{
|
||||
return round ((double)(hw_value - output->backlight_min) /
|
||||
(output->backlight_max - output->backlight_min) * 100.0);
|
||||
}
|
||||
|
||||
static int
|
||||
output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
int value = -1;
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
|
||||
XRRGetOutputProperty (manager_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)
|
||||
return FALSE;
|
||||
|
||||
value = ((int*)buffer)[0];
|
||||
if (value > 0)
|
||||
return normalize_backlight (output, value);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
output_get_backlight_limits_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom atom;
|
||||
xcb_connection_t *xcb_conn;
|
||||
g_autofree xcb_randr_query_output_property_reply_t *reply = NULL;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
|
||||
|
||||
xcb_conn = XGetXCBConnection (manager_xrandr->xdisplay);
|
||||
reply = xcb_randr_query_output_property_reply (xcb_conn,
|
||||
xcb_randr_query_output_property (xcb_conn,
|
||||
(xcb_randr_output_t) output->winsys_id,
|
||||
(xcb_atom_t) atom),
|
||||
NULL);
|
||||
|
||||
/* This can happen on systems without backlights. */
|
||||
if (reply == NULL)
|
||||
return;
|
||||
|
||||
if (!reply->range || reply->length != 2)
|
||||
{
|
||||
meta_verbose ("backlight %s was not range\n", output->name);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t *values = xcb_randr_query_output_property_valid_values (reply);
|
||||
output->backlight_min = values[0];
|
||||
output->backlight_max = values[1];
|
||||
}
|
||||
|
||||
static int
|
||||
compare_outputs (const void *one,
|
||||
const void *two)
|
||||
@ -391,342 +181,6 @@ compare_outputs (const void *one,
|
||||
return strcmp (o_one->name, o_two->name);
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
get_edid_property (Display *dpy,
|
||||
RROutput output,
|
||||
Atom atom,
|
||||
gsize *len)
|
||||
{
|
||||
unsigned char *prop;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
Atom actual_type;
|
||||
guint8 *result;
|
||||
|
||||
XRRGetOutputProperty (dpy, output, atom,
|
||||
0, 100, False, False,
|
||||
AnyPropertyType,
|
||||
&actual_type, &actual_format,
|
||||
&nitems, &bytes_after, &prop);
|
||||
|
||||
if (actual_type == XA_INTEGER && actual_format == 8)
|
||||
{
|
||||
result = g_memdup (prop, nitems);
|
||||
if (len)
|
||||
*len = nitems;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
XFree (prop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
XID winsys_id)
|
||||
{
|
||||
Atom edid_atom;
|
||||
guint8 *result;
|
||||
gsize len;
|
||||
|
||||
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE);
|
||||
result = get_edid_property (manager_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 void
|
||||
output_get_tile_info (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom tile_atom;
|
||||
unsigned char *prop;
|
||||
unsigned long nitems, bytes_after;
|
||||
int actual_format;
|
||||
Atom actual_type;
|
||||
|
||||
if (manager_xrandr->has_randr15 == FALSE)
|
||||
return;
|
||||
|
||||
tile_atom = XInternAtom (manager_xrandr->xdisplay, "TILE", FALSE);
|
||||
XRRGetOutputProperty (manager_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)
|
||||
{
|
||||
long *values = (long *)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];
|
||||
}
|
||||
XFree (prop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update");
|
||||
}
|
||||
|
||||
static gint
|
||||
output_get_suggested_x (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
gint val;
|
||||
if (output_get_integer_property (manager_xrandr, output, "suggested X", &val))
|
||||
return val;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gint
|
||||
output_get_suggested_y (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
gint val;
|
||||
if (output_get_integer_property (manager_xrandr, output, "suggested Y", &val))
|
||||
return val;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
connector_type_from_atom (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
Atom atom)
|
||||
{
|
||||
Display *xdpy = manager_xrandr->xdisplay;
|
||||
|
||||
if (atom == XInternAtom (xdpy, "HDMI", True))
|
||||
return META_CONNECTOR_TYPE_HDMIA;
|
||||
if (atom == XInternAtom (xdpy, "VGA", True))
|
||||
return META_CONNECTOR_TYPE_VGA;
|
||||
/* Doesn't have a DRM equivalent, but means an internal panel.
|
||||
* We could pick either LVDS or eDP here. */
|
||||
if (atom == XInternAtom (xdpy, "Panel", True))
|
||||
return META_CONNECTOR_TYPE_LVDS;
|
||||
if (atom == XInternAtom (xdpy, "DVI", True) || atom == XInternAtom (xdpy, "DVI-I", True))
|
||||
return META_CONNECTOR_TYPE_DVII;
|
||||
if (atom == XInternAtom (xdpy, "DVI-A", True))
|
||||
return META_CONNECTOR_TYPE_DVIA;
|
||||
if (atom == XInternAtom (xdpy, "DVI-D", True))
|
||||
return META_CONNECTOR_TYPE_DVID;
|
||||
if (atom == XInternAtom (xdpy, "DisplayPort", True))
|
||||
return META_CONNECTOR_TYPE_DisplayPort;
|
||||
|
||||
if (atom == XInternAtom (xdpy, "TV", True))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
if (atom == XInternAtom (xdpy, "TV-Composite", True))
|
||||
return META_CONNECTOR_TYPE_Composite;
|
||||
if (atom == XInternAtom (xdpy, "TV-SVideo", True))
|
||||
return META_CONNECTOR_TYPE_SVIDEO;
|
||||
/* Another set of mismatches. */
|
||||
if (atom == XInternAtom (xdpy, "TV-SCART", True))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
if (atom == XInternAtom (xdpy, "TV-C4", True))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
output_get_connector_type_from_prop (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom atom, actual_type, connector_type_atom;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "ConnectorType", False);
|
||||
XRRGetOutputProperty (manager_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)
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
|
||||
connector_type_atom = ((Atom *) buffer)[0];
|
||||
return connector_type_from_atom (manager_xrandr, connector_type_atom);
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
output_get_connector_type_from_name (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
const char *name = output->name;
|
||||
|
||||
/* drmmode_display.c, which was copy/pasted across all the FOSS
|
||||
* xf86-video-* drivers, seems to name its outputs based on the
|
||||
* connector type, so look for that....
|
||||
*
|
||||
* SNA has its own naming scheme, because what else did you expect
|
||||
* from SNA, but it's not too different, so we can thankfully use
|
||||
* that with minor changes.
|
||||
*
|
||||
* http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesetting/drmmode_display.c#n953
|
||||
* http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/sna/sna_display.c#n3486
|
||||
*/
|
||||
|
||||
if (g_str_has_prefix (name, "DVI"))
|
||||
return META_CONNECTOR_TYPE_DVII;
|
||||
if (g_str_has_prefix (name, "LVDS"))
|
||||
return META_CONNECTOR_TYPE_LVDS;
|
||||
if (g_str_has_prefix (name, "HDMI"))
|
||||
return META_CONNECTOR_TYPE_HDMIA;
|
||||
if (g_str_has_prefix (name, "VGA"))
|
||||
return META_CONNECTOR_TYPE_VGA;
|
||||
/* SNA uses DP, not DisplayPort. Test for both. */
|
||||
if (g_str_has_prefix (name, "DP") || g_str_has_prefix (name, "DisplayPort"))
|
||||
return META_CONNECTOR_TYPE_DisplayPort;
|
||||
if (g_str_has_prefix (name, "eDP"))
|
||||
return META_CONNECTOR_TYPE_eDP;
|
||||
if (g_str_has_prefix (name, "Virtual"))
|
||||
return META_CONNECTOR_TYPE_VIRTUAL;
|
||||
if (g_str_has_prefix (name, "Composite"))
|
||||
return META_CONNECTOR_TYPE_Composite;
|
||||
if (g_str_has_prefix (name, "S-video"))
|
||||
return META_CONNECTOR_TYPE_SVIDEO;
|
||||
if (g_str_has_prefix (name, "TV"))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
if (g_str_has_prefix (name, "CTV"))
|
||||
return META_CONNECTOR_TYPE_Composite;
|
||||
if (g_str_has_prefix (name, "DSI"))
|
||||
return META_CONNECTOR_TYPE_DSI;
|
||||
if (g_str_has_prefix (name, "DIN"))
|
||||
return META_CONNECTOR_TYPE_9PinDIN;
|
||||
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
output_get_connector_type (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaConnectorType ret;
|
||||
|
||||
/* The "ConnectorType" property is considered mandatory since RandR 1.3,
|
||||
* but none of the FOSS drivers support it, because we're a bunch of
|
||||
* professional software developers.
|
||||
*
|
||||
* Try poking it first, without any expectations that it will work.
|
||||
* If it's not there, we thankfully have other bonghits to try next.
|
||||
*/
|
||||
ret = output_get_connector_type_from_prop (manager_xrandr, output);
|
||||
if (ret != META_CONNECTOR_TYPE_Unknown)
|
||||
return ret;
|
||||
|
||||
/* Fall back to heuristics based on the output name. */
|
||||
ret = output_get_connector_type_from_name (manager_xrandr, output);
|
||||
if (ret != META_CONNECTOR_TYPE_Unknown)
|
||||
return ret;
|
||||
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
}
|
||||
|
||||
static void
|
||||
output_get_modes (MetaMonitorManager *manager,
|
||||
MetaOutput *output,
|
||||
XRROutputInfo *xrandr_output)
|
||||
{
|
||||
guint j;
|
||||
guint n_actual_modes;
|
||||
|
||||
output->modes = g_new0 (MetaCrtcMode *, 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)
|
||||
{
|
||||
MetaCrtcMode *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 (MetaMonitorManager *manager,
|
||||
MetaOutput *output,
|
||||
XRROutputInfo *xrandr_output)
|
||||
{
|
||||
guint j;
|
||||
guint n_actual_crtcs;
|
||||
GList *l;
|
||||
|
||||
output->possible_crtcs = g_new0 (MetaCrtc *, xrandr_output->ncrtc);
|
||||
|
||||
n_actual_crtcs = 0;
|
||||
for (j = 0; j < (unsigned) xrandr_output->ncrtc; j++)
|
||||
{
|
||||
for (l = manager->crtcs; l; l = l->next)
|
||||
{
|
||||
MetaCrtc *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)
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
if ((XID) crtc->crtc_id == xrandr_output->crtc)
|
||||
{
|
||||
output->crtc = crtc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
get_xmode_name (XRRModeInfo *xmode)
|
||||
{
|
||||
@ -864,70 +318,24 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
|
||||
for (i = 0; i < (unsigned)resources->noutput; i++)
|
||||
{
|
||||
RROutput output_id;
|
||||
XRROutputInfo *xrandr_output;
|
||||
MetaOutput *output;
|
||||
|
||||
output_id = resources->outputs[i];
|
||||
xrandr_output = XRRGetOutputInfo (manager_xrandr->xdisplay,
|
||||
resources, resources->outputs[i]);
|
||||
resources, output_id);
|
||||
if (!xrandr_output)
|
||||
continue;
|
||||
|
||||
output = g_object_new (META_TYPE_OUTPUT, NULL);
|
||||
output->monitor_manager = manager;
|
||||
|
||||
if (xrandr_output->connection != RR_Disconnected)
|
||||
{
|
||||
GBytes *edid;
|
||||
MetaOutput *output;
|
||||
|
||||
output->winsys_id = resources->outputs[i];
|
||||
output->name = g_strdup (xrandr_output->name);
|
||||
|
||||
edid = read_output_edid (manager_xrandr, output->winsys_id);
|
||||
meta_output_parse_edid (output, edid);
|
||||
g_bytes_unref (edid);
|
||||
|
||||
output->width_mm = xrandr_output->mm_width;
|
||||
output->height_mm = xrandr_output->mm_height;
|
||||
output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
output->hotplug_mode_update =
|
||||
output_get_hotplug_mode_update (manager_xrandr, output);
|
||||
output->suggested_x = output_get_suggested_x (manager_xrandr, output);
|
||||
output->suggested_y = output_get_suggested_y (manager_xrandr, output);
|
||||
output->connector_type = output_get_connector_type (manager_xrandr,
|
||||
output);
|
||||
|
||||
output_get_tile_info (manager_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 (MetaOutput *,
|
||||
output->n_possible_clones);
|
||||
/* We can build the list of clones now, because we don't have the list of outputs
|
||||
yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them
|
||||
in a second pass
|
||||
*/
|
||||
for (j = 0; j < (unsigned) 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 (manager_xrandr, output);
|
||||
output->is_underscanning = output_get_underscanning_xrandr (manager_xrandr, output);
|
||||
output->supports_underscanning =
|
||||
output_get_supports_underscanning_xrandr (manager_xrandr, output);
|
||||
output_get_backlight_limits_xrandr (manager_xrandr, output);
|
||||
|
||||
if (!(output->backlight_min == 0 && output->backlight_max == 0))
|
||||
output->backlight = output_get_backlight_xrandr (manager_xrandr, output);
|
||||
else
|
||||
output->backlight = -1;
|
||||
|
||||
if (output->n_modes == 0 || output->n_possible_crtcs == 0)
|
||||
g_object_unref (output);
|
||||
else
|
||||
output = meta_create_xrandr_output (manager,
|
||||
xrandr_output,
|
||||
output_id,
|
||||
primary_output);
|
||||
if (output)
|
||||
manager->outputs = g_list_prepend (manager->outputs, output);
|
||||
}
|
||||
|
||||
@ -965,9 +373,7 @@ static GBytes *
|
||||
meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
|
||||
|
||||
return read_output_edid (manager_xrandr, output->winsys_id);
|
||||
return meta_output_xrandr_read_edid (output);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1024,69 +430,6 @@ meta_monitor_transform_to_xrandr (MetaMonitorTransform transform)
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output,
|
||||
gboolean presentation)
|
||||
{
|
||||
Atom atom;
|
||||
int value = presentation;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
|
||||
|
||||
xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
|
||||
(XID)output->winsys_id,
|
||||
atom, XCB_ATOM_CARDINAL, 32,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
1, &value);
|
||||
}
|
||||
|
||||
static void
|
||||
output_set_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output,
|
||||
gboolean underscanning)
|
||||
{
|
||||
Atom prop, valueatom;
|
||||
const char *value;
|
||||
|
||||
prop = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
|
||||
|
||||
value = underscanning ? "on" : "off";
|
||||
valueatom = XInternAtom (manager_xrandr->xdisplay, value, False);
|
||||
|
||||
xcb_randr_change_output_property (XGetXCBConnection (manager_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 (manager_xrandr->xdisplay, "underscan hborder", False);
|
||||
border_value = output->crtc->current_mode->width * 0.05;
|
||||
|
||||
xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
|
||||
(XID)output->winsys_id,
|
||||
prop, XCB_ATOM_INTEGER, 32,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
1, &border_value);
|
||||
|
||||
prop = XInternAtom (manager_xrandr->xdisplay, "underscan vborder", False);
|
||||
border_value = output->crtc->current_mode->height * 0.05;
|
||||
|
||||
xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
|
||||
(XID)output->winsys_id,
|
||||
prop, XCB_ATOM_INTEGER, 32,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
1, &border_value);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xrandr_set_crtc_config (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
gboolean save_timestamp,
|
||||
@ -1437,25 +780,11 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
MetaOutputInfo *output_info = outputs[i];
|
||||
MetaOutput *output = output_info->output;
|
||||
|
||||
if (output_info->is_primary)
|
||||
{
|
||||
XRRSetOutputPrimary (manager_xrandr->xdisplay,
|
||||
DefaultRootWindow (manager_xrandr->xdisplay),
|
||||
(XID)output_info->output->winsys_id);
|
||||
}
|
||||
|
||||
output_set_presentation_xrandr (manager_xrandr,
|
||||
output_info->output,
|
||||
output_info->is_presentation);
|
||||
|
||||
if (output_get_supports_underscanning_xrandr (manager_xrandr, output_info->output))
|
||||
output_set_underscanning_xrandr (manager_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;
|
||||
|
||||
meta_output_xrandr_apply_mode (output);
|
||||
}
|
||||
|
||||
/* Disable outputs not mentioned in the list */
|
||||
@ -1557,22 +886,7 @@ meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager,
|
||||
MetaOutput *output,
|
||||
gint value)
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
|
||||
Atom atom;
|
||||
int hw_value;
|
||||
|
||||
hw_value = round ((double)value / 100.0 * output->backlight_max + output->backlight_min);
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
|
||||
|
||||
xcb_randr_change_output_property (XGetXCBConnection (manager_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);
|
||||
meta_output_xrandr_change_backlight (output, value);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -29,6 +29,10 @@
|
||||
G_DECLARE_FINAL_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr,
|
||||
META, MONITOR_MANAGER_XRANDR, MetaMonitorManager)
|
||||
|
||||
Display * meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr);
|
||||
|
||||
gboolean meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr);
|
||||
|
||||
gboolean meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager,
|
||||
XEvent *event);
|
||||
|
||||
|
786
src/backends/x11/meta-output-xrandr.c
Normal file
786
src/backends/x11/meta-output-xrandr.c
Normal file
@ -0,0 +1,786 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Havoc Pennington
|
||||
* 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) 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.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/x11/meta-output-xrandr.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <xcb/randr.h>
|
||||
|
||||
#include "backends/meta-crtc.h"
|
||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
||||
#include "meta/util.h"
|
||||
|
||||
static Display *
|
||||
xdisplay_from_output (MetaOutput *output)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_output_get_monitor_manager (output);
|
||||
MetaMonitorManagerXrandr *monitor_manager_xrandr =
|
||||
META_MONITOR_MANAGER_XRANDR (monitor_manager);
|
||||
|
||||
return meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
|
||||
}
|
||||
|
||||
static void
|
||||
output_set_presentation_xrandr (MetaOutput *output,
|
||||
gboolean presentation)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom;
|
||||
int value = presentation;
|
||||
|
||||
atom = XInternAtom (xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
|
||||
|
||||
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 (MetaOutput *output,
|
||||
gboolean underscanning)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom prop, valueatom;
|
||||
const char *value;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_output_xrandr_apply_mode (MetaOutput *output)
|
||||
{
|
||||
Display *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);
|
||||
}
|
||||
|
||||
static int
|
||||
normalize_backlight (MetaOutput *output,
|
||||
int hw_value)
|
||||
{
|
||||
return round ((double)(hw_value - output->backlight_min) /
|
||||
(output->backlight_max - output->backlight_min) * 100.0);
|
||||
}
|
||||
|
||||
void
|
||||
meta_output_xrandr_change_backlight (MetaOutput *output,
|
||||
int value)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom;
|
||||
int hw_value;
|
||||
|
||||
hw_value = round ((double) 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);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_integer_property (MetaOutput *output,
|
||||
const char *propname,
|
||||
gint *value)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
gboolean exists = FALSE;
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
unsigned char *buffer;
|
||||
|
||||
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 = ((int*)buffer)[0];
|
||||
|
||||
XFree (buffer);
|
||||
return exists;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_property_exists (MetaOutput *output,
|
||||
const char *propname)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
gboolean exists = FALSE;
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
unsigned char *buffer;
|
||||
|
||||
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);
|
||||
|
||||
XFree (buffer);
|
||||
return exists;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_boolean_property (MetaOutput *output,
|
||||
const char *propname)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
|
||||
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)
|
||||
return FALSE;
|
||||
|
||||
return ((int*)buffer)[0];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_presentation_xrandr (MetaOutput *output)
|
||||
{
|
||||
return output_get_boolean_property (output, "_MUTTER_PRESENTATION_OUTPUT");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_underscanning_xrandr (MetaOutput *output)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
g_autofree char *str = NULL;
|
||||
|
||||
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)
|
||||
return FALSE;
|
||||
|
||||
str = XGetAtomName (xdisplay, *(Atom *)buffer);
|
||||
return (strcmp (str, "on") == 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_supports_underscanning_xrandr (MetaOutput *output)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom, actual_type;
|
||||
int actual_format, i;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
XRRPropertyInfo *property_info;
|
||||
Atom *values;
|
||||
gboolean supports_underscanning = FALSE;
|
||||
|
||||
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)
|
||||
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.
|
||||
*/
|
||||
char *name = XGetAtomName (xdisplay, values[i]);
|
||||
if (strcmp (name, "on") == 0)
|
||||
supports_underscanning = TRUE;
|
||||
|
||||
XFree (name);
|
||||
}
|
||||
|
||||
XFree (property_info);
|
||||
|
||||
return supports_underscanning;
|
||||
}
|
||||
|
||||
static int
|
||||
output_get_backlight_xrandr (MetaOutput *output)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
int value = -1;
|
||||
Atom atom, actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
|
||||
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)
|
||||
return FALSE;
|
||||
|
||||
value = ((int*)buffer)[0];
|
||||
if (value > 0)
|
||||
return normalize_backlight (output, value);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
output_get_backlight_limits_xrandr (MetaOutput *output)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom;
|
||||
xcb_connection_t *xcb_conn;
|
||||
xcb_randr_query_output_property_cookie_t cookie;
|
||||
g_autofree xcb_randr_query_output_property_reply_t *reply = NULL;
|
||||
|
||||
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)
|
||||
{
|
||||
meta_verbose ("backlight %s was not range\n", output->name);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t *values = xcb_randr_query_output_property_valid_values (reply);
|
||||
output->backlight_min = values[0];
|
||||
output->backlight_max = values[1];
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
get_edid_property (Display *xdisplay,
|
||||
RROutput output,
|
||||
Atom atom,
|
||||
gsize *len)
|
||||
{
|
||||
unsigned char *prop;
|
||||
int actual_format;
|
||||
unsigned long 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;
|
||||
}
|
||||
|
||||
XFree (prop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
meta_output_xrandr_read_edid (MetaOutput *output)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom edid_atom;
|
||||
guint8 *result;
|
||||
gsize len;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_hotplug_mode_update (MetaOutput *output)
|
||||
{
|
||||
return output_get_property_exists (output, "hotplug_mode_update");
|
||||
}
|
||||
|
||||
static gint
|
||||
output_get_suggested_x (MetaOutput *output)
|
||||
{
|
||||
gint val;
|
||||
if (output_get_integer_property (output, "suggested X", &val))
|
||||
return val;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gint
|
||||
output_get_suggested_y (MetaOutput *output)
|
||||
{
|
||||
gint val;
|
||||
if (output_get_integer_property (output, "suggested Y", &val))
|
||||
return val;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
connector_type_from_atom (Display *xdisplay,
|
||||
Atom atom)
|
||||
{
|
||||
if (atom == XInternAtom (xdisplay, "HDMI", True))
|
||||
return META_CONNECTOR_TYPE_HDMIA;
|
||||
if (atom == XInternAtom (xdisplay, "VGA", True))
|
||||
return META_CONNECTOR_TYPE_VGA;
|
||||
/* Doesn't have a DRM equivalent, but means an internal panel.
|
||||
* We could pick either LVDS or eDP here. */
|
||||
if (atom == XInternAtom (xdisplay, "Panel", True))
|
||||
return META_CONNECTOR_TYPE_LVDS;
|
||||
if (atom == XInternAtom (xdisplay, "DVI", True) ||
|
||||
atom == XInternAtom (xdisplay, "DVI-I", True))
|
||||
return META_CONNECTOR_TYPE_DVII;
|
||||
if (atom == XInternAtom (xdisplay, "DVI-A", True))
|
||||
return META_CONNECTOR_TYPE_DVIA;
|
||||
if (atom == XInternAtom (xdisplay, "DVI-D", True))
|
||||
return META_CONNECTOR_TYPE_DVID;
|
||||
if (atom == XInternAtom (xdisplay, "DisplayPort", True))
|
||||
return META_CONNECTOR_TYPE_DisplayPort;
|
||||
|
||||
if (atom == XInternAtom (xdisplay, "TV", True))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
if (atom == XInternAtom (xdisplay, "TV-Composite", True))
|
||||
return META_CONNECTOR_TYPE_Composite;
|
||||
if (atom == XInternAtom (xdisplay, "TV-SVideo", True))
|
||||
return META_CONNECTOR_TYPE_SVIDEO;
|
||||
/* Another set of mismatches. */
|
||||
if (atom == XInternAtom (xdisplay, "TV-SCART", True))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
if (atom == XInternAtom (xdisplay, "TV-C4", True))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
output_get_connector_type_from_prop (MetaOutput *output)
|
||||
{
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom atom, actual_type, connector_type_atom;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
g_autofree unsigned char *buffer = NULL;
|
||||
|
||||
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)
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
|
||||
connector_type_atom = ((Atom *) buffer)[0];
|
||||
return connector_type_from_atom (xdisplay, connector_type_atom);
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
output_get_connector_type_from_name (MetaOutput *output)
|
||||
{
|
||||
const char *name = output->name;
|
||||
|
||||
/* drmmode_display.c, which was copy/pasted across all the FOSS
|
||||
* xf86-video-* drivers, seems to name its outputs based on the
|
||||
* connector type, so look for that....
|
||||
*
|
||||
* SNA has its own naming scheme, because what else did you expect
|
||||
* from SNA, but it's not too different, so we can thankfully use
|
||||
* that with minor changes.
|
||||
*
|
||||
* http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesetting/drmmode_display.c#n953
|
||||
* http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/sna/sna_display.c#n3486
|
||||
*/
|
||||
|
||||
if (g_str_has_prefix (name, "DVI"))
|
||||
return META_CONNECTOR_TYPE_DVII;
|
||||
if (g_str_has_prefix (name, "LVDS"))
|
||||
return META_CONNECTOR_TYPE_LVDS;
|
||||
if (g_str_has_prefix (name, "HDMI"))
|
||||
return META_CONNECTOR_TYPE_HDMIA;
|
||||
if (g_str_has_prefix (name, "VGA"))
|
||||
return META_CONNECTOR_TYPE_VGA;
|
||||
/* SNA uses DP, not DisplayPort. Test for both. */
|
||||
if (g_str_has_prefix (name, "DP") || g_str_has_prefix (name, "DisplayPort"))
|
||||
return META_CONNECTOR_TYPE_DisplayPort;
|
||||
if (g_str_has_prefix (name, "eDP"))
|
||||
return META_CONNECTOR_TYPE_eDP;
|
||||
if (g_str_has_prefix (name, "Virtual"))
|
||||
return META_CONNECTOR_TYPE_VIRTUAL;
|
||||
if (g_str_has_prefix (name, "Composite"))
|
||||
return META_CONNECTOR_TYPE_Composite;
|
||||
if (g_str_has_prefix (name, "S-video"))
|
||||
return META_CONNECTOR_TYPE_SVIDEO;
|
||||
if (g_str_has_prefix (name, "TV"))
|
||||
return META_CONNECTOR_TYPE_TV;
|
||||
if (g_str_has_prefix (name, "CTV"))
|
||||
return META_CONNECTOR_TYPE_Composite;
|
||||
if (g_str_has_prefix (name, "DSI"))
|
||||
return META_CONNECTOR_TYPE_DSI;
|
||||
if (g_str_has_prefix (name, "DIN"))
|
||||
return META_CONNECTOR_TYPE_9PinDIN;
|
||||
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
}
|
||||
|
||||
static MetaConnectorType
|
||||
output_get_connector_type (MetaOutput *output)
|
||||
{
|
||||
MetaConnectorType ret;
|
||||
|
||||
/* The "ConnectorType" property is considered mandatory since RandR 1.3,
|
||||
* but none of the FOSS drivers support it, because we're a bunch of
|
||||
* professional software developers.
|
||||
*
|
||||
* Try poking it first, without any expectations that it will work.
|
||||
* If it's not there, we thankfully have other bonghits to try next.
|
||||
*/
|
||||
ret = output_get_connector_type_from_prop (output);
|
||||
if (ret != META_CONNECTOR_TYPE_Unknown)
|
||||
return ret;
|
||||
|
||||
/* Fall back to heuristics based on the output name. */
|
||||
ret = output_get_connector_type_from_name (output);
|
||||
if (ret != META_CONNECTOR_TYPE_Unknown)
|
||||
return ret;
|
||||
|
||||
return META_CONNECTOR_TYPE_Unknown;
|
||||
}
|
||||
|
||||
static void
|
||||
output_get_tile_info (MetaOutput *output)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_output_get_monitor_manager (output);
|
||||
MetaMonitorManagerXrandr *monitor_manager_xrandr =
|
||||
META_MONITOR_MANAGER_XRANDR (monitor_manager);
|
||||
Display *xdisplay = xdisplay_from_output (output);
|
||||
Atom tile_atom;
|
||||
unsigned char *prop;
|
||||
unsigned long nitems, bytes_after;
|
||||
int actual_format;
|
||||
Atom actual_type;
|
||||
|
||||
if (!meta_monitor_manager_xrandr_has_randr15 (monitor_manager_xrandr))
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
long *values = (long *)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];
|
||||
}
|
||||
XFree (prop);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
output_get_modes (MetaMonitorManager *monitor_manager,
|
||||
MetaOutput *output,
|
||||
XRROutputInfo *xrandr_output)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int n_actual_modes;
|
||||
|
||||
output->modes = g_new0 (MetaCrtcMode *, xrandr_output->nmode);
|
||||
|
||||
n_actual_modes = 0;
|
||||
for (i = 0; i < (unsigned int) xrandr_output->nmode; i++)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = monitor_manager->modes; l; l = l->next)
|
||||
{
|
||||
MetaCrtcMode *mode = l->data;
|
||||
|
||||
if (xrandr_output->modes[i] == (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 (MetaMonitorManager *monitor_manager,
|
||||
MetaOutput *output,
|
||||
XRROutputInfo *xrandr_output)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int n_actual_crtcs;
|
||||
GList *l;
|
||||
|
||||
output->possible_crtcs = g_new0 (MetaCrtc *, xrandr_output->ncrtc);
|
||||
|
||||
n_actual_crtcs = 0;
|
||||
for (i = 0; i < (unsigned int) xrandr_output->ncrtc; i++)
|
||||
{
|
||||
for (l = monitor_manager->crtcs; l; l = l->next)
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
if ((XID) crtc->crtc_id == xrandr_output->crtcs[i])
|
||||
{
|
||||
output->possible_crtcs[n_actual_crtcs] = crtc;
|
||||
n_actual_crtcs += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
output->n_possible_crtcs = n_actual_crtcs;
|
||||
|
||||
output->crtc = NULL;
|
||||
for (l = monitor_manager->crtcs; l; l = l->next)
|
||||
{
|
||||
MetaCrtc *crtc = l->data;
|
||||
|
||||
if ((XID) crtc->crtc_id == xrandr_output->crtc)
|
||||
{
|
||||
output->crtc = crtc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetaOutput *
|
||||
meta_create_xrandr_output (MetaMonitorManager *monitor_manager,
|
||||
XRROutputInfo *xrandr_output,
|
||||
RROutput output_id,
|
||||
RROutput primary_output)
|
||||
{
|
||||
MetaOutput *output;
|
||||
GBytes *edid;
|
||||
unsigned int i;
|
||||
|
||||
output = g_object_new (META_TYPE_OUTPUT, NULL);
|
||||
output->monitor_manager = monitor_manager;
|
||||
output->winsys_id = output_id;
|
||||
output->name = g_strdup (xrandr_output->name);
|
||||
|
||||
edid = meta_output_xrandr_read_edid (output);
|
||||
meta_output_parse_edid (output, edid);
|
||||
g_bytes_unref (edid);
|
||||
|
||||
output->width_mm = xrandr_output->mm_width;
|
||||
output->height_mm = xrandr_output->mm_height;
|
||||
output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
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 (MetaOutput *,
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
return output;
|
||||
}
|
||||
}
|
42
src/backends/x11/meta-output-xrandr.h
Normal file
42
src/backends/x11/meta-output-xrandr.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Red Hat
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_OUTPUT_XRANDR
|
||||
#define META_OUTPUT_XRANDR
|
||||
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
#include "backends/meta-output.h"
|
||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
||||
|
||||
void meta_output_xrandr_apply_mode (MetaOutput *output);
|
||||
|
||||
void meta_output_xrandr_change_backlight (MetaOutput *output,
|
||||
int value);
|
||||
|
||||
GBytes * meta_output_xrandr_read_edid (MetaOutput *output);
|
||||
|
||||
MetaOutput * meta_create_xrandr_output (MetaMonitorManager *monitor_manager,
|
||||
XRROutputInfo *xrandr_output,
|
||||
RROutput output_id,
|
||||
RROutput primary_output);
|
||||
|
||||
#endif /* META_OUTPUT_XRANDR */
|
Loading…
x
Reference in New Issue
Block a user