----- 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. Looks good, > --- > src/virt-viewer-app.c | 101 > ++++++++++++++++++++++++++++++++++++---- > src/virt-viewer-app.h | 3 ++ > src/virt-viewer-session-spice.c | 41 +++++++++++++--- > src/virt-viewer-window.c | 9 +++- > src/virt-viewer.c | 7 +++ > 5 files changed, 144 insertions(+), 17 deletions(-) > > diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c > index d071568..da25863 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; > @@ -271,6 +272,82 @@ 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; > +} > + > + > +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); > + virt_viewer_window_enter_fullscreen(VIRT_VIEWER_WINDOW(value), > monitor); > + i++; > + } You couldn't call app_window_try_fullscreen() ? It could be nice if the virt_viewer_app_get_initial_monitor_for_display() could be done there, in one place. > + } > +} > + > void > virt_viewer_app_maybe_quit(VirtViewerApp *self, VirtViewerWindow *window) > { > @@ -674,7 +751,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); > @@ -745,6 +823,7 @@ virt_viewer_app_display_added(VirtViewerSession *session > G_GNUC_UNUSED, > } > > window = virt_viewer_app_window_new(self, nth); > + > } > } > > @@ -1283,19 +1362,20 @@ virt_viewer_app_set_kiosk(VirtViewerApp *self, > gboolean enabled) > int i; > > self->priv->kiosk = enabled; > - if (enabled) > + if (enabled) { What was the reason for this change? We wanted to disable kiosk mode, now that won't update window kiosk state. > virt_viewer_app_set_fullscreen(self, enabled); > > - for (i = 0; i < gdk_screen_get_n_monitors(gdk_screen_get_default()); > i++) { > - VirtViewerWindow *win = virt_viewer_app_get_nth_window(self, i); > + for (i = 0; i < gdk_screen_get_n_monitors(gdk_screen_get_default()); > i++) { > + VirtViewerWindow *win = virt_viewer_app_get_nth_window(self, i); > > - if (win == NULL) > - win = virt_viewer_app_window_new(self, i); > + if (win == NULL) > + win = virt_viewer_app_window_new(self, i); > > - if (enabled) > - virt_viewer_window_show(win); > + if (enabled) > + virt_viewer_window_show(win); > > - virt_viewer_window_set_kiosk(win, enabled); > + virt_viewer_window_set_kiosk(win, enabled); > + } > } > } > > @@ -1433,6 +1513,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); > > @@ -1854,8 +1935,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 4721fe3..6c9443a 100644 > --- a/src/virt-viewer-app.h > +++ b/src/virt-viewer-app.h > @@ -99,6 +99,9 @@ VirtViewerSession* > virt_viewer_app_get_session(VirtViewerApp *self); > 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); > +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 4ed4aff..229d01e 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" > @@ -51,6 +52,7 @@ struct _VirtViewerSessionSpicePrivate { > SpiceMainChannel *main_channel; > const SpiceAudio *audio; > int channel_count; > + int display_channel_count; > int usbredir_channel_count; > gboolean has_sw_smartcard_reader; > guint pass_try; > @@ -677,10 +679,11 @@ 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)) { > + self->priv->display_channel_count++; > + virt_viewer_session_spice_fullscreen_auto_conf(self); > g_signal_emit_by_name(session, "session-initialized"); > > g_signal_connect(channel, "notify::monitors", > @@ -717,7 +720,8 @@ > virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) > VirtViewerApp *app = NULL; > GdkRectangle dest; > gboolean agent_connected; > - gint i; > + gint i, j; > + gsize ndisplays = 0; > > app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)); > g_return_val_if_fail(VIRT_VIEWER_IS_APP(app), TRUE); > @@ -730,21 +734,28 @@ > virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) > DEBUG_LOG("no main channel yet"); > return FALSE; > } > + if (self->priv->display_channel_count == 0) { Is this related? Why is it needed? > + DEBUG_LOG("no display channel yet"); > + return FALSE; > + } > g_object_get(cmain, "agent-connected", &agent_connected, NULL); > if (!agent_connected) { > DEBUG_LOG("Agent not connected, skipping autoconf"); > 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++) { > + 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); > @@ -777,6 +788,7 @@ virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED > SpiceSession *s, > if (SPICE_IS_DISPLAY_CHANNEL(channel)) { > VirtViewerDisplay *display = g_object_get_data(G_OBJECT(channel), > "virt-viewer-display"); > DEBUG_LOG("zap display channel (#%d, %p)", id, display); > + self->priv->display_channel_count--; > } > > if (SPICE_IS_PLAYBACK_CHANNEL(channel) && self->priv->audio) { > @@ -804,6 +816,22 @@ fullscreen_changed(GObject *gobject G_GNUC_UNUSED, > virt_viewer_session_spice_fullscreen_auto_conf(self); > } > > +static void > +uuid_changed(GObject *gobject G_GNUC_UNUSED, > + GParamSpec *pspec G_GNUC_UNUSED, > + VirtViewerSessionSpice *self) > +{ > + guint8* uuid = NULL; > + gchar* uuid_str = NULL; > + VirtViewerApp* app = > virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)); > + > + g_object_get(self->priv->session, "uuid", &uuid, NULL); > + uuid_str = spice_uuid_to_string(uuid); > + virt_viewer_app_set_uuid_string(app, uuid_str); > + g_free(uuid_str); > + > +} > + > VirtViewerSession * > virt_viewer_session_spice_new(VirtViewerApp *app, GtkWindow *main_window) > { > @@ -815,6 +843,7 @@ virt_viewer_session_spice_new(VirtViewerApp *app, > GtkWindow *main_window) > self->priv->main_window = g_object_ref(main_window); > > g_signal_connect(app, "notify::fullscreen", > G_CALLBACK(fullscreen_changed), self); > + 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..ac2ec3e 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); > priv->fullscreen = FALSE; > priv->fullscreen_monitor = -1; > if (priv->display) { > @@ -528,18 +530,23 @@ 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; > > - priv->fullscreen_monitor = monitor; > priv->fullscreen = TRUE; > + priv->fullscreen_monitor = monitor; > > if (!gtk_widget_get_mapped(priv->window)) { > g_signal_connect(priv->window, "map-event", G_CALLBACK(mapped), > self); > 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