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

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