From 9c5cb3367b05ab32c9ecd88842736639e5b17328 Mon Sep 17 00:00:00 2001
From: Jonathon Jongsma <jjongsma@redhat.com>
Date: Mon, 20 Jan 2014 10:26:10 -0600
Subject: [PATCH] Change per-guest fullscreen config format
use <display>:<monitor>;<display>:<monitor> instead of simply implying the
display from the array index (e.g. <monitor>;<monitor>). This allows you to set
up sparse guest displays (e.g. display 1 + 3).
For example, to configure display 1 to be fullscreen on monitor 2 and display 2
to be fullscreen on monitor 3:
monitor-mapping=1:2;2:3
---
src/virt-viewer-app.c | 133 +++++++++++++++++++++++++++++-----------
src/virt-viewer-session-spice.c | 2 +-
2 files changed, 99 insertions(+), 36 deletions(-)
diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c
index 8f5aa2b..9182fe4 100644
--- a/src/virt-viewer-app.c
+++ b/src/virt-viewer-app.c
@@ -108,7 +108,7 @@ struct _VirtViewerAppPrivate {
VirtViewerWindow *main_window;
GtkWidget *main_notebook;
GHashTable *windows;
- GArray *initial_display_map;
+ GHashTable *initial_display_map;
gchar *clipboard;
gboolean direct;
@@ -273,20 +273,19 @@ virt_viewer_app_quit(VirtViewerApp *self)
gint virt_viewer_app_get_n_initial_displays(VirtViewerApp* self)
{
if (self->priv->initial_display_map)
- return self->priv->initial_display_map->len;
+ return g_hash_table_size(self->priv->initial_display_map);
return gdk_screen_get_n_monitors(gdk_screen_get_default());
}
gint virt_viewer_app_get_initial_monitor_for_display(VirtViewerApp* self, gint display)
{
- gint monitor = -1;
+ gint monitor = display;
if (self->priv->initial_display_map) {
- if (display < self->priv->initial_display_map->len)
- monitor = g_array_index(self->priv->initial_display_map, gint, display);
- } else {
- monitor = display;
+ gpointer value = NULL;
+ if (g_hash_table_lookup_extended(self->priv->initial_display_map, GINT_TO_POINTER(display), NULL, &value))
+ monitor = GPOINTER_TO_INT(value);
}
return monitor;
@@ -307,43 +306,107 @@ app_window_try_fullscreen(VirtViewerApp *self G_GNUC_UNUSED,
}
-static
-void virt_viewer_app_set_uuid_string(VirtViewerApp* self, const gchar* uuid_string)
+static GHashTable*
+virt_viewer_app_parse_monitor_mappings(gchar **mappings, gsize nmappings)
{
- GArray* mapping = NULL;
- GError* error = NULL;
- gsize ndisplays = 0;
- gint* displays = NULL;
gint nmonitors = gdk_screen_get_n_monitors(gdk_screen_get_default());
+ GHashTable *displaymap = g_hash_table_new(g_direct_hash, g_direct_equal);
+ GHashTable *monitormap = g_hash_table_new(g_direct_hash, g_direct_equal);
+ int i = 0;
+ gchar **tokens = NULL;
+
+ for (i = 0; i < nmappings; i++) {
+ gchar *endptr = NULL;
+ gint display = 0, monitor = 0;
+
+ tokens = g_strsplit(mappings[i], ":", 2);
+ if (g_strv_length(tokens) != 2) {
+ g_warning("Invalid monitor-mapping configuration: '%s'. Expected format is '<DISPLAY-ID>:<MONITOR-ID>'. Got %lu elements", mappings[i], G_N_ELEMENTS(tokens));
+ g_strfreev(tokens);
+ goto configerror;
+ }
- g_debug("%s: UUID changed to %s", G_STRFUNC, uuid_string);
+ display = strtol(tokens[0], &endptr, 10);
+ if ((endptr && *endptr != '\0') || display < 1) {
+ g_warning("Invalid monitor-mapping configuration: display id is invalid: %s %p='%s'", tokens[0], endptr, endptr);
+ g_strfreev(tokens);
+ goto configerror;
+ }
+ monitor = strtol(tokens[1], &endptr, 10);
+ if ((endptr && *endptr != '\0') || monitor < 1) {
+ g_warning("Invalid monitor-mapping configuration: monitor id '%s' is invalid", tokens[1]);
+ g_strfreev(tokens);
+ goto configerror;
+ }
+ g_strfreev(tokens);
+
+ if (monitor > nmonitors)
+ g_warning("Initial monitor #%i for display #%i does not exist, skipping...", monitor, display);
+ else {
+ /* config file format is 1-based, not 0-based */
+ display--;
+ monitor--;
+
+ if (g_hash_table_lookup_extended(displaymap, GINT_TO_POINTER(display), NULL, NULL) ||
+ g_hash_table_lookup_extended(monitormap, GINT_TO_POINTER(monitor), NULL, NULL)) {
+ g_warning("Invalid monitor-mapping configuration: a display or monitor id was specified twice");
+ goto configerror;
+ }
+ g_debug("Fullscreen config: mapping guest display %i to monitor %i", display, monitor);
+ g_hash_table_insert(displaymap, GINT_TO_POINTER(display), GINT_TO_POINTER(monitor));
+ g_hash_table_insert(monitormap, GINT_TO_POINTER(monitor), GINT_TO_POINTER(display));
+ }
+ }
- g_free(self->priv->uuid);
- self->priv->uuid = g_strdup(uuid_string);
- displays = g_key_file_get_integer_list(self->priv->config,
- uuid_string, "monitor-mapping", &ndisplays, &error);
+ g_hash_table_unref(monitormap);
+ return displaymap;
+
+configerror:
+ g_hash_table_unref(monitormap);
+ g_hash_table_unref(displaymap);
+ return NULL;
+}
+
+static GHashTable*
+virt_viewer_app_get_monitor_mapping_for_section(VirtViewerApp *self, const gchar *section)
+{
+ GError *error = NULL;
+ gsize nmappings = 0;
+ gchar **mappings = NULL;
+ GHashTable *mapping = NULL;
+
+ mappings = g_key_file_get_string_list(self->priv->config,
+ section, "monitor-mapping", &nmappings, &error);
if (error) {
- if (error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
- g_warning("Error reading monitor assignments: %s", error->message);
+ if (error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND
+ && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+ g_warning("Error reading monitor assignments for %s: %s", section, error->message);
g_clear_error(&error);
} else {
- int i = 0;
- mapping = g_array_sized_new(FALSE, FALSE, sizeof(displays[0]), ndisplays);
- // config file format is 1-based, not 0-based
- for (i = 0; i < ndisplays; i++) {
- gint val = displays[i] - 1;
-
- // sanity check
- if (val >= nmonitors)
- g_warning("Initial monitor #%i for display #%i does not exist, skipping...", val, i);
- else
- g_array_append_val(mapping, val);
- }
- g_free(displays);
+ mapping = virt_viewer_app_parse_monitor_mappings(mappings, nmappings);
+ }
+ g_strfreev(mappings);
+
+ return mapping;
+}
+
+static
+void virt_viewer_app_set_uuid_string(VirtViewerApp *self, const gchar *uuid_string)
+{
+ GHashTable *mapping = NULL;
+
+ g_debug("%s: UUID changed to %s", G_STRFUNC, uuid_string);
+
+ g_free(self->priv->uuid);
+ self->priv->uuid = g_strdup(uuid_string);
+ mapping = virt_viewer_app_get_monitor_mapping_for_section(self, uuid_string);
+ if (!mapping) {
+ g_debug("No guest-specific fullscreen config, using fallback");
+ mapping = virt_viewer_app_get_monitor_mapping_for_section(self, "fallback");
}
if (self->priv->initial_display_map)
- g_array_unref(self->priv->initial_display_map);
+ g_hash_table_unref(self->priv->initial_display_map);
self->priv->initial_display_map = mapping;
@@ -1542,7 +1605,7 @@ virt_viewer_app_dispose (GObject *object)
g_free(priv->config_file);
priv->config_file = NULL;
g_clear_pointer(&priv->config, g_key_file_free);
- g_clear_pointer(&priv->initial_display_map, g_array_unref);
+ g_clear_pointer(&priv->initial_display_map, g_hash_table_unref);
virt_viewer_app_free_connect_info(self);
diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c
index c286fd9..097c9d7 100644
--- a/src/virt-viewer-session-spice.c
+++ b/src/virt-viewer-session-spice.c
@@ -855,7 +855,7 @@ name_changed(GObject *gobject G_GNUC_UNUSED,
VirtViewerSessionSpice *self)
{
gchar *name = NULL;
- VirtViewerApp* app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self));
+ VirtViewerApp *app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self));
g_object_get(self->priv->session, "name", &name, NULL);