Blame SOURCES/0019-wayland-fix-monitor-mapping-issues.patch

bf1251
From 2f025381f8c11cab2f351a478fba80ce7ae70a67 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Tue, 25 Feb 2020 12:17:12 +0100
bf1251
Subject: [PATCH 1/4] Split X11-specific code from the core agent code
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
This commit adds a set of functions (vdagent_display_*) that separates the
bf1251
agent's code from the underlying backend used for handling monitor
bf1251
events/settings.
bf1251
Today, this does not change the behaviour of the agent, as those functions
bf1251
will just call the existing X11 functions. But we will later add code to
bf1251
them to support other means of dealing with monitors (i.e: Wayland
bf1251
support).
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 Makefile.am           |   2 +
bf1251
 src/vdagent/display.c | 129 ++++++++++++++++++++++++++++++++++++++++++
bf1251
 src/vdagent/display.h |  37 ++++++++++++
bf1251
 src/vdagent/vdagent.c |  37 ++++--------
bf1251
 4 files changed, 178 insertions(+), 27 deletions(-)
bf1251
 create mode 100644 src/vdagent/display.c
bf1251
 create mode 100644 src/vdagent/display.h
bf1251
bf1251
diff --git a/Makefile.am b/Makefile.am
bf1251
index 2abb5ec..431e414 100644
bf1251
--- a/Makefile.am
bf1251
+++ b/Makefile.am
bf1251
@@ -43,6 +43,8 @@ src_spice_vdagent_SOURCES =			\
bf1251
 	src/vdagent/clipboard.h			\
bf1251
 	src/vdagent/device-info.c		\
bf1251
 	src/vdagent/device-info.h		\
bf1251
+	src/vdagent/display.c			\
bf1251
+	src/vdagent/display.h			\
bf1251
 	src/vdagent/file-xfers.c		\
bf1251
 	src/vdagent/file-xfers.h		\
bf1251
 	src/vdagent/x11-priv.h			\
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
new file mode 100644
bf1251
index 0000000..bb83762
bf1251
--- /dev/null
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -0,0 +1,129 @@
bf1251
+/*  display.c vdagent display source code
bf1251
+
bf1251
+ Copyright 2020 Red Hat, Inc.
bf1251
+
bf1251
+ Red Hat Authors:
bf1251
+ Julien Ropé <jrope@redhat.com>
bf1251
+
bf1251
+ This program is free software: you can redistribute it and/or modify
bf1251
+ it under the terms of the GNU General Public License as published by
bf1251
+ the Free Software Foundation, either version 3 of the License, or
bf1251
+ (at your option) any later version.
bf1251
+
bf1251
+ This program is distributed in the hope that it will be useful,
bf1251
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
bf1251
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bf1251
+ GNU General Public License for more details.
bf1251
+
bf1251
+ You should have received a copy of the GNU General Public License
bf1251
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
bf1251
+ */
bf1251
+
bf1251
+#include <config.h>
bf1251
+
bf1251
+#include <glib.h>
bf1251
+#ifdef WITH_GTK
bf1251
+#include <gdk/gdk.h>
bf1251
+#ifdef GDK_WINDOWING_X11
bf1251
+#include <gdk/gdkx.h>
bf1251
+#endif
bf1251
+#endif
bf1251
+#include <syslog.h>
bf1251
+#include "x11.h"
bf1251
+#include "x11-priv.h"
bf1251
+
bf1251
+#include "display.h"
bf1251
+
bf1251
+/**
bf1251
+ * VDAgentDisplay and the vdagent_display_*() functions are used as wrappers for display-related
bf1251
+ * operations.
bf1251
+ * They allow vdagent code to call generic display functions that are independent from the underlying
bf1251
+ * API (X11/GTK/etc).
bf1251
+ *
bf1251
+ * The display.c file contains the actual implementation and chooses what API will be called.
bf1251
+ * The x11.c and x11-randr.c files contains the x11-specific functions.
bf1251
+ */
bf1251
+struct VDAgentDisplay {
bf1251
+    struct vdagent_x11 *x11;
bf1251
+    GIOChannel *x11_channel;
bf1251
+};
bf1251
+
bf1251
+struct vdagent_x11* vdagent_display_get_x11(VDAgentDisplay *display)
bf1251
+{
bf1251
+    return display->x11;
bf1251
+}
bf1251
+
bf1251
+static gboolean x11_io_channel_cb(GIOChannel *source, GIOCondition condition, gpointer data)
bf1251
+{
bf1251
+    VDAgentDisplay *display = data;
bf1251
+    vdagent_x11_do_read(display->x11);
bf1251
+
bf1251
+    return G_SOURCE_CONTINUE;
bf1251
+}
bf1251
+
bf1251
+VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int sync)
bf1251
+{
bf1251
+    VDAgentDisplay *display;
bf1251
+
bf1251
+    display = g_new0(VDAgentDisplay, 1);
bf1251
+    display->x11 = vdagent_x11_create(vdagentd, debug, sync);
bf1251
+    if (display->x11 == NULL) {
bf1251
+        g_free(display);
bf1251
+        return NULL;
bf1251
+    }
bf1251
+
bf1251
+    display->x11_channel = g_io_channel_unix_new(vdagent_x11_get_fd(display->x11));
bf1251
+    if (display->x11_channel == NULL) {
bf1251
+        vdagent_x11_destroy(display->x11, TRUE);
bf1251
+        g_free(display);
bf1251
+        return NULL;
bf1251
+    }
bf1251
+
bf1251
+    g_io_add_watch(display->x11_channel, G_IO_IN, x11_io_channel_cb, display);
bf1251
+
bf1251
+    return display;
bf1251
+}
bf1251
+
bf1251
+void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected)
bf1251
+{
bf1251
+    if (!display) {
bf1251
+        return;
bf1251
+    }
bf1251
+
bf1251
+    g_clear_pointer(&display->x11_channel, g_io_channel_unref);
bf1251
+    vdagent_x11_destroy(display->x11, vdagentd_disconnected);
bf1251
+}
bf1251
+
bf1251
+/* Function used to determine the default location to save file-xfers,
bf1251
+ xdg desktop dir or xdg download dir. We err on the safe side and use a
bf1251
+ whitelist approach, so any unknown desktop will end up with saving
bf1251
+ file-xfers to the xdg download dir, and opening the xdg download dir with
bf1251
+ xdg-open when the file-xfer completes. */
bf1251
+int vdagent_display_has_icons_on_desktop(VDAgentDisplay *display)
bf1251
+{
bf1251
+    return vdagent_x11_has_icons_on_desktop(display->x11);
bf1251
+}
bf1251
+
bf1251
+// handle the device info message from the server. This will allow us to
bf1251
+// maintain a mapping from spice display id to xrandr output
bf1251
+void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_t *data,
bf1251
+        size_t size)
bf1251
+{
bf1251
+    vdagent_x11_handle_graphics_device_info(display->x11, data, size);
bf1251
+}
bf1251
+
bf1251
+/*
bf1251
+ * Set monitor configuration according to client request.
bf1251
+ *
bf1251
+ * On exit send current configuration to client, regardless of error.
bf1251
+ *
bf1251
+ * Errors:
bf1251
+ *  screen size too large for driver to handle. (we set the largest/smallest possible)
bf1251
+ *  no randr support in X server.
bf1251
+ *  invalid configuration request from client.
bf1251
+ */
bf1251
+void vdagent_display_set_monitor_config(VDAgentDisplay *display, VDAgentMonitorsConfig *mon_config,
bf1251
+        int fallback)
bf1251
+{
bf1251
+    vdagent_x11_set_monitor_config(display->x11, mon_config, fallback);
bf1251
+}
bf1251
diff --git a/src/vdagent/display.h b/src/vdagent/display.h
bf1251
new file mode 100644
bf1251
index 0000000..1f5365f
bf1251
--- /dev/null
bf1251
+++ b/src/vdagent/display.h
bf1251
@@ -0,0 +1,37 @@
bf1251
+/*
bf1251
+ * display.h- vdagent display handling header
bf1251
+
bf1251
+    Copyright 2020 Red Hat, Inc.
bf1251
+
bf1251
+    This program is free software: you can redistribute it and/or modify
bf1251
+    it under the terms of the GNU General Public License as published by
bf1251
+    the Free Software Foundation, either version 3 of the License, or
bf1251
+    (at your option) any later version.
bf1251
+
bf1251
+    This program is distributed in the hope that it will be useful,
bf1251
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
bf1251
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bf1251
+    GNU General Public License for more details.
bf1251
+
bf1251
+    You should have received a copy of the GNU General Public License
bf1251
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
bf1251
+ */
bf1251
+
bf1251
+#ifndef SRC_VDAGENT_DISPLAY_H_
bf1251
+#define SRC_VDAGENT_DISPLAY_H_
bf1251
+
bf1251
+typedef struct VDAgentDisplay VDAgentDisplay;
bf1251
+
bf1251
+VDAgentDisplay *vdagent_display_create(UdscsConnection *vdagentd, int debug, int sync);
bf1251
+void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected);
bf1251
+
bf1251
+int vdagent_display_has_icons_on_desktop(VDAgentDisplay *display);
bf1251
+void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_t *data, size_t size);
bf1251
+void vdagent_display_set_monitor_config(VDAgentDisplay *display,
bf1251
+                                        VDAgentMonitorsConfig *mon_config,
bf1251
+                                        int fallback);
bf1251
+
bf1251
+struct vdagent_x11 *vdagent_display_get_x11(VDAgentDisplay *display);
bf1251
+
bf1251
+
bf1251
+#endif /* SRC_VDAGENT_DISPLAY_H_ */
bf1251
diff --git a/src/vdagent/vdagent.c b/src/vdagent/vdagent.c
bf1251
index 53b177b..af78328 100644
bf1251
--- a/src/vdagent/vdagent.c
bf1251
+++ b/src/vdagent/vdagent.c
bf1251
@@ -38,16 +38,15 @@
bf1251
 #include "udscs.h"
bf1251
 #include "vdagentd-proto.h"
bf1251
 #include "audio.h"
bf1251
-#include "x11.h"
bf1251
 #include "file-xfers.h"
bf1251
 #include "clipboard.h"
bf1251
+#include "display.h"
bf1251
 
bf1251
 typedef struct VDAgent {
bf1251
     VDAgentClipboards *clipboards;
bf1251
-    struct vdagent_x11 *x11;
bf1251
+    VDAgentDisplay *display;
bf1251
     struct vdagent_file_xfers *xfers;
bf1251
     UdscsConnection *conn;
bf1251
-    GIOChannel *x11_channel;
bf1251
 
bf1251
     GMainLoop *loop;
bf1251
 } VDAgent;
bf1251
@@ -114,7 +113,7 @@ static const gchar *xfer_get_download_directory(VDAgent *agent)
bf1251
         return fx_dir;
bf1251
     }
bf1251
 
bf1251
-    return g_get_user_special_dir(vdagent_x11_has_icons_on_desktop(agent->x11) ?
bf1251
+    return g_get_user_special_dir(vdagent_display_has_icons_on_desktop(agent->display) ?
bf1251
                                   G_USER_DIRECTORY_DESKTOP :
bf1251
                                   G_USER_DIRECTORY_DOWNLOAD);
bf1251
 }
bf1251
@@ -144,7 +143,7 @@ static gboolean vdagent_init_file_xfer(VDAgent *agent)
bf1251
     }
bf1251
 
bf1251
     open_dir = fx_open_dir == -1 ?
bf1251
-               !vdagent_x11_has_icons_on_desktop(agent->x11) :
bf1251
+               !vdagent_display_has_icons_on_desktop(agent->display) :
bf1251
                fx_open_dir;
bf1251
 
