summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Ropé <jrope@redhat.com>2020-03-24 16:42:16 +0100
committerJulien Ropé <jrope@redhat.com>2020-10-19 17:58:43 +0200
commitd92f37ae06aafa77b8bc27a458c449c28d0d5f09 (patch)
tree89fd16fee0f80fcd75d1316382185ef8feb5143c
parentf59192a021ffe5a59eba850ccef9c389681579e5 (diff)
Prepare mapping based on connector name.
Split the lookup_xrandr_output_for_device_info to access the part retrieving the expected connector name. Call that separate function in the "non-X11" part of the code, and use a hashtable to map Spice display ID to its expected connector name. This hashtable will later be used when we need to report resolution changes to the daemon/server. Signed-off-by: Julien Ropé <jrope@redhat.com> Acked-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r--src/vdagent/device-info.c167
-rw-r--r--src/vdagent/device-info.h4
-rw-r--r--src/vdagent/display.c37
3 files changed, 139 insertions, 69 deletions
diff --git a/src/vdagent/device-info.c b/src/vdagent/device-info.c
index 6b0e28f..8cf72c9 100644
--- a/src/vdagent/device-info.c
+++ b/src/vdagent/device-info.c
@@ -388,12 +388,14 @@ static char* find_device_at_pci_address(PciAddress *pci_addr, int *vendor_id, in
return NULL;
}
-// PCI address should be in the following format:
-// pci/$domain/$slot.$fn/$slot.$fn
-bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
- Display *xdisplay,
- XRRScreenResources *xres,
- RROutput *output_id)
+
+/**
+ * Look up DRM info for the device, and retrieve the expected connector name.
+ * This name will later be compared to the monitor names found at the display manager level.
+ */
+int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
+ char *expected_name, size_t name_size,
+ bool has_virtual_zero_display)
{
PciAddress *user_pci_addr = parse_pci_address_from_spice((char*)device_info->device_address);
if (!user_pci_addr) {
@@ -401,7 +403,7 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
"Couldn't parse PCI address '%s'. "
"Address should be the form 'pci/$domain/$slot.$fn/$slot.fn...",
device_info->device_address);
- return false;
+ return -1;
}
int vendor_id = 0;
@@ -412,68 +414,106 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
int drm_fd = open(dev_path, O_RDWR);
if (drm_fd < 0) {
syslog(LOG_WARNING, "Unable to open file %s", dev_path);
- return false;
+ g_free(dev_path);
+ return -1;
}
drmModeResPtr res = drmModeGetResources(drm_fd);
- if (res) {
- // find the drm output that is equal to device_display_id
- if (device_info->device_display_id >= res->count_connectors) {
- syslog(LOG_WARNING,
- "Specified display id %i is higher than the maximum display id "
- "provided by this device (%i)",
- device_info->device_display_id, res->count_connectors - 1);
- close(drm_fd);
- return false;
- }
+ if (res == NULL) {
+ syslog(LOG_WARNING,
+ "Unable to get DRM resources for card %s. "
+ "Falling back to using xrandr output index.",
+ dev_path);
+ close(drm_fd);
+ g_free(dev_path);
+ return 1; // error out - actual handling is deferred to the caller
+ }
- drmModeConnectorPtr conn =
- drmModeGetConnector(drm_fd, res->connectors[device_info->device_display_id]);
- drmModeFreeResources(res);
- res = NULL;
+ // no need for dev_path anymore
+ g_free(dev_path);
+
+ // find the drm output that is equal to device_display_id
+ if (device_info->device_display_id >= res->count_connectors) {
+ syslog(LOG_WARNING,
+ "Specified display id %i is higher than the maximum display id "
+ "provided by this device (%i)",
+ device_info->device_display_id, res->count_connectors - 1);
close(drm_fd);
+ return -1;
+ }
- if (conn == NULL) {
- syslog(LOG_WARNING, "Unable to get drm connector for display id %i",
- device_info->device_display_id);
- return false;
- }
+ drmModeConnectorPtr conn =
+ drmModeGetConnector(drm_fd, res->connectors[device_info->device_display_id]);
+ drmModeFreeResources(res);
+ res = NULL;
+ close(drm_fd);
- bool decrement_name = false;
- if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
- // Older QXL drivers numbered their outputs starting with
- // 0. This contrasts with most drivers who start numbering
- // outputs with 1. In this case, the expected drm connector
- // name will need to be decremented before comparing to the
- // xrandr output name
- for (int i = 0; i < xres->noutput; ++i) {
- XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
- if (!oinfo) {
- syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
- xres->outputs[i]);
- return false;
- }
- if (strcmp(oinfo->name, "Virtual-0") == 0) {
- decrement_name = true;
- XRRFreeOutputInfo(oinfo);
- break;
- }
- XRRFreeOutputInfo(oinfo);
- }
+ if (conn == NULL) {
+ syslog(LOG_WARNING, "Unable to get drm connector for display id %i",
+ device_info->device_display_id);
+ return -1;
+ }
+
+ bool decrement_name = false;
+
+ if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL
+ && has_virtual_zero_display) {
+ decrement_name = true;
+ }
+
+ // Compare the name of the xrandr output against what we would
+ // expect based on the drm connection type. The xrandr names
+ // are driver-specific, so we need to special-case some
+ // drivers. Most hardware these days uses the 'modesetting'
+ // driver, but the QXL device uses its own driver which has
+ // different naming conventions
+ if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
+ drm_conn_name_qxl(conn, expected_name, name_size, decrement_name);
+ } else {
+ drm_conn_name_modesetting(conn, expected_name, name_size);
+ }
+ drmModeFreeConnector(conn);
+
+ return 0;
+}
+
+// PCI address should be in the following format:
+// pci/$domain/$slot.$fn/$slot.$fn
+bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
+ Display *xdisplay,
+ XRRScreenResources *xres,
+ RROutput *output_id)
+{
+ char expected_name[100];
+ int ret;
+
+ // Older QXL drivers numbered their outputs starting with
+ // 0. This contrasts with most drivers who start numbering
+ // outputs with 1. In this case, the expected drm connector
+ // name will need to be decremented before comparing to the
+ // xrandr output name
+ bool has_virtual_zero_display = false;
+ for (int i = 0; i < xres->noutput; ++i) {
+ XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
+ if (!oinfo) {
+ syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
+ xres->outputs[i]);
+ return false;
}
- // Compare the name of the xrandr output against what we would
- // expect based on the drm connection type. The xrandr names
- // are driver-specific, so we need to special-case some
- // drivers. Most hardware these days uses the 'modesetting'
- // driver, but the QXL device uses its own driver which has
- // different naming conventions
- char expected_name[100];
- if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
- drm_conn_name_qxl(conn, expected_name, sizeof(expected_name), decrement_name);
- } else {
- drm_conn_name_modesetting(conn, expected_name, sizeof(expected_name));
+ if (strcmp(oinfo->name, "Virtual-0") == 0) {
+ has_virtual_zero_display = true;
+ XRRFreeOutputInfo(oinfo);
+ break;
}
+ XRRFreeOutputInfo(oinfo);
+ }
+ ret = get_connector_name_for_device_info(device_info, expected_name, sizeof(expected_name),
+ has_virtual_zero_display);
+ switch (ret) {
+ case -1: // generic error => exit
+ return false;
+ case 0:
// Loop through xrandr outputs and check whether the xrandr
// output name matches the drm connector name
for (int i = 0; i < xres->noutput; ++i) {
@@ -493,13 +533,8 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
}
XRRFreeOutputInfo(oinfo);
}
- drmModeFreeConnector(conn);
- } else {
- close(drm_fd);
- syslog(LOG_WARNING,
- "Unable to get DRM resources for card %s. "
- "Falling back to using xrandr output index.",
- dev_path);
+ break;
+ case 1: // no DRM info found
// This is probably a proprietary driver (e.g. Nvidia) that does
// not provide outputs via drm, so the only thing we can do is just
// assume that it is the only device assigned to X, and use the
diff --git a/src/vdagent/device-info.h b/src/vdagent/device-info.h
index 8646cc5..d4d8cbd 100644
--- a/src/vdagent/device-info.h
+++ b/src/vdagent/device-info.h
@@ -28,3 +28,7 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
Display *xdisplay,
XRRScreenResources *xres,
RROutput *output_id);
+
+int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
+ char *expected_name, size_t name_size,
+ bool has_virtual_zero_display);
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
index 2577f9c..b82db5c 100644
--- a/src/vdagent/display.c
+++ b/src/vdagent/display.c
@@ -25,9 +25,12 @@
#ifdef WITH_GTK
#include <gdk/gdk.h>
#include <gtk/gtk.h> // for GTK_CHECK_VERSION
-#ifdef GDK_WINDOWING_X11
- #if ! GTK_CHECK_VERSION(3, 98, 0)
- #include <gdk/gdkx.h>
+#if GTK_CHECK_VERSION(3, 98, 0)
+ #include <gdk/wayland/gdkwayland.h>
+ #include <gdk/x11/gdkx.h>
+#else
+ #ifdef GDK_WINDOWING_X11
+ #include <gdk/gdkx.h>
#endif
#endif
#endif
@@ -50,6 +53,10 @@
* The x11.c and x11-randr.c files contains the x11-specific functions.
*/
struct VDAgentDisplay {
+#ifdef USE_GTK_FOR_MONITORS
+ // association between SPICE display ID and expected connector name
+ GHashTable *connector_mapping;
+#endif
struct vdagent_x11 *x11;
UdscsConnection *vdagentd;
int debug;
@@ -132,6 +139,9 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
}
display->x11->vdagent_display = display;
+#ifdef USE_GTK_FOR_MONITORS
+ display->connector_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+#endif
display->x11_channel = g_io_channel_unix_new(vdagent_x11_get_fd(display->x11));
if (display->x11_channel == NULL) {
@@ -167,6 +177,10 @@ void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected)
return;
}
+#ifdef USE_GTK_FOR_MONITORS
+ g_hash_table_destroy(display->connector_mapping);
+#endif
+
g_clear_pointer(&display->x11_channel, g_io_channel_unref);
vdagent_x11_destroy(display->x11, vdagentd_disconnected);
}
@@ -227,6 +241,23 @@ void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_
device_display_info->channel_id, device_display_info->monitor_id);
}
+#ifdef USE_GTK_FOR_MONITORS
+ if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
+ // Get the expected connector name from hardware info. Store it with the SPICE display ID.
+ char expected_name[100];
+ int ret = get_connector_name_for_device_info(device_display_info, expected_name,
+ sizeof(expected_name), false);
+ if (ret == 0) {
+ g_hash_table_insert(display->connector_mapping,
+ g_strdup(expected_name),
+ GUINT_TO_POINTER(device_display_info->channel_id + device_display_info->monitor_id));
+ syslog(LOG_DEBUG, "Mapping connector %s to display #%d", expected_name,
+ (device_display_info->channel_id + device_display_info->monitor_id));
+ }
+ }
+ else
+ // under X11, use the X11 API
+#endif
vdagent_x11_handle_device_display_info(display->x11, device_display_info);
device_display_info = (VDAgentDeviceDisplayInfo*) ((char*) device_display_info +