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

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