bf1251
     agent->xfers = vdagent_file_xfers_create(agent->conn, xfer_dir,
bf1251
@@ -179,7 +178,7 @@ static void daemon_read_complete(UdscsConnection *conn,
bf1251
 
bf1251
     switch (header->type) {
bf1251
     case VDAGENTD_MONITORS_CONFIG:
bf1251
-        vdagent_x11_set_monitor_config(agent->x11, (VDAgentMonitorsConfig *)data, 0);
bf1251
+        vdagent_display_set_monitor_config(agent->display, (VDAgentMonitorsConfig *)data, 0);
bf1251
         break;
bf1251
     case VDAGENTD_CLIPBOARD_REQUEST:
bf1251
         vdagent_clipboard_request(agent->clipboards, header->arg1, header->arg2);
bf1251
@@ -249,7 +248,7 @@ static void daemon_read_complete(UdscsConnection *conn,
bf1251
         }
bf1251
         break;
bf1251
     case VDAGENTD_GRAPHICS_DEVICE_INFO:
bf1251
-        vdagent_x11_handle_graphics_device_info(agent->x11, data, header->size);
bf1251
+        vdagent_display_handle_graphics_device_info(agent->display, data, header->size);
bf1251
         break;
bf1251
     case VDAGENTD_CLIENT_DISCONNECTED:
bf1251
         vdagent_clipboards_release_all(agent->clipboards);
bf1251
@@ -335,15 +334,7 @@ static int daemonize(void)
bf1251
     return 0;
bf1251
 }
bf1251
 
bf1251
-static gboolean x11_io_channel_cb(GIOChannel *source,
bf1251
-                                  GIOCondition condition,
bf1251
-                                  gpointer data)
bf1251
-{
bf1251
-    VDAgent *agent = data;
bf1251
-    vdagent_x11_do_read(agent->x11);
bf1251
 
bf1251
-    return G_SOURCE_CONTINUE;
bf1251
-}
bf1251
 
bf1251
 gboolean vdagent_signal_handler(gpointer user_data)
bf1251
 {
bf1251
@@ -369,13 +360,12 @@ static VDAgent *vdagent_new(void)
bf1251
 static void vdagent_destroy(VDAgent *agent)
bf1251
 {
bf1251
     vdagent_finalize_file_xfer(agent);
bf1251
-    vdagent_x11_destroy(agent->x11, agent->conn == NULL);
bf1251
+    vdagent_display_destroy(agent->display, agent->conn == NULL);
bf1251
     g_clear_pointer(&agent->conn, vdagent_connection_destroy);
bf1251
 
bf1251
     while (g_source_remove_by_user_data(agent))
bf1251
         continue;
bf1251
 
bf1251
-    g_clear_pointer(&agent->x11_channel, g_io_channel_unref);
bf1251
     g_clear_pointer(&agent->loop, g_main_loop_unref);
bf1251
     g_free(agent);
bf1251
 }
bf1251
@@ -393,22 +383,15 @@ static gboolean vdagent_init_async_cb(gpointer user_data)
bf1251
     }
bf1251
     g_object_set_data(G_OBJECT(agent->conn), "agent", agent);
bf1251
 
bf1251
-    agent->x11 = vdagent_x11_create(agent->conn, debug, x11_sync);
bf1251
-    if (agent->x11 == NULL)
bf1251
-        goto err_init;
bf1251
-    agent->x11_channel = g_io_channel_unix_new(vdagent_x11_get_fd(agent->x11));
bf1251
-    if (agent->x11_channel == NULL)
bf1251
+    agent->display = vdagent_display_create(agent->conn, debug, x11_sync);
bf1251
+    if (agent->display == NULL)
bf1251
         goto err_init;
bf1251
 
bf1251
-    g_io_add_watch(agent->x11_channel,
bf1251
-                   G_IO_IN,
bf1251
-                   x11_io_channel_cb,
bf1251
-                   agent);
bf1251
 
bf1251
     if (!vdagent_init_file_xfer(agent))
bf1251
         syslog(LOG_WARNING, "File transfer is disabled");
bf1251
 
bf1251
-    agent->clipboards = vdagent_clipboards_new(agent->x11);
bf1251
+    agent->clipboards = vdagent_clipboards_new(vdagent_display_get_x11(agent->display));
bf1251
     vdagent_clipboards_set_conn(agent->clipboards, agent->conn);
bf1251
 
bf1251
     if (parent_socket != -1) {
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From aa75e9d7920ffb2290b56fd018789611748f1ea8 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Tue, 25 Feb 2020 15:18:41 +0100
bf1251
Subject: [PATCH 2/4] Move handle_graphics_device_info code to generic display
bf1251
 functions
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
Most of the code in vdagent_x11_handle_graphics_device_info() is dealing
bf1251
with SPICE information, only a few of it is X11-specific.
bf1251
Move that code away from x11-randr.c so that we can use it with Wayland.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/display.c   | 33 ++++++++++++++++-
bf1251
 src/vdagent/x11-randr.c | 82 +++++++++++++----------------------------
bf1251
 src/vdagent/x11.h       |  3 +-
bf1251
 3 files changed, 60 insertions(+), 58 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index bb83762..51b0a0d 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -109,7 +109,38 @@ int vdagent_display_has_icons_on_desktop(VDAgentDisplay *display)
bf1251
 void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_t *data,
bf1251
         size_t size)
bf1251
 {
bf1251
-    vdagent_x11_handle_graphics_device_info(display->x11, data, size);
bf1251
+    VDAgentGraphicsDeviceInfo *graphics_device_info = (VDAgentGraphicsDeviceInfo *)data;
bf1251
+    VDAgentDeviceDisplayInfo *device_display_info = graphics_device_info->display_info;
bf1251
+
bf1251
+    void *buffer_end = data + size;
bf1251
+
bf1251
+    syslog(LOG_INFO, "Received Graphics Device Info:");
bf1251
+
bf1251
+    for (size_t i = 0; i < graphics_device_info->count; ++i) {
bf1251
+        if ((void*) device_display_info > buffer_end ||
bf1251
+                (void*) (&device_display_info->device_address +
bf1251
+                    device_display_info->device_address_len) > buffer_end) {
bf1251
+            syslog(LOG_ERR, "Malformed graphics_display_info message, "
bf1251
+                   "extends beyond the end of the buffer");
bf1251
+            break;
bf1251
+        }
bf1251
+
bf1251
+        // make sure the string is terminated:
bf1251
+        if (device_display_info->device_address_len > 0) {
bf1251
+            device_display_info->device_address[device_display_info->device_address_len - 1] = '\0';
bf1251
+        } else {
bf1251
+            syslog(LOG_WARNING, "Zero length device_address received for channel_id: %u, monitor_id: %u",
bf1251
+                   device_display_info->channel_id, device_display_info->monitor_id);
bf1251
+        }
bf1251
+
bf1251
+        vdagent_x11_handle_device_display_info(display->x11, device_display_info);
bf1251
+
bf1251
+        device_display_info = (VDAgentDeviceDisplayInfo*) ((char*) device_display_info +
bf1251
+            sizeof(VDAgentDeviceDisplayInfo) + device_display_info->device_address_len);
bf1251
+    }
bf1251
+
bf1251
+    // make sure daemon is up-to-date with (possibly updated) device IDs
bf1251
+    vdagent_x11_send_daemon_guest_xorg_res(display->x11, 1);
bf1251
 }
bf1251
 
bf1251
 /*
bf1251
diff --git a/src/vdagent/x11-randr.c b/src/vdagent/x11-randr.c
bf1251
index 3fb7a68..9148563 100644
bf1251
--- a/src/vdagent/x11-randr.c
bf1251
+++ b/src/vdagent/x11-randr.c
bf1251
@@ -778,64 +778,34 @@ static void dump_monitors_config(struct vdagent_x11 *x11,
bf1251
 
bf1251
 // handle the device info message from the server. This will allow us to
bf1251
 // maintain a mapping from spice display id to xrandr output
bf1251
-void vdagent_x11_handle_graphics_device_info(struct vdagent_x11 *x11, uint8_t *data, size_t size)
bf1251
+void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
+                                            VDAgentDeviceDisplayInfo *device_display_info)
bf1251
 {
bf1251
-    VDAgentGraphicsDeviceInfo *graphics_device_info = (VDAgentGraphicsDeviceInfo *)data;
bf1251
-    VDAgentDeviceDisplayInfo *device_display_info = graphics_device_info->display_info;
bf1251
-
bf1251
-    void *buffer_end = data + size;
bf1251
-
bf1251
-    syslog(LOG_INFO, "Received Graphics Device Info:");
bf1251
-
bf1251
-    for (size_t i = 0; i < graphics_device_info->count; ++i) {
bf1251
-        if ((void*) device_display_info > buffer_end ||
bf1251
-                (void*) (&device_display_info->device_address +
bf1251
-                    device_display_info->device_address_len) > buffer_end) {
bf1251
-            syslog(LOG_ERR, "Malformed graphics_display_info message, "
bf1251
-                   "extends beyond the end of the buffer");
bf1251
-            break;
bf1251
-        }
bf1251
-
bf1251
-        // make sure the string is terminated:
bf1251
-        if (device_display_info->device_address_len > 0) {
bf1251
-            device_display_info->device_address[device_display_info->device_address_len - 1] = '\0';
bf1251
-        } else {
bf1251
-            syslog(LOG_WARNING, "Zero length device_address received for channel_id: %u, monitor_id: %u",
bf1251
-                   device_display_info->channel_id, device_display_info->monitor_id);
bf1251
-        }
bf1251
-
bf1251
-        RROutput x_output;
bf1251
-        if (lookup_xrandr_output_for_device_info(device_display_info, x11->display,
bf1251
-                                                 x11->randr.res, &x_output)) {
bf1251
-            gint64 *value = g_new(gint64, 1);
bf1251
-            *value = x_output;
bf1251
-
bf1251
-            syslog(LOG_INFO, "Adding graphics device info: channel_id: %u monitor_id: "
bf1251
-                   "%u device_address: %s, device_display_id: %u xrandr output ID: %lu",
bf1251
-                   device_display_info->channel_id,
bf1251
-                   device_display_info->monitor_id,
bf1251
-                   device_display_info->device_address,
bf1251
-                   device_display_info->device_display_id,
bf1251
-                   x_output);
bf1251
-
bf1251
-            g_hash_table_insert(x11->guest_output_map,
bf1251
-                GUINT_TO_POINTER(device_display_info->channel_id + device_display_info->monitor_id),
bf1251
-                value);
bf1251
-        } else {
bf1251
-            syslog(LOG_INFO, "channel_id: %u monitor_id: %u device_address: %s, "
bf1251
-                   "device_display_id: %u xrandr output ID NOT FOUND",
bf1251
-                   device_display_info->channel_id,
bf1251
-                   device_display_info->monitor_id,
bf1251
-                   device_display_info->device_address,
bf1251
-                   device_display_info->device_display_id);
bf1251
-        }
bf1251
-
bf1251
-        device_display_info = (VDAgentDeviceDisplayInfo*) ((char*) device_display_info +
bf1251
-            sizeof(VDAgentDeviceDisplayInfo) + device_display_info->device_address_len);
bf1251
+    RROutput x_output;
bf1251
+    if (lookup_xrandr_output_for_device_info(device_display_info, x11->display,
bf1251
+                                             x11->randr.res, &x_output)) {
bf1251
+        gint64 *value = g_new(gint64, 1);
bf1251
+        *value = x_output;
bf1251
+
bf1251
+        syslog(LOG_INFO, "Adding graphics device info: channel_id: %u monitor_id: "
bf1251
+               "%u device_address: %s, device_display_id: %u xrandr output ID: %lu",
bf1251
+               device_display_info->channel_id,
bf1251
+               device_display_info->monitor_id,
bf1251
+               device_display_info->device_address,
bf1251
+               device_display_info->device_display_id,
bf1251
+               x_output);
bf1251
+
bf1251
+        g_hash_table_insert(x11->guest_output_map,
bf1251
+            GUINT_TO_POINTER(device_display_info->channel_id + device_display_info->monitor_id),
bf1251
+            value);
bf1251
+    } else {
bf1251
+        syslog(LOG_INFO, "channel_id: %u monitor_id: %u device_address: %s, "
bf1251
+               "device_display_id: %u xrandr output ID NOT FOUND",
bf1251
+               device_display_info->channel_id,
bf1251
+               device_display_info->monitor_id,
bf1251
+               device_display_info->device_address,
bf1251
+               device_display_info->device_display_id);
bf1251
     }
bf1251
-
bf1251
-    // make sure daemon is up-to-date with (possibly updated) device IDs
bf1251
-    vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
bf1251
 }
bf1251
 
bf1251
 static int get_output_index_for_display_id(struct vdagent_x11 *x11, int display_id)
bf1251
diff --git a/src/vdagent/x11.h b/src/vdagent/x11.h
bf1251
index c49a397..6b3bcc1 100644
bf1251
--- a/src/vdagent/x11.h
bf1251
+++ b/src/vdagent/x11.h
bf1251
@@ -51,6 +51,7 @@ void vdagent_x11_client_disconnected(struct vdagent_x11 *x11);
bf1251
 #endif
bf1251
 
bf1251
 int vdagent_x11_has_icons_on_desktop(struct vdagent_x11 *x11);
bf1251
-void vdagent_x11_handle_graphics_device_info(struct vdagent_x11 *x11, uint8_t *data, size_t size);
bf1251
+void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
+                                            VDAgentDeviceDisplayInfo *device_display_info);
bf1251
 
bf1251
 #endif
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From 1601f4de9533dfe35536f68afc9ca899cf578ae3 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Mon, 6 Jul 2020 09:24:10 +0200
bf1251
Subject: [PATCH 3/4] Move more code from x11.c to display.c
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
Moving the non-X11 part of the code related to
bf1251
"vdagent_x11_has_icon_on_desktop()".
bf1251
Turns out most of it is disabled anyway when we build with GTK.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/display.c | 60 ++++++++++++++++++++++++++++++++++++++-----
bf1251
 src/vdagent/display.h |  2 +-
bf1251
 src/vdagent/x11.c     | 53 +++-----------------------------------
bf1251
 src/vdagent/x11.h     |  5 +++-
bf1251
 4 files changed, 62 insertions(+), 58 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index 51b0a0d..5f2ba2c 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -48,6 +48,21 @@ struct VDAgentDisplay {
bf1251
     GIOChannel *x11_channel;
bf1251
 };
bf1251
 
bf1251
+
bf1251
+static gchar *vdagent_display_get_wm_name(VDAgentDisplay *display)
bf1251
+{
bf1251
+#ifdef GDK_WINDOWING_X11
bf1251
+    GdkDisplay *gdk_display = gdk_display_get_default();
bf1251
+    if (GDK_IS_X11_DISPLAY(gdk_display))
bf1251
+        return g_strdup(gdk_x11_screen_get_window_manager_name(
bf1251
+            gdk_display_get_default_screen(gdk_display)));
bf1251
+    return g_strdup("unsupported");
bf1251
+#else
bf1251
+    return vdagent_x11_get_wm_name(display->x11);
bf1251
+#endif
bf1251
+}
bf1251
+
bf1251
+
bf1251
 struct vdagent_x11* vdagent_display_get_x11(VDAgentDisplay *display)
bf1251
 {
bf1251
     return display->x11;
bf1251
@@ -64,6 +79,7 @@ static gboolean x11_io_channel_cb(GIOChannel *source, GIOCondition condition, gp
bf1251
 VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int sync)
bf1251
 {
bf1251
     VDAgentDisplay *display;
bf1251
+    gchar *net_wm_name = NULL;
bf1251
 
bf1251
     display = g_new0(VDAgentDisplay, 1);
bf1251
     display->x11 = vdagent_x11_create(vdagentd, debug, sync);
bf1251
@@ -81,6 +97,21 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
 
bf1251
     g_io_add_watch(display->x11_channel, G_IO_IN, x11_io_channel_cb, display);
bf1251
 
bf1251
+
bf1251
+    /* Since we are started at the same time as the wm,
bf1251
+       sometimes we need to wait a bit for the _NET_WM_NAME to show up. */
bf1251
+    for (int i = 0; i < 9; i++) {
bf1251
+        g_free(net_wm_name);
bf1251
+        net_wm_name = vdagent_display_get_wm_name(display);
bf1251
+        if (strcmp(net_wm_name, "unknown"))
bf1251
+            break;
bf1251
+        usleep(100000);
bf1251
+    }
bf1251
+    if (display->x11->debug)
bf1251
+        syslog(LOG_DEBUG, "%s: net_wm_name=\"%s\", has icons=%d",
bf1251
+               __func__, net_wm_name, vdagent_display_has_icons_on_desktop(display));
bf1251
+    g_free(net_wm_name);
bf1251
+
bf1251
     return display;
bf1251
 }
bf1251
 
bf1251
@@ -95,13 +126,30 @@ void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected)
bf1251
 }
