diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 59c715438..c6d16827b 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -396,6 +396,32 @@ make_display_name (MetaMonitorManager *manager, return ret; } +static const char * +get_connector_type_name (MetaConnectorType connector_type) +{ + switch (connector_type) + { + case META_CONNECTOR_TYPE_Unknown: return "Unknown"; + case META_CONNECTOR_TYPE_VGA: return "VGA"; + case META_CONNECTOR_TYPE_DVII: return "DVII"; + case META_CONNECTOR_TYPE_DVID: return "DVID"; + case META_CONNECTOR_TYPE_DVIA: return "DVIA"; + case META_CONNECTOR_TYPE_Composite: return "Composite"; + case META_CONNECTOR_TYPE_SVIDEO: return "SVIDEO"; + case META_CONNECTOR_TYPE_LVDS: return "LVDS"; + case META_CONNECTOR_TYPE_Component: return "Component"; + case META_CONNECTOR_TYPE_9PinDIN: return "9PinDIN"; + case META_CONNECTOR_TYPE_DisplayPort: return "DisplayPort"; + case META_CONNECTOR_TYPE_HDMIA: return "HDMIA"; + case META_CONNECTOR_TYPE_HDMIB: return "HDMIB"; + case META_CONNECTOR_TYPE_TV: return "TV"; + case META_CONNECTOR_TYPE_eDP: return "eDP"; + case META_CONNECTOR_TYPE_VIRTUAL: return "VIRTUAL"; + case META_CONNECTOR_TYPE_DSI: return "DSI"; + default: g_assert_not_reached (); + } +} + static gboolean meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton, GDBusMethodInvocation *invocation) @@ -476,6 +502,8 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton, g_variant_new_boolean (output->is_primary)); g_variant_builder_add (&properties, "{sv}", "presentation", g_variant_new_boolean (output->is_presentation)); + g_variant_builder_add (&properties, "{sv}", "connector-type", + g_variant_new_string (get_connector_type_name (output->connector_type))); edid_file = manager_class->get_edid_file (manager, output); if (edid_file) diff --git a/src/backends/meta-monitor-manager.h b/src/backends/meta-monitor-manager.h index 102759f7c..8ba3b46a1 100644 --- a/src/backends/meta-monitor-manager.h +++ b/src/backends/meta-monitor-manager.h @@ -69,6 +69,27 @@ typedef enum { META_MONITOR_TRANSFORM_FLIPPED_270, } MetaMonitorTransform; +/* This matches the values in drm_mode.h */ +typedef enum { + META_CONNECTOR_TYPE_Unknown = 0, + META_CONNECTOR_TYPE_VGA = 1, + META_CONNECTOR_TYPE_DVII = 2, + META_CONNECTOR_TYPE_DVID = 3, + META_CONNECTOR_TYPE_DVIA = 4, + META_CONNECTOR_TYPE_Composite = 5, + META_CONNECTOR_TYPE_SVIDEO = 6, + META_CONNECTOR_TYPE_LVDS = 7, + META_CONNECTOR_TYPE_Component = 8, + META_CONNECTOR_TYPE_9PinDIN = 9, + META_CONNECTOR_TYPE_DisplayPort = 10, + META_CONNECTOR_TYPE_HDMIA = 11, + META_CONNECTOR_TYPE_HDMIB = 12, + META_CONNECTOR_TYPE_TV = 13, + META_CONNECTOR_TYPE_eDP = 14, + META_CONNECTOR_TYPE_VIRTUAL = 15, + META_CONNECTOR_TYPE_DSI = 16, +} MetaConnectorType; + struct _MetaOutput { /* The CRTC driving this output, NULL if the output is not enabled */ @@ -84,6 +105,8 @@ struct _MetaOutput CoglSubpixelOrder subpixel_order; int scale; + MetaConnectorType connector_type; + MetaMonitorMode *preferred_mode; MetaMonitorMode **modes; unsigned int n_modes; diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index aa949ab1c..564bc5088 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -537,6 +537,9 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) meta_output->serial = g_strdup ("unknown"); } + /* MetaConnectorType matches DRM's connector types */ + meta_output->connector_type = (MetaConnectorType) connector->connector_type; + /* FIXME: backlight is a very driver specific thing unfortunately, every DDX does its own thing, and the dumb KMS API does not include it. diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 6abe6e011..96781a9dc 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -406,6 +406,147 @@ output_get_suggested_y (MetaMonitorManagerXrandr *manager_xrandr, 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) +{ + MetaConnectorType ret = META_CONNECTOR_TYPE_Unknown; + Atom atom, actual_type, connector_type_atom; + int actual_format; + unsigned long nitems, bytes_after; + unsigned char *buffer; + + atom = XInternAtom (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) + goto out; + + connector_type_atom = ((Atom *) buffer)[0]; + ret = connector_type_from_atom (manager_xrandr, connector_type_atom); + + out: + meta_XFree (buffer); + return ret; +} + +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_VGA; + if (g_str_has_prefix (name, "S-video")) + return META_CONNECTOR_TYPE_SVIDEO; + if (g_str_has_prefix (name, "TV")) + return META_CONNECTOR_TYPE_TV; + if (g_str_has_prefix (name, "CTV")) + return META_CONNECTOR_TYPE_Composite; + if (g_str_has_prefix (name, "DSI")) + return META_CONNECTOR_TYPE_DSI; + if (g_str_has_prefix (name, "DIN")) + return META_CONNECTOR_TYPE_9PinDIN; + + return META_CONNECTOR_TYPE_Unknown; +} + +static MetaConnectorType +output_get_connector_type (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 char * get_xmode_name (XRRModeInfo *xmode) { @@ -595,6 +736,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager) meta_output->hotplug_mode_update = output_get_hotplug_mode_update (manager_xrandr, meta_output); meta_output->suggested_x = output_get_suggested_x (manager_xrandr, meta_output); meta_output->suggested_y = output_get_suggested_y (manager_xrandr, meta_output); + meta_output->connector_type = output_get_connector_type (manager_xrandr, meta_output); meta_output->n_modes = output->nmode; meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);