----- Original Message ----- > Fullscreen mode generally just assigns display 1 to monitor 1, display 2 to > monitor 2, etc. For custom setups, you can define a monitor mapping in the > settings keyfile per-vm. This requires a vm uuid (so only works in > virt-viewer > or on versions of spice-server that send the uuid over the wire). The format > is > pretty basic: > > [6485b20f-e9da-614c-72b0-60a7857e7886] > monitor-mapping=2;3 > > The group name ("6485b20f-e9da-614c-72b0-60a7857e7886") is the uuid id of the > vm. This group has a single key: monitor-mapping. This key is an array of > integers describing the order in which to assign the monitors to a guest > display. Any monitors that are not listed in this array will not be > configured > at startup. For instance: > > monitor-mapping=2;1 > > will attempt to configure 2 displays on the guest and assign the first > display > to monitor 2 and the second display to monitor 1. > > monitor-mapping=2 > > will only configure a single display on the guest and place it on the second > monitor. Any monitor numbers listed in the keyfile are greater than the > number > of monitors that are physically present, they will be ignored. > --- > src/virt-viewer-app.c | 111 > ++++++++++++++++++++++++++++++++++------ > src/virt-viewer-app.h | 3 ++ > src/virt-viewer-session-spice.c | 63 ++++++++++++++++++----- > src/virt-viewer-window.c | 7 +++ > src/virt-viewer.c | 7 +++ > 5 files changed, 163 insertions(+), 28 deletions(-) > > diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c > index cdf6104..7962dc5 100644 > --- a/src/virt-viewer-app.c > +++ b/src/virt-viewer-app.c > @@ -108,6 +108,7 @@ struct _VirtViewerAppPrivate { > VirtViewerWindow *main_window; > GtkWidget *main_notebook; > GHashTable *windows; > + GArray *initial_display_map; > gchar *clipboard; > > gboolean direct; > @@ -273,6 +274,96 @@ virt_viewer_app_quit(VirtViewerApp *self) > gtk_main_quit(); > } > > +gint virt_viewer_app_get_n_initial_displays(VirtViewerApp* self) > +{ > + if (self->priv->initial_display_map) > + return self->priv->initial_display_map->len; > + > + 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; > + > + 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; > + } > + > + return monitor; > +} > + > +static void > +app_window_try_fullscreen(VirtViewerApp *self G_GNUC_UNUSED, > + VirtViewerWindow *win, gint nth) > +{ > + GdkScreen *screen = gdk_screen_get_default(); > + > + if (nth >= gdk_screen_get_n_monitors(screen)) { > + DEBUG_LOG("skipping display %d", nth); > + return; > + } > + > + virt_viewer_window_enter_fullscreen(win, nth); > +} > + > + > +void virt_viewer_app_set_uuid_string(VirtViewerApp* self, const gchar* > uuid_string) > +{ > + GArray* mapping = NULL; > + GError* error = NULL; > + gsize ndisplays = 0; > + gint* displays = NULL; > + gint nmonitors = gdk_screen_get_n_monitors(gdk_screen_get_default()); > + > + DEBUG_LOG("%s: UUID changed to %s", G_STRFUNC, uuid_string); > + > + displays = g_key_file_get_integer_list(self->priv->config, > + uuid_string, "monitor-mapping", > &ndisplays, &error); > + if (error) { > + if (error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) > + g_warning("Error reading monitor assignments: %s", > 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); > + } > + > + if (self->priv->initial_display_map) > + g_array_unref(self->priv->initial_display_map); > + > + self->priv->initial_display_map = mapping; > + > + // if we're changing our initial display map, move any existing windows > to > + // the appropriate monitors according to the per-vm configuration > + if (mapping && self->priv->fullscreen) { > + GHashTableIter iter; > + gpointer value; > + gint i = 0; > + > + g_hash_table_iter_init(&iter, self->priv->windows); > + while (g_hash_table_iter_next(&iter, NULL, &value)) { > + gint monitor = > virt_viewer_app_get_initial_monitor_for_display(self, i); > + app_window_try_fullscreen(self, VIRT_VIEWER_WINDOW(value), > monitor); > + i++; > + } > + } > +} > + > void > virt_viewer_app_maybe_quit(VirtViewerApp *self, VirtViewerWindow *window) > { > @@ -648,20 +739,6 @@ viewer_window_focus_out_cb(GtkWindow *window > G_GNUC_UNUSED, > return FALSE; > } > > -static void > -app_window_try_fullscreen(VirtViewerApp *self G_GNUC_UNUSED, > - VirtViewerWindow *win, gint nth) > -{ > - GdkScreen *screen = gdk_screen_get_default(); > - > - if (nth >= gdk_screen_get_n_monitors(screen)) { > - DEBUG_LOG("skipping display %d", nth); > - return; > - } > - > - virt_viewer_window_enter_fullscreen(win, nth); > -} > - > static VirtViewerWindow* > virt_viewer_app_window_new(VirtViewerApp *self, gint nth) > { > @@ -678,7 +755,8 @@ virt_viewer_app_window_new(VirtViewerApp *self, gint nth) > virt_viewer_window_set_zoom_level(window, > virt_viewer_window_get_zoom_level(self->priv->main_window)); > virt_viewer_app_set_nth_window(self, nth, window); > if (self->priv->fullscreen) > - app_window_try_fullscreen(self, window, nth); > + app_window_try_fullscreen(self, window, > + > virt_viewer_app_get_initial_monitor_for_display(self, > nth)); > > w = virt_viewer_window_get_window(window); > g_signal_connect(w, "hide", G_CALLBACK(viewer_window_visible_cb), self); > @@ -1445,6 +1523,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); > > virt_viewer_app_free_connect_info(self); > > @@ -1883,8 +1962,8 @@ static void fullscreen_cb(gpointer key, > gpointer value, > gpointer user_data) > { > - gint nth = *(gint*)key; > FullscreenOptions *options = (FullscreenOptions *)user_data; > + gint nth = virt_viewer_app_get_initial_monitor_for_display(options->app, > *(gint*)key); > VirtViewerWindow *vwin = VIRT_VIEWER_WINDOW(value); > > DEBUG_LOG("fullscreen display %d: %d", nth, options->fullscreen); > diff --git a/src/virt-viewer-app.h b/src/virt-viewer-app.h > index f72f5b3..737b0af 100644 > --- a/src/virt-viewer-app.h > +++ b/src/virt-viewer-app.h > @@ -100,6 +100,9 @@ gboolean virt_viewer_app_get_fullscreen(VirtViewerApp > *app); > gboolean virt_viewer_app_get_fullscreen_auto_conf(VirtViewerApp *app); > const GOptionEntry* virt_viewer_app_get_options(void); > void virt_viewer_app_clear_hotkeys(VirtViewerApp *app); > +gint virt_viewer_app_get_n_initial_displays(VirtViewerApp* self); > +gint virt_viewer_app_get_initial_monitor_for_display(VirtViewerApp* self, > gint display); > +void virt_viewer_app_set_uuid_string(VirtViewerApp* self, const gchar* > uuid_string); > > G_END_DECLS > > diff --git a/src/virt-viewer-session-spice.c > b/src/virt-viewer-session-spice.c > index b42d48e..41467cf 100644 > --- a/src/virt-viewer-session-spice.c > +++ b/src/virt-viewer-session-spice.c > @@ -28,6 +28,7 @@ > #include <glib/gi18n.h> > > #include <spice-option.h> > +#include <spice-util.h> > #include <usb-device-widget.h> > #include "virt-viewer-file.h" > #include "virt-viewer-util.h" > @@ -579,8 +580,6 @@ agent_connected_changed(SpiceChannel *cmain > G_GNUC_UNUSED, > { > // this will force refresh of application menu > g_signal_emit_by_name(self, "session-display-updated"); > - > - virt_viewer_session_spice_fullscreen_auto_conf(self); > } > > static void > @@ -677,7 +676,6 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, > self->priv->main_channel = SPICE_MAIN_CHANNEL(channel); > > g_signal_connect(channel, "notify::agent-connected", > G_CALLBACK(agent_connected_changed), self); > - virt_viewer_session_spice_fullscreen_auto_conf(self); > } > > if (SPICE_IS_DISPLAY_CHANNEL(channel)) { > @@ -709,6 +707,14 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, > self->priv->channel_count++; > } > > +static void > +property_notify_do_auto_conf(GObject *gobject G_GNUC_UNUSED, > + GParamSpec *pspec G_GNUC_UNUSED, > + VirtViewerSessionSpice *self) > +{ > + virt_viewer_session_spice_fullscreen_auto_conf(self); > +} > + > static gboolean > virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) > { > @@ -718,6 +724,7 @@ > virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) > GdkRectangle dest; > gboolean auto_conf, agent_connected; > gint i; > + gsize ndisplays = 0; > > app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)); > g_return_val_if_fail(VIRT_VIEWER_IS_APP(app), TRUE); > @@ -739,18 +746,23 @@ > virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) > g_object_get(cmain, "agent-connected", &agent_connected, NULL); > if (!agent_connected) { > DEBUG_LOG("Agent not connected, skipping autoconf"); > + g_signal_connect(cmain, "notify::agent-connected", > G_CALLBACK(property_notify_do_auto_conf), self); > return FALSE; > } > > - DEBUG_LOG("Performing full screen auto-conf, %d host monitors", > - gdk_screen_get_n_monitors(screen)); > + > g_object_set(G_OBJECT(cmain), > "disable-display-position", FALSE, > "disable-display-align", TRUE, > NULL); > spice_main_set_display_enabled(cmain, -1, FALSE); > - for (i = 0; i < gdk_screen_get_n_monitors(screen); i++) { > - gdk_screen_get_monitor_geometry(screen, i, &dest); > + > + ndisplays = virt_viewer_app_get_n_initial_displays(app); > + DEBUG_LOG("Performing full screen auto-conf, %zd host monitors", > ndisplays); > + > + for (i = 0; i < ndisplays; i++) { > + gint j = virt_viewer_app_get_initial_monitor_for_display(app, i); > + gdk_screen_get_monitor_geometry(screen, j, &dest); > DEBUG_LOG("Set SPICE display %d to (%d,%d)-(%dx%d)", > i, dest.x, dest.y, dest.width, dest.height); > spice_main_set_display(cmain, i, dest.x, dest.y, dest.width, > dest.height); > @@ -802,11 +814,34 @@ virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED > SpiceSession *s, > g_signal_emit_by_name(self, "session-disconnected"); > } > > +#define UUID_LEN 16 > static void > -fullscreen_changed(GObject *gobject G_GNUC_UNUSED, > - GParamSpec *pspec G_GNUC_UNUSED, > - VirtViewerSessionSpice *self) > -{ > +uuid_changed(GObject *gobject G_GNUC_UNUSED, > + GParamSpec *pspec G_GNUC_UNUSED, > + VirtViewerSessionSpice *self) > +{ > + guint8* uuid = NULL; > + VirtViewerApp* app = > virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)); > + > + g_object_get(self->priv->session, "uuid", &uuid, NULL); > + if (uuid) { > + int i; > + gboolean uuid_empty = TRUE; > + > + for (i = 0; i < UUID_LEN; i++) { > + if (uuid[i] != 0) { > + uuid_empty = FALSE; > + break; > + } > + } > + > + if (!uuid_empty) { > + gchar* uuid_str = spice_uuid_to_string(uuid); > + virt_viewer_app_set_uuid_string(app, uuid_str); > + g_free(uuid_str); > + } > + } > + > virt_viewer_session_spice_fullscreen_auto_conf(self); > } > > @@ -820,7 +855,11 @@ virt_viewer_session_spice_new(VirtViewerApp *app, > GtkWindow *main_window) > create_spice_session(self); > self->priv->main_window = g_object_ref(main_window); > > - g_signal_connect(app, "notify::fullscreen", > G_CALLBACK(fullscreen_changed), self); > + g_signal_connect(app, "notify::fullscreen", > G_CALLBACK(property_notify_do_auto_conf), self); > + > + /* notify::uuid is guaranteed to be emitted during connection startup > even > + * if the server is too old to support sending uuid */ > + g_signal_connect(self->priv->session, "notify::uuid", > G_CALLBACK(uuid_changed), self); > > return VIRT_VIEWER_SESSION(self); > } > diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c > index 5ce1d98..468e61c 100644 > --- a/src/virt-viewer-window.c > +++ b/src/virt-viewer-window.c > @@ -496,7 +496,9 @@ virt_viewer_window_leave_fullscreen(VirtViewerWindow > *self) > if (!priv->fullscreen) > return; > > + g_signal_handlers_block_by_func(check, > virt_viewer_window_menu_view_fullscreen, self); > gtk_check_menu_item_set_active(check, FALSE); > + g_signal_handlers_unblock_by_func(check, > virt_viewer_window_menu_view_fullscreen, self); Is this block/unblock addition related? a comment could help. could you make it a seperate fullscreen_menu_set_active() function instead? ack otherwise > priv->fullscreen = FALSE; > priv->fullscreen_monitor = -1; > if (priv->display) { > @@ -528,6 +530,9 @@ virt_viewer_window_enter_fullscreen(VirtViewerWindow > *self, gint monitor) > GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, > "top-menu")); > GtkCheckMenuItem *check = > GTK_CHECK_MENU_ITEM(gtk_builder_get_object(priv->builder, > "menu-view-fullscreen")); > > + if (priv->fullscreen && priv->fullscreen_monitor != monitor) > + virt_viewer_window_leave_fullscreen(self); > + > if (priv->fullscreen) > return; > > @@ -539,7 +544,9 @@ virt_viewer_window_enter_fullscreen(VirtViewerWindow > *self, gint monitor) > return; > } > > + g_signal_handlers_block_by_func(check, > virt_viewer_window_menu_view_fullscreen, self); > gtk_check_menu_item_set_active(check, TRUE); > + g_signal_handlers_unblock_by_func(check, > virt_viewer_window_menu_view_fullscreen, self); > gtk_widget_hide(menu); > gtk_widget_show(priv->toolbar); > ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(priv->layout), TRUE); > diff --git a/src/virt-viewer.c b/src/virt-viewer.c > index ae25fc6..e1553fd 100644 > --- a/src/virt-viewer.c > +++ b/src/virt-viewer.c > @@ -530,6 +530,7 @@ virt_viewer_initial_connect(VirtViewerApp *app, GError > **error) > gboolean ret = FALSE; > VirtViewer *self = VIRT_VIEWER(app); > VirtViewerPrivate *priv = self->priv; > + char uuid_string[VIR_UUID_STRING_BUFLEN]; > > DEBUG_LOG("initial connect"); > > @@ -555,6 +556,12 @@ virt_viewer_initial_connect(VirtViewerApp *app, GError > **error) > } > } > > + if (virDomainGetUUIDString(dom, uuid_string) < 0) { > + DEBUG_LOG("Couldn't get uuid from libvirt"); > + } else { > + virt_viewer_app_set_uuid_string(app, uuid_string); > + } > + > virt_viewer_app_show_status(app, _("Checking guest domain status")); > if (virDomainGetInfo(dom, &info) < 0) { > DEBUG_LOG("Cannot get guest state"); > -- > 1.8.3.1 > > _______________________________________________ > virt-tools-list mailing list > virt-tools-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/virt-tools-list > _______________________________________________ virt-tools-list mailing list virt-tools-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/virt-tools-list