bf1251
 
bf1251
 /* Function used to determine the default location to save file-xfers,
bf1251
- xdg desktop dir or xdg download dir. We err on the safe side and use a
bf1251
- whitelist approach, so any unknown desktop will end up with saving
bf1251
- file-xfers to the xdg download dir, and opening the xdg download dir with
bf1251
- xdg-open when the file-xfer completes. */
bf1251
-int vdagent_display_has_icons_on_desktop(VDAgentDisplay *display)
bf1251
+   xdg desktop dir or xdg download dir. We err on the safe side and use a
bf1251
+   whitelist approach, so any unknown desktop will end up with saving
bf1251
+   file-xfers to the xdg download dir, and opening the xdg download dir with
bf1251
+   xdg-open when the file-xfer completes. */
bf1251
+gboolean vdagent_display_has_icons_on_desktop(VDAgentDisplay *display)
bf1251
 {
bf1251
-    return vdagent_x11_has_icons_on_desktop(display->x11);
bf1251
+    static const char * const wms_with_icons_on_desktop[] = {
bf1251
+        "Metacity", /* GNOME-2 or GNOME-3 fallback */
bf1251
+        "Xfwm4",    /* Xfce */
bf1251
+        "Marco",    /* Mate */
bf1251
+        "Metacity (Marco)", /* Mate, newer */
bf1251
+        NULL
bf1251
+    };
bf1251
+    gchar *net_wm_name = vdagent_display_get_wm_name(display);
bf1251
+    int i;
bf1251
+
bf1251
+    for (i = 0; wms_with_icons_on_desktop[i]; i++)
bf1251
+        if (!strcmp(net_wm_name, wms_with_icons_on_desktop[i])) {
bf1251
+            g_free(net_wm_name);
bf1251
+            return TRUE;
bf1251
+        }
bf1251
+
bf1251
+    g_free(net_wm_name);
bf1251
+    return FALSE;
bf1251
 }
bf1251
 
bf1251
 // handle the device info message from the server. This will allow us to
bf1251
diff --git a/src/vdagent/display.h b/src/vdagent/display.h
bf1251
index 1f5365f..af165ef 100644
bf1251
--- a/src/vdagent/display.h
bf1251
+++ b/src/vdagent/display.h
bf1251
@@ -25,7 +25,7 @@ typedef struct VDAgentDisplay VDAgentDisplay;
bf1251
 VDAgentDisplay *vdagent_display_create(UdscsConnection *vdagentd, int debug, int sync);
bf1251
 void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected);
bf1251
 
bf1251
-int vdagent_display_has_icons_on_desktop(VDAgentDisplay *display);
bf1251
+gboolean vdagent_display_has_icons_on_desktop(VDAgentDisplay *display);
bf1251
 void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_t *data, size_t size);
bf1251
 void vdagent_display_set_monitor_config(VDAgentDisplay *display,
bf1251
                                         VDAgentMonitorsConfig *mon_config,
bf1251
diff --git a/src/vdagent/x11.c b/src/vdagent/x11.c
bf1251
index 550d097..d171ffd 100644
bf1251
--- a/src/vdagent/x11.c
bf1251
+++ b/src/vdagent/x11.c
bf1251
@@ -123,15 +123,8 @@ int vdagent_x11_restore_error_handler(struct vdagent_x11 *x11)
bf1251
     return error;
bf1251
 }
bf1251
 
bf1251
-static gchar *vdagent_x11_get_wm_name(struct vdagent_x11 *x11)
bf1251
+gchar *vdagent_x11_get_wm_name(struct vdagent_x11 *x11)
bf1251
 {
bf1251
-#ifdef GDK_WINDOWING_X11
bf1251
-    GdkDisplay *display = gdk_display_get_default();
bf1251
-    if (GDK_IS_X11_DISPLAY(display))
bf1251
-        return g_strdup(gdk_x11_screen_get_window_manager_name(
bf1251
-            gdk_display_get_default_screen(display)));
bf1251
-    return g_strdup("unsupported");
bf1251
-#else
bf1251
     Atom type_ret;
bf1251
     int format_ret;
bf1251
     unsigned long len, remain;
bf1251
@@ -193,8 +186,7 @@ static gchar *vdagent_x11_get_wm_name(struct vdagent_x11 *x11)
bf1251
     if (net_wm_name == NULL)
bf1251
         return g_strdup("unknown");
bf1251
     return net_wm_name;
bf1251
-#endif
bf1251
 }
bf1251
 
bf1251
 struct vdagent_x11 *vdagent_x11_create(UdscsConnection *vdagentd,
bf1251
     int debug, int sync)
bf1251
@@ -206,7 +198,6 @@ struct vdagent_x11 *vdagent_x11_create(UdscsConnection *vdagentd,
bf1251
 #else
bf1251
     int i, j, major, minor;
bf1251
 #endif
bf1251
-    gchar *net_wm_name = NULL;
bf1251
 
bf1251
     x11 = g_new0(struct vdagent_x11, 1);
bf1251
     x11->vdagentd = vdagentd;
bf1251
@@ -308,19 +299,6 @@ struct vdagent_x11 *vdagent_x11_create(UdscsConnection *vdagentd,
bf1251
     }
bf1251
     vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
bf1251
 
bf1251
-    /* Since we are started at the same time as the wm,
bf1251
-       sometimes we need to wait a bit for the _NET_WM_NAME to show up. */
bf1251
-    for (i = 0; i < 9; i++) {
bf1251
-        g_free(net_wm_name);
bf1251
-        net_wm_name = vdagent_x11_get_wm_name(x11);
bf1251
-        if (strcmp(net_wm_name, "unknown"))
bf1251
-            break;
bf1251
-        usleep(100000);
bf1251
-    }
bf1251
-    if (x11->debug)
bf1251
-        syslog(LOG_DEBUG, "%s: net_wm_name=\"%s\", has icons=%d",
bf1251
-               __func__, net_wm_name, vdagent_x11_has_icons_on_desktop(x11));
bf1251
-    g_free(net_wm_name);
bf1251
 
bf1251
     /* Flush output buffers and consume any pending events */
bf1251
     vdagent_x11_do_read(x11);
bf1251
@@ -1407,30 +1365,3 @@ void vdagent_x11_client_disconnected(struct vdagent_x11 *x11)
bf1251
     }
bf1251
 }
bf1251
 #endif
bf1251
-
bf1251
-/* Function used to determine the default location to save file-xfers,
bf1251
-   xdg desktop dir or xdg download dir. We err on the safe side and use a
bf1251
-   whitelist approach, so any unknown desktop will end up with saving
bf1251
-   file-xfers to the xdg download dir, and opening the xdg download dir with
bf1251
-   xdg-open when the file-xfer completes. */
bf1251
-int vdagent_x11_has_icons_on_desktop(struct vdagent_x11 *x11)
bf1251
-{
bf1251
-    const char * const wms_with_icons_on_desktop[] = {
bf1251
-        "Metacity", /* GNOME-2 or GNOME-3 fallback */
bf1251
-        "Xfwm4",    /* Xfce */
bf1251
-        "Marco",    /* Mate */
bf1251
-        "Metacity (Marco)", /* Mate, newer */
bf1251
-        NULL
bf1251
-    };
bf1251
-    gchar *net_wm_name = vdagent_x11_get_wm_name(x11);
bf1251
-    int i;
bf1251
-
bf1251
-    for (i = 0; wms_with_icons_on_desktop[i]; i++)
bf1251
-        if (!strcmp(net_wm_name, wms_with_icons_on_desktop[i])) {
bf1251
-            g_free(net_wm_name);
bf1251
-            return 1;
bf1251
-        }
bf1251
-
bf1251
-    g_free(net_wm_name);
bf1251
-    return 0;
bf1251
-}
bf1251
diff --git a/src/vdagent/x11.h b/src/vdagent/x11.h
bf1251
index 6b3bcc1..6afee7f 100644
bf1251
--- a/src/vdagent/x11.h
bf1251
+++ b/src/vdagent/x11.h
bf1251
@@ -50,7 +50,8 @@ void vdagent_x11_clipboard_release(struct vdagent_x11 *x11, uint8_t selection);
bf1251
 void vdagent_x11_client_disconnected(struct vdagent_x11 *x11);
bf1251
 #endif
bf1251
 
bf1251
-int vdagent_x11_has_icons_on_desktop(struct vdagent_x11 *x11);
bf1251
+gchar *vdagent_x11_get_wm_name(struct vdagent_x11 *x11);
bf1251
+
bf1251
 void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
                                             VDAgentDeviceDisplayInfo *device_display_info);
bf1251
 
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From ef54256abff5fabb3158bff34c96781d09e25f45 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Mon, 6 Jul 2020 15:09:00 +0200
bf1251
Subject: [PATCH 4/4] Use RROutput directly in guest_output_map.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
No need to allocate a separate variable - the RROutput value can be used
bf1251
directly in the hashtable.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/x11-randr.c | 14 +++++---------
bf1251
 src/vdagent/x11.c       |  2 +-
bf1251
 2 files changed, 6 insertions(+), 10 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/x11-randr.c b/src/vdagent/x11-randr.c
bf1251
index 9148563..6cd9012 100644
bf1251
--- a/src/vdagent/x11-randr.c
bf1251
+++ b/src/vdagent/x11-randr.c
bf1251
@@ -414,7 +414,7 @@ static RROutput get_xrandr_output_for_display_id(struct vdagent_x11 *x11, int di
bf1251
         gpointer value;
bf1251
         if (g_hash_table_lookup_extended(x11->guest_output_map, GINT_TO_POINTER(display_id),
bf1251
                                          NULL, &value)) {
bf1251
-            return *(gint64*)value;
bf1251
+            return (RROutput)value;
bf1251
         }
bf1251
     }
bf1251
 
bf1251
@@ -784,9 +784,6 @@ void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
     RROutput x_output;
