diff --git a/src/Makefile.am b/src/Makefile.am index afcbc3e7e..71a846a6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 5f78c6a73..f8eec04c6 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -32,11 +32,8 @@ #include #include -#include #include -#include #include -#include #include #include @@ -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 diff --git a/src/backends/x11/meta-monitor-manager-xrandr.h b/src/backends/x11/meta-monitor-manager-xrandr.h index 3076e24d9..9f1d6ffdf 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.h +++ b/src/backends/x11/meta-monitor-manager-xrandr.h @@ -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); diff --git a/src/backends/x11/meta-output-xrandr.c b/src/backends/x11/meta-output-xrandr.c new file mode 100644 index 000000000..608c6b673 --- /dev/null +++ b/src/backends/x11/meta-output-xrandr.c @@ -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 +#include +#include +#include +#include + +#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; + } +} diff --git a/src/backends/x11/meta-output-xrandr.h b/src/backends/x11/meta-output-xrandr.h new file mode 100644 index 000000000..3a263a4fd --- /dev/null +++ b/src/backends/x11/meta-output-xrandr.h @@ -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 + +#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 */