bf1251
     if (lookup_xrandr_output_for_device_info(device_display_info, x11->display,
bf1251
                                              x11->randr.res, &x_output)) {
bf1251
-        gint64 *value = g_new(gint64, 1);
bf1251
-        *value = x_output;
bf1251
-
bf1251
         syslog(LOG_INFO, "Adding graphics device info: channel_id: %u monitor_id: "
bf1251
                "%u device_address: %s, device_display_id: %u xrandr output ID: %lu",
bf1251
                device_display_info->channel_id,
bf1251
@@ -797,7 +794,7 @@ void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
 
bf1251
         g_hash_table_insert(x11->guest_output_map,
bf1251
             GUINT_TO_POINTER(device_display_info->channel_id + device_display_info->monitor_id),
bf1251
-            value);
bf1251
+            (gpointer)x_output);
bf1251
     } else {
bf1251
         syslog(LOG_INFO, "channel_id: %u monitor_id: %u device_address: %s, "
bf1251
                "device_display_id: %u xrandr output ID NOT FOUND",
bf1251
@@ -1058,12 +1055,11 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
bf1251
                 // all down.
bf1251
                 RROutput output_id = x11->randr.res->outputs[i];
bf1251
                 GHashTableIter iter;
bf1251
-                gpointer key, value;
bf1251
+                gpointer key, other_id;
bf1251
                 g_hash_table_iter_init(&iter, x11->guest_output_map);
bf1251
                 bool found = false;
bf1251
-                while (g_hash_table_iter_next(&iter, &key, &value)) {
bf1251
-                    gint64 *other_id = value;
bf1251
-                    if (*other_id == output_id) {
bf1251
+                while (g_hash_table_iter_next(&iter, &key, &other_id)) {
bf1251
+                    if ((RROutput)other_id == output_id) {
bf1251
                         curr.display_id = GPOINTER_TO_INT(key);
bf1251
                         g_array_append_val(res_array, curr);
bf1251
                         found = true;
bf1251
diff --git a/src/vdagent/x11.c b/src/vdagent/x11.c
bf1251
index d171ffd..ee0533f 100644
bf1251
--- a/src/vdagent/x11.c
bf1251
+++ b/src/vdagent/x11.c
bf1251
@@ -208,7 +206,7 @@ struct vdagent_x11 *vdagent_x11_create(UdscsConnection *vdagentd,
bf1251
     x11->guest_output_map = g_hash_table_new_full(&g_direct_hash,
bf1251
                                                   &g_direct_equal,
bf1251
                                                   NULL,
bf1251
-                                                  &g_free);
bf1251
+                                                  NULL);
bf1251
 
bf1251
 
bf1251
     x11->display = XOpenDisplay(NULL);
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
From 6e5e6c2ca6dde2fa489344e497c46fcdec364012 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Tue, 24 Mar 2020 18:13:15 +0100
bf1251
Subject: [PATCH 1/7] Add a non-X11 function to send the guest resolution to
bf1251
 the daemon/server.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
The purpose here is to further separate X11-specific code, and have the
bf1251
actual sending to the daemon to be out of X11 code, and reusable by
bf1251
other APIs.
bf1251
bf1251
- Replace vdagent_x11_send_daemon_guest_res() with a function that
bf1251
builds
bf1251
  and returns the list of monitor resolutions.
bf1251
- Create the vdagent_display_send_daemon_guest_res() that uses this to
bf1251
  send the resolutions to the daemon.
bf1251
- Call this function in place of vdagent_x11_send_daemon_guest_res()
bf1251
bf1251
In later commits, we will be able to use a different API to generate
bf1251
the list of monitor resolution, without having to change the X11 code.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/display.c   | 37 +++++++++++++++++++-
bf1251
 src/vdagent/display.h   |  2 ++
bf1251
 src/vdagent/x11-priv.h  |  7 ++--
bf1251
 src/vdagent/x11-randr.c | 75 ++++++++++++++++++++++++-----------------
bf1251
 src/vdagent/x11.c       |  2 --
bf1251
 5 files changed, 88 insertions(+), 35 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index d34a6e5..f84b1b3 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -35,6 +32,9 @@
bf1251
 #include "x11.h"
bf1251
 #include "x11-priv.h"
bf1251
 
bf1251
+#include "device-info.h"
bf1251
+#include "vdagentd-proto.h"
bf1251
+
bf1251
 #include "display.h"
bf1251
 
bf1251
 /**
bf1251
@@ -51,6 +51,35 @@ struct VDAgentDisplay {
bf1251
     GIOChannel *x11_channel;
bf1251
 };
bf1251
 
bf1251
+void vdagent_display_send_daemon_guest_res(VDAgentDisplay *display, gboolean update)
bf1251
+{
bf1251
+    GArray *res_array;
bf1251
+    int width, height, screen_count;
bf1251
+
bf1251
+    res_array = vdagent_x11_get_resolutions(display->x11, update, &width, &height, &screen_count);
bf1251
+    if (res_array == NULL) {
bf1251
+        return;
bf1251
+    }
bf1251
+
bf1251
+    if (display->x11->debug) {
bf1251
+        syslog(LOG_DEBUG, "Sending guest screen resolutions to vdagentd:");
bf1251
+        if (res_array->len > screen_count) {
bf1251
+            syslog(LOG_DEBUG, "(NOTE: list may contain overlapping areas when "
bf1251
+                              "multiple spice displays show the same guest output)");
bf1251
+        }
bf1251
+        struct vdagentd_guest_xorg_resolution *res =
bf1251
+            (struct vdagentd_guest_xorg_resolution*)res_array->data;
bf1251
+        for (int i = 0; i < res_array->len; i++) {
bf1251
+            syslog(LOG_DEBUG, "   display_id=%d - %dx%d%+d%+d",
bf1251
+                   res[i].display_id, res[i].width, res[i].height, res[i].x, res[i].y);
bf1251
+        }
bf1251
+    }
bf1251
+
bf1251
+    udscs_write(display->x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height,
bf1251
+                (uint8_t *)res_array->data,
bf1251
+                res_array->len * sizeof(struct vdagentd_guest_xorg_resolution));
bf1251
+    g_array_free(res_array, TRUE);
bf1251
+}
bf1251
 
bf1251
 static gchar *vdagent_display_get_wm_name(VDAgentDisplay *display)
bf1251
 {
bf1251
@@ -94,6 +120,8 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
         return NULL;
bf1251
     }
bf1251
 
bf1251
+    display->x11->vdagent_display = display;
bf1251
+
bf1251
     display->x11_channel = g_io_channel_unix_new(vdagent_x11_get_fd(display->x11));
bf1251
     if (display->x11_channel == NULL) {
bf1251
         vdagent_x11_destroy(display->x11, TRUE);
bf1251
@@ -118,6 +146,7 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
                __func__, net_wm_name, vdagent_display_has_icons_on_desktop(display));
bf1251
     g_free(net_wm_name);
bf1251
 
bf1251
+    vdagent_display_send_daemon_guest_res(display, TRUE);
bf1251
     return display;
bf1251
 }
bf1251
 
bf1251
@@ -194,7 +223,7 @@ void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_
bf1251
     }
bf1251
 
bf1251
     // make sure daemon is up-to-date with (possibly updated) device IDs
bf1251
-    vdagent_x11_send_daemon_guest_xorg_res(display->x11, 1);
bf1251
+    vdagent_display_send_daemon_guest_res(display, TRUE);
bf1251
 }
bf1251
 
bf1251
 /*
bf1251
diff --git a/src/vdagent/display.h b/src/vdagent/display.h
bf1251
index af165ef..5858237 100644
bf1251
--- a/src/vdagent/display.h
bf1251
+++ b/src/vdagent/display.h
bf1251
@@ -33,5 +33,7 @@ void vdagent_display_set_monitor_config(VDAgentDisplay *display,
bf1251
 
bf1251
 struct vdagent_x11 *vdagent_display_get_x11(VDAgentDisplay *display);
bf1251
 
bf1251
+void vdagent_display_send_daemon_guest_res(VDAgentDisplay *display, gboolean update);
bf1251
+
bf1251
 
bf1251
 #endif /* SRC_VDAGENT_DISPLAY_H_ */
bf1251
diff --git a/src/vdagent/x11-priv.h b/src/vdagent/x11-priv.h
bf1251
index f6f7efe..805d124 100644
bf1251
--- a/src/vdagent/x11-priv.h
bf1251
+++ b/src/vdagent/x11-priv.h
bf1251
@@ -7,5 +7,6 @@
bf1251
 #include <spice/vd_agent.h>
bf1251
 
bf1251
 #include <X11/extensions/Xrandr.h>
bf1251
+#include "display.h"
bf1251
 
bf1251
 #ifndef WITH_GTK
bf1251
@@ -155,14 +142,16 @@ struct vdagent_x11 {
bf1251
     int has_xinerama;
bf1251
     int dont_send_guest_xorg_res;
bf1251
     GHashTable *guest_output_map;
bf1251
+
bf1251
+    VDAgentDisplay *vdagent_display;
bf1251
 };
bf1251
 
bf1251
 extern int (*vdagent_x11_prev_error_handler)(Display *, XErrorEvent *);
bf1251
 extern int vdagent_x11_caught_error;
bf1251
 
bf1251
 void vdagent_x11_randr_init(struct vdagent_x11 *x11);
bf1251
-void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11,
bf1251
-                                            int update);
bf1251
+GArray *vdagent_x11_get_resolutions(struct vdagent_x11 *x11, gboolean update,
bf1251
+                                    int *width, int *height, int *system_screen_count);
bf1251
 void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11,
bf1251
                                             int screen, int width, int height);
bf1251
 int vdagent_x11_randr_handle_event(struct vdagent_x11 *x11,
bf1251
diff --git a/src/vdagent/x11-randr.c b/src/vdagent/x11-randr.c
bf1251
index b688b55..145e75a 100644
bf1251
--- a/src/vdagent/x11-randr.c
bf1251
+++ b/src/vdagent/x11-randr.c
bf1251
@@ -524,7 +524,7 @@ void vdagent_x11_randr_handle_root_size_change(struct vdagent_x11 *x11,
bf1251
     x11->width[screen]  = width;
bf1251
     x11->height[screen] = height;
bf1251
     if (!x11->dont_send_guest_xorg_res) {
bf1251
-        vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
bf1251
+        vdagent_display_send_daemon_guest_res(x11->vdagent_display, TRUE);
bf1251
     }
bf1251
 }
bf1251
 
bf1251
@@ -544,7 +544,7 @@ int vdagent_x11_randr_handle_event(struct vdagent_x11 *x11,
bf1251
         case RRNotify: {
bf1251
             update_randr_res(x11, 0);
bf1251
             if (!x11->dont_send_guest_xorg_res)
bf1251
-                vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
bf1251
+                vdagent_display_send_daemon_guest_res(x11->vdagent_display, TRUE);
bf1251
             break;
bf1251
         }
bf1251
         default:
bf1251
@@ -1021,18 +1021,45 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
bf1251
     x11->dont_send_guest_xorg_res = 0;
bf1251
 
bf1251
 exit:
bf1251
-    vdagent_x11_send_daemon_guest_xorg_res(x11, 0);
bf1251
+    vdagent_display_send_daemon_guest_res(x11->vdagent_display, FALSE);
bf1251
 
bf1251
     /* Flush output buffers and consume any pending events */
bf1251
     vdagent_x11_do_read(x11);
bf1251
     g_free(curr);
bf1251
 }
bf1251
 
bf1251
-void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
bf1251
+/**
bf1251
+ * Builds a list of available monitors, associated with their resolutions.
bf1251
+ *
bf1251
+ * This function will use the x11->guest_output_map hashtable to map the SPICE display ID to the
bf1251
+ * XRandr display ID, and make sure we get the right resolution for each SPICE display.
bf1251
+ * See vdagent_x11_handle_device_display_info() for how this hashtable is populated.
bf1251
+ *
bf1251
+ * If the ID can't be matched (which happens when running under XWayland for instance), a default
bf1251
+ * mapping is made, which assumes the list of X displays are in the same order as the SPICE displays.
bf1251
+ * This will cause issues if some SPICE displays are not enabled (for instance: display 2 is
bf1251
+ * enabled, but not display 1, causing a mismatch of IDs).
bf1251
+ *
bf1251
+ * Parameters:
bf1251
+ * x11    - pointer to the X11 structure
bf1251
+ * update - TRUE if the cached resolutions need to be updated before building the list
bf1251
+ * width  - full width of the desktop area (containing all the displays)
bf1251
+ * height - full height of the desktop area (containing all the displays)
bf1251
+ * system_screen_count - number of displays found on the system. In some situations, this may be
bf1251
+ *                       different than the number of SPICE displays (for instance: multiple displays
bf1251
+ *                       overlapping the same area of the desktop).
bf1251
+ *                       Used for logging/troubleshooting purposes.
bf1251
+ *
bf1251
+ * Returns: a GArray of vdagentd_guest_xorg_resolution elements, to be sent to the vdagent daemon.
bf1251
+ *          NULL if an error occurs.
bf1251
+ */
bf1251
+GArray *vdagent_x11_get_resolutions(struct vdagent_x11 *x11, gboolean update,
bf1251
+                                    int *width, int *height, int *system_screen_count)
bf1251
 {
bf1251
     GArray *res_array = g_array_new(FALSE, FALSE, sizeof(struct vdagentd_guest_xorg_resolution));
bf1251
-    int i, width = 0, height = 0, screen_count = 0;
bf1251
+    int i, screen_count = 0;
bf1251
 
bf1251
+    *width = *height = 0;
bf1251
     if (x11->has_xrandr) {
bf1251
         if (update)
bf1251
             update_randr_res(x11, 0);
bf1251
@@ -1070,8 +1097,8 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
bf1251
                 }
bf1251
             }
bf1251
         }
bf1251
-        width  = x11->width[0];
bf1251
-        height = x11->height[0];
bf1251
+        *width  = x11->width[0];
bf1251
+        *height = x11->height[0];
bf1251
     } else if (x11->has_xinerama) {
bf1251
         XineramaScreenInfo *screen_info = NULL;
bf1251
 
bf1251
@@ -1085,7 +1112,7 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
bf1251
                        screen_info[i].screen_number, screen_count);
bf1251
                 XFree(screen_info);
bf1251
                 g_array_free(res_array, true);
bf1251
-                return;
bf1251
+                return NULL;
bf1251
             }
bf1251
             struct vdagentd_guest_xorg_resolution *curr = &g_array_index(res_array,
bf1251
                                                                          struct vdagentd_guest_xorg_resolution,
bf1251
@@ -1096,8 +1123,8 @@ void vdagent_x11_send_daemon_guest_xorg_res(struct vdagent_x11 *x11, int update)
bf1251
             curr->y = screen_info[i].y_org;
bf1251
         }
bf1251
         XFree(screen_info);
bf1251
-        width  = x11->width[0];
bf1251
-        height = x11->height[0];
bf1251
+        *width  = x11->width[0];
bf1251
+        *height = x11->height[0];
bf1251
     } else {
bf1251
 no_info:
bf1251
         for (i = 0; i < screen_count; i++) {
bf1251
@@ -1105,11 +1132,12 @@ no_info:
bf1251
             res.width  = x11->width[i];
bf1251
             res.height = x11->height[i];
bf1251
             /* No way to get screen coordinates, assume rtl order */
bf1251
-            res.x = width;
bf1251
+            res.x = *width;
bf1251
             res.y = 0;
bf1251
-            width += x11->width[i];
bf1251
-            if (x11->height[i] > height)
bf1251
-                height = x11->height[i];
bf1251
+            *width += x11->width[i];
bf1251
+            if (x11->height[i] > *height) {
bf1251
+                *height = x11->height[i];
bf1251
+            }
bf1251
             g_array_append_val(res_array, res);
bf1251
         }
bf1251
     }
bf1251
@@ -1117,22 +1145,9 @@ no_info:
bf1251
     if (screen_count == 0) {
bf1251
         syslog(LOG_DEBUG, "Screen count is zero, are we on wayland?");
bf1251
         g_array_free(res_array, TRUE);
bf1251
-        return;
bf1251
-    }
bf1251
-
bf1251
-    if (x11->debug) {
bf1251
-        syslog(LOG_DEBUG, "Sending guest screen resolutions to vdagentd:");
bf1251
-        if (res_array->len > screen_count) {
bf1251
-            syslog(LOG_DEBUG, "(NOTE: list may contain overlapping areas when multiple spice displays show the same guest output)");
bf1251
-        }
bf1251
-        for (i = 0; i < res_array->len; i++) {
bf1251
-            struct vdagentd_guest_xorg_resolution *res = (struct vdagentd_guest_xorg_resolution*)res_array->data;
bf1251
-            syslog(LOG_DEBUG, "   screen %d %dx%d%+d%+d, display_id=%d", i,
bf1251
-                   res[i].width, res[i].height, res[i].x, res[i].y, res[i].display_id);
bf1251
-        }
bf1251
+        return NULL;
bf1251
     }
bf1251
 
bf1251
-    udscs_write(x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height,
bf1251
-                (uint8_t *)res_array->data, res_array->len * sizeof(struct vdagentd_guest_xorg_resolution));
bf1251
-    g_array_free(res_array, TRUE);
bf1251
+    *system_screen_count = screen_count;
bf1251
+    return res_array;
bf1251
 }
bf1251
diff --git a/src/vdagent/x11.c b/src/vdagent/x11.c
bf1251
index 58b99b7..b867a5a 100644
bf1251
--- a/src/vdagent/x11.c
bf1251
+++ b/src/vdagent/x11.c
bf1251
@@ -301,8 +297,6 @@ struct vdagent_x11 *vdagent_x11_create(UdscsConnection *vdagentd,
bf1251
         x11->width[i]  = attrib.width;
bf1251
         x11->height[i] = attrib.height;
bf1251
     }
bf1251
-    vdagent_x11_send_daemon_guest_xorg_res(x11, 1);
bf1251
-
bf1251
 
bf1251
     /* Flush output buffers and consume any pending events */
bf1251
     vdagent_x11_do_read(x11);
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From f59192a021ffe5a59eba850ccef9c389681579e5 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Mon, 24 Aug 2020 11:08:43 +0200
bf1251
Subject: [PATCH 2/7] Copy the 'debug' flag and 'vdagentd' socket into the
bf1251
 VDAgentDisplay structure.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/display.c | 11 ++++++++---
bf1251
 1 file changed, 8 insertions(+), 3 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index f84b1b3..2577f9c 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -51,6 +48,8 @@
bf1251
  */
bf1251
 struct VDAgentDisplay {
bf1251
     struct vdagent_x11 *x11;
bf1251
+    UdscsConnection *vdagentd;
bf1251
+    int debug;
bf1251
     GIOChannel *x11_channel;
bf1251
 };
bf1251
 
bf1251
@@ -64,7 +63,7 @@ void vdagent_display_send_daemon_guest_res(VDAgentDisplay *display, gboolean upd
bf1251
         return;
bf1251
     }
bf1251
 
bf1251
-    if (display->x11->debug) {
bf1251
+    if (display->debug) {
bf1251
         syslog(LOG_DEBUG, "Sending guest screen resolutions to vdagentd:");
bf1251
         if (res_array->len > screen_count) {
bf1251
             syslog(LOG_DEBUG, "(NOTE: list may contain overlapping areas when "
bf1251
@@ -78,7 +77,7 @@ void vdagent_display_send_daemon_guest_res(VDAgentDisplay *display, gboolean upd
bf1251
         }
bf1251
     }
bf1251
 
bf1251
-    udscs_write(display->x11->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height,
bf1251
+    udscs_write(display->vdagentd, VDAGENTD_GUEST_XORG_RESOLUTION, width, height,
bf1251
                 (uint8_t *)res_array->data,
bf1251
                 res_array->len * sizeof(struct vdagentd_guest_xorg_resolution));
bf1251
     g_array_free(res_array, TRUE);
bf1251
@@ -120,6 +116,9 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
     gchar *net_wm_name = NULL;
bf1251
 
bf1251
     display = g_new0(VDAgentDisplay, 1);
bf1251
+    display->vdagentd = vdagentd;
bf1251
+    display->debug = debug;
bf1251
+
bf1251
     display->x11 = vdagent_x11_create(vdagentd, debug, sync);
bf1251
     if (display->x11 == NULL) {
bf1251
         g_free(display);
bf1251
@@ -147,7 +146,7 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
             break;
bf1251
         usleep(100000);
bf1251
     }
bf1251
-    if (display->x11->debug)
bf1251
+    if (display->debug)
bf1251
         syslog(LOG_DEBUG, "%s: net_wm_name=\"%s\", has icons=%d",
bf1251
                __func__, net_wm_name, vdagent_display_has_icons_on_desktop(display));
bf1251
     g_free(net_wm_name);
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From d92f37ae06aafa77b8bc27a458c449c28d0d5f09 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Tue, 24 Mar 2020 16:42:16 +0100
bf1251
Subject: [PATCH 3/7] Prepare mapping based on connector name.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
Split the lookup_xrandr_output_for_device_info to access the part
bf1251
retrieving the expected connector name.
bf1251
Call that separate function in the "non-X11" part of the code, and use a
bf1251
hashtable to map Spice display ID to its expected connector name.
bf1251
This hashtable will later be used when we need to report resolution
bf1251
changes to the daemon/server.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/device-info.c | 167 +++++++++++++++++++++++---------------
bf1251
 src/vdagent/device-info.h |   4 +
bf1251
 src/vdagent/display.c     |  37 ++++++++-
bf1251
 3 files changed, 139 insertions(+), 69 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/device-info.c b/src/vdagent/device-info.c
bf1251
index 6b0e28f..8cf72c9 100644
bf1251
--- a/src/vdagent/device-info.c
bf1251
+++ b/src/vdagent/device-info.c
bf1251
@@ -388,12 +388,14 @@ static char* find_device_at_pci_address(PciAddress *pci_addr, int *vendor_id, in
bf1251
     return NULL;
bf1251
 }
bf1251
 
bf1251
-// PCI address should be in the following format:
bf1251
-//   pci/$domain/$slot.$fn/$slot.$fn
bf1251
-bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
-                                          Display *xdisplay,
bf1251
-                                          XRRScreenResources *xres,
bf1251
-                                          RROutput *output_id)
bf1251
+
bf1251
+/**
bf1251
+ * Look up DRM info for the device, and retrieve the expected connector name.
bf1251
+ * This name will later be compared to the monitor names found at the display manager level.
bf1251
+ */
bf1251
+int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
+                                       char *expected_name, size_t name_size,
bf1251
+                                       bool has_virtual_zero_display)
bf1251
 {
bf1251
     PciAddress *user_pci_addr = parse_pci_address_from_spice((char*)device_info->device_address);
bf1251
     if (!user_pci_addr) {
bf1251
@@ -401,7 +403,7 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
                "Couldn't parse PCI address '%s'. "
bf1251
                "Address should be the form 'pci/$domain/$slot.$fn/$slot.fn...",
bf1251
                device_info->device_address);
bf1251
-        return false;
bf1251
+        return -1;
bf1251
     }
bf1251
 
bf1251
     int vendor_id = 0;
bf1251
@@ -412,68 +414,106 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
     int drm_fd = open(dev_path, O_RDWR);
bf1251
     if (drm_fd < 0) {
bf1251
         syslog(LOG_WARNING, "Unable to open file %s", dev_path);
bf1251
-        return false;
bf1251
+        g_free(dev_path);
bf1251
+        return -1;
bf1251
     }
bf1251
 
bf1251
     drmModeResPtr res = drmModeGetResources(drm_fd);
bf1251
-    if (res) {
bf1251
-        // find the drm output that is equal to device_display_id
bf1251
-        if (device_info->device_display_id >= res->count_connectors) {
bf1251
-            syslog(LOG_WARNING,
bf1251
-                   "Specified display id %i is higher than the maximum display id "
bf1251
-                   "provided by this device (%i)",
bf1251
-                   device_info->device_display_id, res->count_connectors - 1);
bf1251
-            close(drm_fd);
bf1251
-            return false;
bf1251
-        }
bf1251
+    if (res == NULL) {
bf1251
+        syslog(LOG_WARNING,
bf1251
+               "Unable to get DRM resources for card %s. "
bf1251
+               "Falling back to using xrandr output index.",
bf1251
+               dev_path);
bf1251
+        close(drm_fd);
bf1251
+        g_free(dev_path);
bf1251
+        return 1;   // error out - actual handling is deferred to the caller
bf1251
+    }
bf1251
 
bf1251
-        drmModeConnectorPtr conn =
bf1251
-            drmModeGetConnector(drm_fd, res->connectors[device_info->device_display_id]);
bf1251
-        drmModeFreeResources(res);
bf1251
-        res = NULL;
bf1251
+    // no need for dev_path anymore
bf1251
+    g_free(dev_path);
bf1251
+
bf1251
+    // find the drm output that is equal to device_display_id
bf1251
+    if (device_info->device_display_id >= res->count_connectors) {
bf1251
+        syslog(LOG_WARNING,
bf1251
+               "Specified display id %i is higher than the maximum display id "
bf1251
+               "provided by this device (%i)",
bf1251
+               device_info->device_display_id, res->count_connectors - 1);
bf1251
         close(drm_fd);
bf1251
+        return -1;
bf1251
+    }
bf1251
 
bf1251
-        if (conn == NULL) {
bf1251
-            syslog(LOG_WARNING, "Unable to get drm connector for display id %i",
bf1251
-                   device_info->device_display_id);
bf1251
-            return false;
bf1251
-        }
bf1251
+    drmModeConnectorPtr conn =
bf1251
+        drmModeGetConnector(drm_fd, res->connectors[device_info->device_display_id]);
bf1251
+    drmModeFreeResources(res);
bf1251
+    res = NULL;
bf1251
+    close(drm_fd);
bf1251
 
bf1251
-        bool decrement_name = false;
bf1251
-        if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
bf1251
-            // Older QXL drivers numbered their outputs starting with
bf1251
-            // 0. This contrasts with most drivers who start numbering
bf1251
-            // outputs with 1.  In this case, the expected drm connector
bf1251
-            // name will need to be decremented before comparing to the
bf1251
-            // xrandr output name
bf1251
-            for (int i = 0; i < xres->noutput; ++i) {
bf1251
-                XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
bf1251
-                if (!oinfo) {
bf1251
-                    syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
bf1251
-                           xres->outputs[i]);
bf1251
-                    return false;
bf1251
-                }
bf1251
-                if (strcmp(oinfo->name, "Virtual-0") == 0) {
bf1251
-                    decrement_name = true;
bf1251
-                    XRRFreeOutputInfo(oinfo);
bf1251
-                    break;
bf1251
-                }
bf1251
-                XRRFreeOutputInfo(oinfo);
bf1251
-            }
bf1251
+    if (conn == NULL) {
bf1251
+        syslog(LOG_WARNING, "Unable to get drm connector for display id %i",
bf1251
+               device_info->device_display_id);
bf1251
+        return -1;
bf1251
+    }
bf1251
+
bf1251
+    bool decrement_name = false;
bf1251
+
bf1251
+    if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL
bf1251
+        && has_virtual_zero_display) {
bf1251
+        decrement_name = true;
bf1251
+    }
bf1251
+
bf1251
+    // Compare the name of the xrandr output against what we would
bf1251
+    // expect based on the drm connection type. The xrandr names
bf1251
+    // are driver-specific, so we need to special-case some
bf1251
+    // drivers.  Most hardware these days uses the 'modesetting'
bf1251
+    // driver, but the QXL device uses its own driver which has
bf1251
+    // different naming conventions
bf1251
+    if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
bf1251
+        drm_conn_name_qxl(conn, expected_name, name_size, decrement_name);
bf1251
+    } else {
bf1251
+        drm_conn_name_modesetting(conn, expected_name, name_size);
bf1251
+    }
bf1251
+    drmModeFreeConnector(conn);
bf1251
+
bf1251
+    return 0;
bf1251
+}
bf1251
+
bf1251
+// PCI address should be in the following format:
bf1251
+//   pci/$domain/$slot.$fn/$slot.$fn
bf1251
+bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
+                                          Display *xdisplay,
bf1251
+                                          XRRScreenResources *xres,
bf1251
+                                          RROutput *output_id)
bf1251
+{
bf1251
+    char expected_name[100];
bf1251
+    int ret;
bf1251
+
bf1251
+    // Older QXL drivers numbered their outputs starting with
bf1251
+    // 0. This contrasts with most drivers who start numbering
bf1251
+    // outputs with 1.  In this case, the expected drm connector
bf1251
+    // name will need to be decremented before comparing to the
bf1251
+    // xrandr output name
bf1251
+    bool has_virtual_zero_display = false;
bf1251
+    for (int i = 0; i < xres->noutput; ++i) {
bf1251
+        XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
bf1251
+        if (!oinfo) {
bf1251
+            syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
bf1251
+                   xres->outputs[i]);
bf1251
+            return false;
bf1251
         }
bf1251
-        // Compare the name of the xrandr output against what we would
bf1251
-        // expect based on the drm connection type. The xrandr names
bf1251
-        // are driver-specific, so we need to special-case some
bf1251
-        // drivers.  Most hardware these days uses the 'modesetting'
bf1251
-        // driver, but the QXL device uses its own driver which has
bf1251
-        // different naming conventions
bf1251
-        char expected_name[100];
bf1251
-        if (vendor_id == PCI_VENDOR_ID_REDHAT && device_id == PCI_DEVICE_ID_QXL) {
bf1251
-            drm_conn_name_qxl(conn, expected_name, sizeof(expected_name), decrement_name);
bf1251
-        } else {
bf1251
-            drm_conn_name_modesetting(conn, expected_name, sizeof(expected_name));
bf1251
+        if (strcmp(oinfo->name, "Virtual-0") == 0) {
bf1251
+            has_virtual_zero_display = true;
bf1251
+            XRRFreeOutputInfo(oinfo);
bf1251
+            break;
bf1251
         }
bf1251
+        XRRFreeOutputInfo(oinfo);
bf1251
+    }
bf1251
 
bf1251
+    ret = get_connector_name_for_device_info(device_info, expected_name, sizeof(expected_name),
bf1251
+                                             has_virtual_zero_display);
bf1251
+    switch (ret) {
bf1251
+    case -1:    // generic error => exit
bf1251
+        return false;
bf1251
+    case 0:
bf1251
         // Loop through xrandr outputs and check whether the xrandr
bf1251
         // output name matches the drm connector name
bf1251
         for (int i = 0; i < xres->noutput; ++i) {
bf1251
@@ -493,13 +533,8 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
             }
bf1251
             XRRFreeOutputInfo(oinfo);
bf1251
         }
bf1251
-        drmModeFreeConnector(conn);
bf1251
-    } else {
bf1251
-        close(drm_fd);
bf1251
-        syslog(LOG_WARNING,
bf1251
-               "Unable to get DRM resources for card %s. "
bf1251
-               "Falling back to using xrandr output index.",
bf1251
-               dev_path);
bf1251
+        break;
bf1251
+    case 1:     // no DRM info found
bf1251
         // This is probably a proprietary driver (e.g. Nvidia) that does
bf1251
         // not provide outputs via drm, so the only thing we can do is just
bf1251
         // assume that it is the only device assigned to X, and use the
bf1251
diff --git a/src/vdagent/device-info.h b/src/vdagent/device-info.h
bf1251
index 8646cc5..d4d8cbd 100644
bf1251
--- a/src/vdagent/device-info.h
bf1251
+++ b/src/vdagent/device-info.h
bf1251
@@ -28,3 +28,7 @@ bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
                                           Display *xdisplay,
bf1251
                                           XRRScreenResources *xres,
bf1251
                                           RROutput *output_id);
bf1251
+
bf1251
+int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
+                                       char *expected_name, size_t name_size,
bf1251
+                                       bool has_virtual_zero_display);
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index 2577f9c..b82db5c 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -50,6 +47,8 @@
bf1251
  * The x11.c and x11-randr.c files contains the x11-specific functions.
bf1251
  */
bf1251
 struct VDAgentDisplay {
bf1251
+    // association between SPICE display ID and expected connector name
bf1251
+    GHashTable *connector_mapping;
bf1251
     struct vdagent_x11 *x11;
bf1251
     UdscsConnection *vdagentd;
bf1251
     int debug;
bf1251
@@ -132,6 +130,7 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
     }
bf1251
 
bf1251
     display->x11->vdagent_display = display;
bf1251
+    display->connector_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
bf1251
 
bf1251
     display->x11_channel = g_io_channel_unix_new(vdagent_x11_get_fd(display->x11));
bf1251
     if (display->x11_channel == NULL) {
bf1251
@@ -167,6 +168,8 @@ void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected)
bf1251
         return;
bf1251
     }
bf1251
 
bf1251
+    g_hash_table_destroy(display->connector_mapping);
bf1251
+
bf1251
     g_clear_pointer(&display->x11_channel, g_io_channel_unref);
bf1251
     vdagent_x11_destroy(display->x11, vdagentd_disconnected);
bf1251
 }
bf1251
@@ -227,6 +232,19 @@ void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_
bf1251
                    device_display_info->channel_id, device_display_info->monitor_id);
bf1251
         }
bf1251
 
bf1251
+        // Get the expected connector name from hardware info. Store it with the SPICE display ID.
bf1251
+        char expected_name[100];
bf1251
+        int ret = get_connector_name_for_device_info(device_display_info, expected_name,
bf1251
+                                                     sizeof(expected_name), false);
bf1251
+        if (ret == 0) {
bf1251
+            g_hash_table_insert(display->connector_mapping,
bf1251
+                                g_strdup(expected_name),
bf1251
+                                GUINT_TO_POINTER(device_display_info->channel_id + device_display_info->monitor_id));
bf1251
+            syslog(LOG_DEBUG, "Mapping connector %s to display #%d", expected_name,
bf1251
+                   (device_display_info->channel_id + device_display_info->monitor_id));
bf1251
+        }
bf1251
+
bf1251
+        // Also map the SPICE display ID to the corresponding X server object.
bf1251
         vdagent_x11_handle_device_display_info(display->x11, device_display_info);
bf1251
 
bf1251
         device_display_info = (VDAgentDeviceDisplayInfo*) ((char*) device_display_info +
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From 4c8009068115b6f89491e0e3e108d38084b2417a Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Wed, 29 Apr 2020 16:31:58 +0200
bf1251
Subject: [PATCH 4/7] Split the "lookup_xrandr_output_for_device_info()"
bf1251
 function to reuse some of it with different backends.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
Most display drivers will number their outputs starting with "1", but
bf1251
some (like older QXL drivers) will start from 0.
bf1251
As we need to map device names with SPICE display IDs, we need to know
bf1251
what to expect.
bf1251
bf1251
The logic that finds whether we have a O-based index or not is
bf1251
independent from the backend, and can be reused outside of the X11
bf1251
implementation.
bf1251
bf1251
This commit separates this logic for that purpose, to prevent code
bf1251
duplication.
bf1251
- create the has_zero_based_display_id() function to call whatever the
bf1251
  backend, and learn whether our IDs should be decremented or not.
bf1251
  Its code is taken out of lookup_xrandr_output_for_device_info()
bf1251
- keep the lookup_xrandr_output_for_device_info() for x11 implementation
bf1251
- add parameters to some functions to give them the information that IDs
bf1251
  should be decremented because of the 0-based index.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Frediano Ziglio <fziglio@redhat.com>
bf1251
---
bf1251
 src/vdagent/device-info.c | 24 ++---------------
bf1251
 src/vdagent/device-info.h |  3 ++-
bf1251
 src/vdagent/display.c     | 56 +++++++++++++++++++++++++++++++++++++--
bf1251
 src/vdagent/x11-randr.c   |  5 ++--
bf1251
 src/vdagent/x11.h         |  3 ++-
bf1251
 5 files changed, 63 insertions(+), 28 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/device-info.c b/src/vdagent/device-info.c
bf1251
index 8cf72c9..f07de03 100644
bf1251
--- a/src/vdagent/device-info.c
bf1251
+++ b/src/vdagent/device-info.c
bf1251
@@ -482,32 +482,12 @@ int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
 bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
                                           Display *xdisplay,
bf1251
                                           XRRScreenResources *xres,
bf1251
-                                          RROutput *output_id)
bf1251
+                                          RROutput *output_id,
bf1251
+                                          bool has_virtual_zero_display)
bf1251
 {
bf1251
     char expected_name[100];
bf1251
     int ret;
bf1251
 
bf1251
-    // Older QXL drivers numbered their outputs starting with
bf1251
-    // 0. This contrasts with most drivers who start numbering
bf1251
-    // outputs with 1.  In this case, the expected drm connector
bf1251
-    // name will need to be decremented before comparing to the
bf1251
-    // xrandr output name
bf1251
-    bool has_virtual_zero_display = false;
bf1251
-    for (int i = 0; i < xres->noutput; ++i) {
bf1251
-        XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
bf1251
-        if (!oinfo) {
bf1251
-            syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
bf1251
-                   xres->outputs[i]);
bf1251
-            return false;
bf1251
-        }
bf1251
-        if (strcmp(oinfo->name, "Virtual-0") == 0) {
bf1251
-            has_virtual_zero_display = true;
bf1251
-            XRRFreeOutputInfo(oinfo);
bf1251
-            break;
bf1251
-        }
bf1251
-        XRRFreeOutputInfo(oinfo);
bf1251
-    }
bf1251
-
bf1251
     ret = get_connector_name_for_device_info(device_info, expected_name, sizeof(expected_name),
bf1251
                                              has_virtual_zero_display);
bf1251
     switch (ret) {
bf1251
diff --git a/src/vdagent/device-info.h b/src/vdagent/device-info.h
bf1251
index d4d8cbd..f90fbe2 100644
bf1251
--- a/src/vdagent/device-info.h
bf1251
+++ b/src/vdagent/device-info.h
bf1251
@@ -27,7 +27,8 @@ struct vdagent_x11;
bf1251
 bool lookup_xrandr_output_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
                                           Display *xdisplay,
bf1251
                                           XRRScreenResources *xres,
bf1251
-                                          RROutput *output_id);
bf1251
+                                          RROutput *output_id,
bf1251
+                                          bool has_virtual_zero_display);
bf1251
 
bf1251
 int get_connector_name_for_device_info(VDAgentDeviceDisplayInfo *device_info,
bf1251
                                        char *expected_name, size_t name_size,
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index b82db5c..d556f92 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -212,6 +197,57 @@ gboolean vdagent_display_has_icons_on_desktop(VDAgentDisplay *display)
bf1251
     return FALSE;
bf1251
 }
bf1251
 
bf1251
+static bool has_zero_based_display_id(VDAgentDisplay *display)
bf1251
+{
bf1251
+    // Older QXL drivers numbered their outputs starting with
bf1251
+    // 0. This contrasts with most drivers who start numbering
bf1251
+    // outputs with 1.  In this case, the expected drm connector
bf1251
+    // name will need to be decremented before comparing to the
bf1251
+    // display manager output name
bf1251
+    bool ret = false;
bf1251
+#ifdef USE_GTK_FOR_MONITORS
bf1251
+    GdkDisplay *gdk_display = gdk_display_get_default();
bf1251
+    if (GDK_IS_WAYLAND_DISPLAY(gdk_display)) {
bf1251
+        gdk_display_sync(gdk_display);
bf1251
+
bf1251
+        GListModel *monitors = gdk_display_get_monitors(gdk_display);
bf1251
+        int screen_count = g_list_model_get_n_items(monitors);
bf1251
+        for (int i = 0; i < screen_count; i++) {
bf1251
+            GdkMonitor *monitor = (GdkMonitor *)g_list_model_get_item(monitors, i);
bf1251
+            const char *name = gdk_monitor_get_connector(monitor);
bf1251
+            if (!name) {
bf1251
+                continue;
bf1251
+            }
bf1251
+
bf1251
+            if (strcmp(name, "Virtual-0") == 0) {
bf1251
+                ret = true;
bf1251
+                break;
bf1251
+            }
bf1251
+        }
bf1251
+    }
bf1251
+    else // otherwise, use the X11 code (below)
bf1251
+#endif
bf1251
+    {
bf1251
+        XRRScreenResources *xres = display->x11->randr.res;
bf1251
+        Display *xdisplay = display->x11->display;
bf1251
+        for (int i = 0; i < xres->noutput; ++i) {
bf1251
+            XRROutputInfo *oinfo = XRRGetOutputInfo(xdisplay, xres, xres->outputs[i]);
bf1251
+            if (!oinfo) {
bf1251
+                syslog(LOG_WARNING, "Unable to lookup XRandr output info for output %li",
bf1251
+                       xres->outputs[i]);
bf1251
+                return false;
bf1251
+            }
bf1251
+            if (strcmp(oinfo->name, "Virtual-0") == 0) {
bf1251
+                ret = true;
bf1251
+                XRRFreeOutputInfo(oinfo);
bf1251
+                break;
bf1251
+            }
bf1251
+            XRRFreeOutputInfo(oinfo);
bf1251
+        }
bf1251
+    }
bf1251
+    return ret;
bf1251
+}
bf1251
+
bf1251
 // handle the device info message from the server. This will allow us to
bf1251
 // maintain a mapping from spice display id to xrandr output
bf1251
 void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_t *data,
bf1251
@@ -221,6 +257,7 @@ void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_
bf1251
     VDAgentDeviceDisplayInfo *device_display_info = graphics_device_info->display_info;
bf1251
 
bf1251
     void *buffer_end = data + size;
bf1251
+    bool decrement_id = has_zero_based_display_id(display);
bf1251
 
bf1251
     syslog(LOG_INFO, "Received Graphics Device Info:");
bf1251
 
bf1251
@@ -246,7 +281,7 @@ void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_
bf1251
         // Get the expected connector name from hardware info. Store it with the SPICE display ID.
bf1251
         char expected_name[100];
bf1251
         int ret = get_connector_name_for_device_info(device_display_info, expected_name,
bf1251
-                                                     sizeof(expected_name), false);
bf1251
+                                                     sizeof(expected_name), decrement_id);
bf1251
         if (ret == 0) {
bf1251
             g_hash_table_insert(display->connector_mapping,
bf1251
                                 g_strdup(expected_name),
bf1251
@@ -258,7 +291,7 @@ void vdagent_display_handle_graphics_device_info(VDAgentDisplay *display, uint8_
bf1251
         }
bf1251
 
bf1251
         // Also map the SPICE display ID to the corresponding X server object.
bf1251
-        vdagent_x11_handle_device_display_info(display->x11, device_display_info);
bf1251
+        vdagent_x11_handle_device_display_info(display->x11, device_display_info, decrement_id);
bf1251
 
bf1251
         device_display_info = (VDAgentDeviceDisplayInfo*) ((char*) device_display_info +
bf1251
             sizeof(VDAgentDeviceDisplayInfo) + device_display_info->device_address_len);
bf1251
diff --git a/src/vdagent/x11-randr.c b/src/vdagent/x11-randr.c
bf1251
index 145e75a..cac9643 100644
bf1251
--- a/src/vdagent/x11-randr.c
bf1251
+++ b/src/vdagent/x11-randr.c
bf1251
@@ -779,11 +779,12 @@ static void dump_monitors_config(struct vdagent_x11 *x11,
bf1251
 // handle the device info message from the server. This will allow us to
bf1251
 // maintain a mapping from spice display id to xrandr output
bf1251
 void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
-                                            VDAgentDeviceDisplayInfo *device_display_info)
bf1251
+                                            VDAgentDeviceDisplayInfo *device_display_info,
bf1251
+                                            gboolean has_virtual_zero_display)
bf1251
 {
bf1251
     RROutput x_output;
bf1251
     if (lookup_xrandr_output_for_device_info(device_display_info, x11->display,
bf1251
-                                             x11->randr.res, &x_output)) {
bf1251
+                                             x11->randr.res, &x_output, has_virtual_zero_display)) {
bf1251
         syslog(LOG_INFO, "Adding graphics device info: channel_id: %u monitor_id: "
bf1251
                "%u device_address: %s, device_display_id: %u xrandr output ID: %lu",
bf1251
                device_display_info->channel_id,
bf1251
diff --git a/src/vdagent/x11.h b/src/vdagent/x11.h
bf1251
index a75638c..45018bd 100644
bf1251
--- a/src/vdagent/x11.h
bf1251
+++ b/src/vdagent/x11.h
bf1251
@@ -53,6 +53,7 @@ void vdagent_x11_client_disconnected(struct vdagent_x11 *x11);
bf1251
 gchar *vdagent_x11_get_wm_name(struct vdagent_x11 *x11);
bf1251
 
bf1251
 void vdagent_x11_handle_device_display_info(struct vdagent_x11 *x11,
bf1251
-                                            VDAgentDeviceDisplayInfo *device_display_info);
bf1251
+                                            VDAgentDeviceDisplayInfo *device_display_info,
bf1251
+                                            gboolean has_virtual_zero_display);
bf1251
 
bf1251
 #endif
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From 6c475b368d34f24509bd03412b0a8a4d81a9f2e7 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Thu, 26 Mar 2020 15:16:51 +0100
bf1251
Subject: [PATCH 5/7] Send guest resolution using GDK functions.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
- RHEL 8.4: skeleton implementation of vdagent_gtk_get_resolutions().
bf1251
  Do not introduce GTK4 code into RHEL8.4 as this will not be used anyway.
bf1251
- Add disabled monitors to the list before sending
bf1251
  (vdagent_display_send_daemon_guest_res)
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
---
bf1251
 src/vdagent/display.c | 149 +++++++++++++++++++++++++++++++++++++++++-
bf1251
 1 file changed, 146 insertions(+), 3 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index d556f92..a6de9c0 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -63,14 +55,76 @@ struct VDAgentDisplay {
bf1251
     GIOChannel *x11_channel;
bf1251
 };
bf1251
 
bf1251
+static gint vdagent_guest_xorg_resolution_compare(gconstpointer a, gconstpointer b)
bf1251
+{
bf1251
+    struct vdagentd_guest_xorg_resolution *ptr_a, *ptr_b;
bf1251
+
bf1251
+    ptr_a = (struct vdagentd_guest_xorg_resolution *)a;
bf1251
+    ptr_b = (struct vdagentd_guest_xorg_resolution *)b;
bf1251
+
bf1251
+    return ptr_a->display_id - ptr_b->display_id;
bf1251
+}
bf1251
+
bf1251
+static GArray *vdagent_gtk_get_resolutions(VDAgentDisplay *display,
bf1251
+                                           int *width, int *height, int *screen_count)
bf1251
+{
bf1251
+    return NULL;
bf1251
+}
bf1251
+
bf1251
 void vdagent_display_send_daemon_guest_res(VDAgentDisplay *display, gboolean update)
bf1251
 {
bf1251
     GArray *res_array;
bf1251
-    int width, height, screen_count;
bf1251
+    int width = 0, height = 0, screen_count = 0;
bf1251
 
bf1251
-    res_array = vdagent_x11_get_resolutions(display->x11, update, &width, &height, &screen_count);
bf1251
+    res_array = vdagent_gtk_get_resolutions(display, &width, &height, &screen_count);
bf1251
     if (res_array == NULL) {
bf1251
-        return;
bf1251
+        if (display->x11->dont_send_guest_xorg_res) {
bf1251
+            return;
bf1251
+        }
bf1251
+
bf1251
+        res_array = vdagent_x11_get_resolutions(display->x11, update,
bf1251
+                                                &width, &height, &screen_count);
bf1251
+        if (res_array == NULL) {
bf1251
+            return;
bf1251
+        }
bf1251
     }
bf1251
+
bf1251
+    if (res_array->len < g_hash_table_size(display->connector_mapping)) {
bf1251
+        // Complete the array with disabled displays.
bf1251
+        // We need to send 0x0 resolution to let the daemon know the display is not there anymore.
bf1251
+
bf1251
+        syslog(LOG_DEBUG, "%d/%d displays found - completing with disabled displays.",
bf1251
+               res_array->len, g_hash_table_size(display->connector_mapping));
bf1251
+
bf1251
+        GHashTableIter iter;
bf1251
+        gpointer key, value;
bf1251
+        g_hash_table_iter_init(&iter, display->connector_mapping);
bf1251
+        while (g_hash_table_iter_next(&iter, &key, &value)) {
bf1251
+            bool found = false;
bf1251
+            int display_id = GPOINTER_TO_INT(value);
bf1251
+            for (int i = 0; i < res_array->len; i++) {
bf1251
+                struct vdagentd_guest_xorg_resolution *res =
bf1251
+                    (struct vdagentd_guest_xorg_resolution*)res_array->data;
bf1251
+                if (res[i].display_id == display_id) {
bf1251
+                    found = true;
bf1251
+                    break;
bf1251
+                }
bf1251
+            }
bf1251
+            if (!found) {
bf1251
+                struct vdagentd_guest_xorg_resolution res;
bf1251
+
bf1251
+                res.x = 0;
bf1251
+                res.y = 0;
bf1251
+                res.height = 0;
bf1251
+                res.width = 0;
bf1251
+                res.display_id = display_id;
bf1251
+
bf1251
+                g_array_append_val(res_array, res);
bf1251
+            }
bf1251
+        }
bf1251
+    }
bf1251
+
bf1251
+    // sort the list to make sure we send them in the display_id order
bf1251
+    g_array_sort(res_array, vdagent_guest_xorg_resolution_compare);
bf1251
 
bf1251
     if (display->debug) {
bf1251
@@ -183,6 +231,7 @@ void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected)
bf1251
 
bf1251
     g_clear_pointer(&display->x11_channel, g_io_channel_unref);
bf1251
     vdagent_x11_destroy(display->x11, vdagentd_disconnected);
bf1251
+    g_free(display);
bf1251
 }
bf1251
 
bf1251
 /* Function used to determine the default location to save file-xfers,
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From 73bf8367268e7ef5a00fd23674b0a8700d0e4a85 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Mon, 12 Oct 2020 10:07:42 +0200
bf1251
Subject: [PATCH 3/4] Add implementation of the DBUS interface to Mutter.
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
This can be used to retrieve monitor resolutions directly from the
bf1251
Mutter compositor under Wayland.
bf1251
Under environments using a different compositor, the X11 lib will keep
bf1251
being used.
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Jakub Janků <jjanku@redhat.com>
bf1251
---
bf1251
 Makefile.am          |   2 +
bf1251
 src/vdagent/mutter.c | 276 +++++++++++++++++++++++++++++++++++++++++++
bf1251
 src/vdagent/mutter.h |  33 ++++++
bf1251
 3 files changed, 311 insertions(+)
bf1251
 create mode 100644 src/vdagent/mutter.c
bf1251
 create mode 100644 src/vdagent/mutter.h
bf1251
bf1251
diff --git a/Makefile.am b/Makefile.am
bf1251
index 47d7820..e8fa4a6 100644
bf1251
--- a/Makefile.am
bf1251
+++ b/Makefile.am
bf1251
@@ -49,6 +47,8 @@ src_spice_vdagent_SOURCES =			\
bf1251
 	src/vdagent/display.h			\
bf1251
 	src/vdagent/file-xfers.c		\
bf1251
 	src/vdagent/file-xfers.h		\
bf1251
+	src/vdagent/mutter.c			\
bf1251
+	src/vdagent/mutter.h			\
bf1251
 	src/vdagent/x11-priv.h			\
bf1251
 	src/vdagent/x11-randr.c			\
bf1251
 	src/vdagent/x11.c			\
bf1251
diff --git a/src/vdagent/mutter.c b/src/vdagent/mutter.c
bf1251
new file mode 100644
bf1251
index 0000000..f6ff11b
bf1251
--- /dev/null
bf1251
+++ b/src/vdagent/mutter.c
bf1251
@@ -0,0 +1,276 @@
bf1251
+/* mutter.c - implements the DBUS interface to mutter
bf1251
+
bf1251
+ Copyright 2020 Red Hat, Inc.
bf1251
+
bf1251
+ Red Hat Authors:
bf1251
+ Julien Ropé <jrope@redhat.com>
bf1251
+
bf1251
+ This program is free software: you can redistribute it and/or modify
bf1251
+ it under the terms of the GNU General Public License as published by
bf1251
+ the Free Software Foundation, either version 3 of the License, or
bf1251
+ (at your option) any later version.
bf1251
+
bf1251
+ This program is distributed in the hope that it will be useful,
bf1251
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
bf1251
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bf1251
+ GNU General Public License for more details.
bf1251
+
bf1251
+ You should have received a copy of the GNU General Public License
bf1251
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
bf1251
+ */
bf1251
+
bf1251
+#include <config.h>
bf1251
+
bf1251
+#include <glib.h>
bf1251
+#include <gio/gio.h>
bf1251
+
bf1251
+#include <syslog.h>
bf1251
+
bf1251
+#include "vdagentd-proto.h"
bf1251
+#include "mutter.h"
bf1251
+
bf1251
+// MUTTER DBUS FORMAT STRINGS
bf1251
+#define MODE_BASE_FORMAT "siiddad"
bf1251
+#define MODE_FORMAT "(" MODE_BASE_FORMAT "a{sv})"
bf1251
+#define MODES_FORMAT "a" MODE_FORMAT
bf1251
+#define MONITOR_SPEC_FORMAT "(ssss)"
bf1251
+#define MONITOR_FORMAT "(" MONITOR_SPEC_FORMAT MODES_FORMAT "a{sv})"
bf1251
+#define MONITORS_FORMAT "a" MONITOR_FORMAT
bf1251
+
bf1251
+#define LOGICAL_MONITOR_MONITORS_FORMAT "a" MONITOR_SPEC_FORMAT
bf1251
+#define LOGICAL_MONITOR_FORMAT "(iidub" LOGICAL_MONITOR_MONITORS_FORMAT "a{sv})"
bf1251
+#define LOGICAL_MONITORS_FORMAT "a" LOGICAL_MONITOR_FORMAT
bf1251
+
bf1251
+#define CURRENT_STATE_FORMAT "(u" MONITORS_FORMAT LOGICAL_MONITORS_FORMAT "a{sv})"
bf1251
+
bf1251
+
bf1251
+struct VDAgentMutterDBus {
bf1251
+    GDBusProxy *dbus_proxy;
bf1251
+    GHashTable *connector_mapping;
bf1251
+};
bf1251
+
bf1251
+/**
bf1251
+ * Initialise a communication to Mutter through its DBUS interface.
bf1251
+ *
bf1251
+ * Errors can indicate that another compositor is used. This is not a blocker, and we should default
bf1251
+ * to use a different API then.
bf1251
+ *
bf1251
+ * Returns:
bf1251
+ * An initialise VDAgentMutterDBus structure if successful.
bf1251
+ * NULL if an error occured.
bf1251
+ */
bf1251
+VDAgentMutterDBus *vdagent_mutter_create(GHashTable *connector_mapping)
bf1251
+{
bf1251
+    GError *error = NULL;
bf1251
+    VDAgentMutterDBus *mutter = g_new0(VDAgentMutterDBus, 1);
bf1251
+
bf1251
+    mutter->connector_mapping = g_hash_table_ref(connector_mapping);
bf1251
+
bf1251
+    GDBusProxyFlags flags = (G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
bf1251
+                            | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
bf1251
+                            | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS);
bf1251
+
bf1251
+    mutter->dbus_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION,
bf1251
+                                                       flags,
bf1251
+                                                       NULL,
bf1251
+                                                       "org.gnome.Mutter.DisplayConfig",
bf1251
+                                                       "/org/gnome/Mutter/DisplayConfig",
bf1251
+                                                       "org.gnome.Mutter.DisplayConfig",
bf1251
+                                                       NULL,
bf1251
+                                                       &error);
bf1251
+    if (!mutter->dbus_proxy) {
bf1251
+        syslog(LOG_WARNING, "display: failed to create dbus proxy: %s", error->message);
bf1251
+        g_clear_error(&error);
bf1251
+        vdagent_mutter_destroy(mutter);
bf1251
+        return NULL;
bf1251
+    }
bf1251
+
bf1251
+    return mutter;
bf1251
+}
bf1251
+
bf1251
+
bf1251
+void vdagent_mutter_destroy(VDAgentMutterDBus *mutter)
bf1251
+{
bf1251
+    g_clear_object(&mutter->dbus_proxy);
bf1251
+    g_hash_table_unref(mutter->connector_mapping);
bf1251
+    g_free(mutter);
bf1251
+}
bf1251
+
bf1251
+/** Look through a list of logical monitor to find the one provided.
bf1251
+ *  Returns the corresponding x and y position of the monitor on the desktop.
bf1251
+ *  This function is a helper to vdagent_mutter_get_resolution().
bf1251
+ *
bf1251
+ *  Parameters:
bf1251
+ *  logical_monitor: initialized GVariant iterator. It will be copied to look through the items
bf1251
+ *                   so that its original position is not modified.
bf1251
+ *  connector: name of the connector that must be found
bf1251
+ *  x and y: will received the found position
bf1251
+ *
bf1251
+ */
bf1251
+static void vdagent_mutter_get_monitor_position(GVariantIter *logical_monitors,
bf1251
+                                                const gchar *connector, int *x, int *y)
bf1251
+{
bf1251
+    GVariant *logical_monitor = NULL;
bf1251
+    GVariantIter *logical_monitor_iterator = g_variant_iter_copy(logical_monitors);
bf1251
+    while (g_variant_iter_next(logical_monitor_iterator, "@"LOGICAL_MONITOR_FORMAT,
bf1251
+                               &logical_monitor)) {
bf1251
+        GVariantIter *tmp_monitors = NULL;
bf1251
+
bf1251
+        g_variant_get_child(logical_monitor, 0, "i", x);
bf1251
+        g_variant_get_child(logical_monitor, 1, "i", y);
bf1251
+        g_variant_get_child(logical_monitor, 5, LOGICAL_MONITOR_MONITORS_FORMAT, &tmp_monitors);
bf1251
+
bf1251
+        g_variant_unref(logical_monitor);
bf1251
+
bf1251
+        GVariant *tmp_monitor = NULL;
bf1251
+        gboolean found = FALSE;
bf1251
+        while (!found && g_variant_iter_next(tmp_monitors, "@"MONITOR_SPEC_FORMAT, &tmp_monitor)) {
bf1251
+            const gchar *tmp_connector;
bf1251
+
bf1251
+            g_variant_get_child(tmp_monitor, 0, "&s", &tmp_connector);
bf1251
+
bf1251
+            if (g_strcmp0(connector, tmp_connector) == 0) {
bf1251
+                found = TRUE;
bf1251
+            }
bf1251
+            g_variant_unref(tmp_monitor);
bf1251
+        }
bf1251
+
bf1251
+        g_variant_iter_free(tmp_monitors);
bf1251
+
bf1251
+        if (found) {
bf1251
+            break;
bf1251
+        }
bf1251
+        *x = *y = 0;
bf1251
+    }
bf1251
+    g_variant_iter_free(logical_monitor_iterator);
bf1251
+}
bf1251
+
bf1251
+GArray *vdagent_mutter_get_resolutions(VDAgentMutterDBus *mutter,
bf1251
+                                       int *desktop_width, int *desktop_height, int *screen_count)
bf1251
+{
bf1251
+    GError *error = NULL;
bf1251
+    GArray *res_array = NULL;
bf1251
+
bf1251
+    // keep track of monitors we find and are not mapped to SPICE displays
bf1251
+    // we will map them back later (assuming display ID == monitor index)
bf1251
+    // this prevents the need from looping twice on all DBUS items
bf1251
+    GArray *not_found_array = NULL;
bf1251
+
bf1251
+    if (!mutter) {
bf1251
+        return res_array;
bf1251
+    }
bf1251
+
bf1251
+    GVariant *values = g_dbus_proxy_call_sync(mutter->dbus_proxy,
bf1251
+                                              "GetCurrentState",
bf1251
+                                              NULL,
bf1251
+                                              G_DBUS_CALL_FLAGS_NONE,
bf1251
+                                              -1,   // use proxy default timeout
bf1251
+                                              NULL,
bf1251
+                                              &error);
bf1251
+    if (!values) {
bf1251
+        syslog(LOG_WARNING, "display: failed to call GetCurrentState from mutter over DBUS");
bf1251
+        if (error != NULL) {
bf1251
+            syslog(LOG_WARNING, "   error message: %s", error->message);
bf1251
+            g_clear_error(&error);
bf1251
+        }
bf1251
+        return res_array;
bf1251
+    }
bf1251
+
bf1251
+    res_array = g_array_new(FALSE, FALSE, sizeof(struct vdagentd_guest_xorg_resolution));
bf1251
+    not_found_array = g_array_new(FALSE, FALSE, sizeof(struct vdagentd_guest_xorg_resolution));
bf1251
+
bf1251
+    GVariantIter *monitors = NULL;
bf1251
+    GVariantIter *logical_monitors = NULL;
bf1251
+
bf1251
+    g_variant_get_child(values, 1, MONITORS_FORMAT, &monitors);
bf1251
+    g_variant_get_child(values, 2, LOGICAL_MONITORS_FORMAT, &logical_monitors);
bf1251
+
bf1251
+    // list monitors
bf1251
+    GVariant *monitor = NULL;
bf1251
+    *screen_count = g_variant_iter_n_children(monitors);
bf1251
+
bf1251
+    while (g_variant_iter_next(monitors, "@"MONITOR_FORMAT, &monitor)) {
bf1251
+
bf1251
+        const gchar *connector = NULL;
bf1251
+        GVariantIter *modes = NULL;
bf1251
+        GVariant *monitor_specs = NULL;
bf1251
+
bf1251
+        g_variant_get_child(monitor, 0, "@"MONITOR_SPEC_FORMAT, &monitor_specs);
bf1251
+        g_variant_get_child(monitor_specs, 0, "&s", &connector);
bf1251
+        g_variant_get_child(monitor, 1, MODES_FORMAT, &modes;;
bf1251
+
bf1251
+        g_variant_unref(monitor_specs);
bf1251
+        g_variant_unref(monitor);
bf1251
+
bf1251
+        // list modes
bf1251
+        GVariant *mode = NULL;
bf1251
+        while (g_variant_iter_next(modes, "@"MODE_FORMAT, &mode)) {
bf1251
+            GVariant *properties = NULL;
bf1251
+            gboolean is_current;
bf1251
+
bf1251
+            g_variant_get_child(mode, 6, "@a{sv}", &properties);
bf1251
+            if (!g_variant_lookup(properties, "is-current", "b", &is_current)) {
bf1251
+                is_current = FALSE;
bf1251
+            }
bf1251
+            g_variant_unref(properties);
bf1251
+
bf1251
+            if (!is_current) {
bf1251
+                g_variant_unref(mode);
bf1251
+                continue;
bf1251
+            }
bf1251
+
bf1251
+            struct vdagentd_guest_xorg_resolution curr;
bf1251
+            vdagent_mutter_get_monitor_position(logical_monitors, connector, &curr.x, &curr.y);
bf1251
+            g_variant_get_child(mode, 1, "i", &curr.width);
bf1251
+            g_variant_get_child(mode, 2, "i", &curr.height);
bf1251
+            g_variant_unref(mode);
bf1251
+
bf1251
+            // compute the size of the desktop based on the dimension of the monitors
bf1251
+            if (curr.x + curr.width > *desktop_width) {
bf1251
+                *desktop_width = curr.x + curr.width;
bf1251
+            }
bf1251
+            if (curr.y + curr.height > *desktop_height) {
bf1251
+                *desktop_height = curr.y + curr.height;
bf1251
+            }
bf1251
+
bf1251
+            gpointer value;
bf1251
+            if (g_hash_table_lookup_extended(mutter->connector_mapping, connector, NULL, &value)) {
bf1251
+                curr.display_id = GPOINTER_TO_UINT(value);
bf1251
+                syslog(LOG_DEBUG,
bf1251
+                       "Found monitor %s with geometry %dx%d+%d-%d - associating it to SPICE display #%d",
bf1251
+                       connector, curr.width, curr.height, curr.x, curr.y, curr.display_id);
bf1251
+                g_array_append_val(res_array, curr);
bf1251
+            } else {
bf1251
+                syslog(LOG_DEBUG, "No SPICE display found for connector %s", connector);
bf1251
+                g_array_append_val(not_found_array, curr);
bf1251
+            }
bf1251
+
bf1251
+            break;
bf1251
+        }
bf1251
+        g_variant_iter_free(modes);
bf1251
+    }
bf1251
+
bf1251
+    g_variant_iter_free(logical_monitors);
bf1251
+    g_variant_iter_free(monitors);
bf1251
+
bf1251
+    int i;
bf1251
+
bf1251
+    if (res_array->len == 0) {
bf1251
+        syslog(LOG_DEBUG, "%s: No Spice display ID matching - assuming display ID == Monitor index",
bf1251
+                __FUNCTION__);
bf1251
+        g_array_free(res_array, TRUE);
bf1251
+        res_array = not_found_array;
bf1251
+
bf1251
+        struct vdagentd_guest_xorg_resolution *res;
bf1251
+        res = (struct vdagentd_guest_xorg_resolution*)res_array->data;
bf1251
+        for (i = 0; i < res_array->len; i++) {
bf1251
+            res[i].display_id = i;
bf1251
+        }
bf1251
+    }
bf1251
+    else {
bf1251
+        g_array_free(not_found_array, TRUE);
bf1251
+    }
bf1251
+
bf1251
+    g_variant_unref(values);
bf1251
+    return res_array;
bf1251
+}
bf1251
diff --git a/src/vdagent/mutter.h b/src/vdagent/mutter.h
bf1251
new file mode 100644
bf1251
index 0000000..abd2bd2
bf1251
--- /dev/null
bf1251
+++ b/src/vdagent/mutter.h
bf1251
@@ -0,0 +1,33 @@
bf1251
+/* mutter.h - implements the DBUS interface to mutter
bf1251
+
bf1251
+ Copyright 2020 Red Hat, Inc.
bf1251
+
bf1251
+ Red Hat Authors:
bf1251
+ Julien Ropé <jrope@redhat.com>
bf1251
+
bf1251
+ This program is free software: you can redistribute it and/or modify
bf1251
+ it under the terms of the GNU General Public License as published by
bf1251
+ the Free Software Foundation, either version 3 of the License, or
bf1251
+ (at your option) any later version.
bf1251
+
bf1251
+ This program is distributed in the hope that it will be useful,
bf1251
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
bf1251
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bf1251
+ GNU General Public License for more details.
bf1251
+
bf1251
+ You should have received a copy of the GNU General Public License
bf1251
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
bf1251
+ */
bf1251
+
bf1251
+#ifndef SRC_VDAGENT_MUTTER_H_
bf1251
+#define SRC_VDAGENT_MUTTER_H_
bf1251
+
bf1251
+typedef struct VDAgentMutterDBus VDAgentMutterDBus;
bf1251
+
bf1251
+VDAgentMutterDBus *vdagent_mutter_create(GHashTable *connector_mapping);
bf1251
+void vdagent_mutter_destroy(VDAgentMutterDBus *mutter);
bf1251
+
bf1251
+GArray *vdagent_mutter_get_resolutions(VDAgentMutterDBus *mutter, int *width, int *height, int *screen_count);
bf1251
+
bf1251
+
bf1251
+#endif /* SRC_VDAGENT_MUTTER_H_ */
bf1251
-- 
bf1251
2.29.2
bf1251
bf1251
bf1251
From 58d97554e52be79f450c4da664c2191966bf60a9 Mon Sep 17 00:00:00 2001
bf1251
From: =?UTF-8?q?Julien=20Rop=C3=A9?= <jrope@redhat.com>
bf1251
Date: Mon, 12 Oct 2020 14:55:51 +0200
bf1251
Subject: [PATCH 4/4] Use the Mutter API from display.c
bf1251
MIME-Version: 1.0
bf1251
Content-Type: text/plain; charset=UTF-8
bf1251
Content-Transfer-Encoding: 8bit
bf1251
bf1251
Signed-off-by: Julien Ropé <jrope@redhat.com>
bf1251
Acked-by: Jakub Janků <jjanku@redhat.com>
bf1251
---
bf1251
 src/vdagent/display.c | 32 ++++++++++++++++++++++----------
bf1251
 1 file changed, 22 insertions(+), 10 deletions(-)
bf1251
bf1251
diff --git a/src/vdagent/display.c b/src/vdagent/display.c
bf1251
index 9569173..790d9ad 100644
bf1251
--- a/src/vdagent/display.c
bf1251
+++ b/src/vdagent/display.c
bf1251
@@ -41,6 +35,7 @@
bf1251
 #include "device-info.h"
bf1251
 #include "vdagentd-proto.h"
bf1251
 
bf1251
+#include "mutter.h"
bf1251
 #include "display.h"
bf1251
 
bf1251
 /**
bf1251
@@ -59,6 +54,7 @@ struct VDAgentDisplay {
bf1251
     UdscsConnection *vdagentd;
bf1251
     int debug;
bf1251
     GIOChannel *x11_channel;
bf1251
+    VDAgentMutterDBus *mutter;
bf1251
 };
bf1251
 
bf1251
 static gint vdagent_guest_xorg_resolution_compare(gconstpointer a, gconstpointer b)
bf1251
@@ -161,17 +78,22 @@ void vdagent_display_send_daemon_guest_res(VDAgentDisplay *display, gboolean upd
bf1251
     GArray *res_array;
bf1251
     int width = 0, height = 0, screen_count = 0;
bf1251
 
bf1251
-    res_array = vdagent_gtk_get_resolutions(display, &width, &height, &screen_count);
bf1251
+    // Try various backends one after the other.
bf1251
+    // We try Mutter first, because it has a bigger probability of being available.
bf1251
+    // Second GTK, because if/when we build with GTK4, this is the one that will work best.
bf1251
+    // Finally we try X11. This is the default, and should work OK in most circumstances.
bf1251
+    res_array = vdagent_mutter_get_resolutions(display->mutter, &width, &height, &screen_count);
bf1251
+
bf1251
     if (res_array == NULL) {
bf1251
-        if (display->x11->dont_send_guest_xorg_res) {
bf1251
-            return;
bf1251
-        }
bf1251
+        res_array = vdagent_gtk_get_resolutions(display, &width, &height, &screen_count);
bf1251
+    }
bf1251
 
bf1251
-        res_array = vdagent_x11_get_resolutions(display->x11, update,
bf1251
-                                                &width, &height, &screen_count);
bf1251
-        if (res_array == NULL) {
bf1251
-            return;
bf1251
-        }
bf1251
+    if (res_array == NULL) {
bf1251
+        res_array = vdagent_x11_get_resolutions(display->x11, update, &width, &height, &screen_count);
bf1251
+    }
bf1251
+
bf1251
+    if (res_array == NULL) {
bf1251
+        return;
bf1251
     }
bf1251
 
bf1251
     if (res_array->len < g_hash_table_size(display->connector_mapping)) {
bf1251
@@ -280,6 +199,8 @@ VDAgentDisplay* vdagent_display_create(UdscsConnection *vdagentd, int debug, int
bf1251
     display->x11->vdagent_display = display;
bf1251
     display->connector_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
bf1251
 
bf1251
+    display->mutter = vdagent_mutter_create(display->connector_mapping);
bf1251
+
bf1251
     display->x11_channel = g_io_channel_unix_new(vdagent_x11_get_fd(display->x11));
bf1251
     if (display->x11_channel == NULL) {
bf1251
         vdagent_x11_destroy(display->x11, TRUE);
bf1251
@@ -314,10 +235,13 @@ void vdagent_display_destroy(VDAgentDisplay *display, int vdagentd_disconnected)
bf1251
         return;
bf1251
     }
bf1251
 
bf1251
-    g_hash_table_destroy(display->connector_mapping);
bf1251
 
bf1251
     g_clear_pointer(&display->x11_channel, g_io_channel_unref);
bf1251
     vdagent_x11_destroy(display->x11, vdagentd_disconnected);
bf1251
+
bf1251
+    vdagent_mutter_destroy(display->mutter);
bf1251
+
bf1251
+    g_hash_table_destroy(display->connector_mapping);
bf1251
     g_free(display);
bf1251
 }
bf1251
 
bf1251
-- 
bf1251
2.29.2
bf1251