Rely on spice-gtk display channel monitors property to manage displays. The same display channel may now provide several monitors, the SpiceDisplay widget must be told which monitor to display --- src/virt-viewer-display-spice.c | 20 +++++---- src/virt-viewer-display-spice.h | 2 +- src/virt-viewer-session-spice.c | 89 ++++++++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 19 deletions(-) diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c index 53430dd..d06e5cf 100644 --- a/src/virt-viewer-display-spice.c +++ b/src/virt-viewer-display-spice.c @@ -172,7 +172,7 @@ virt_viewer_display_spice_size_allocate(VirtViewerDisplaySpice *self, { gdouble dw = allocation->width, dh = allocation->height; guint zoom = 100; - guint channelid; + guint nth; if (virt_viewer_display_get_auto_resize(VIRT_VIEWER_DISPLAY(self)) == FALSE) return; @@ -187,13 +187,11 @@ virt_viewer_display_spice_size_allocate(VirtViewerDisplaySpice *self, dh /= ((double)zoom / 100.0); } - g_object_get(self->priv->channel, "channel-id", &channelid, NULL); + g_object_get(self, "nth-display", &nth, NULL); SpiceMainChannel *main_channel = virt_viewer_session_spice_get_main_channel( VIRT_VIEWER_SESSION_SPICE(virt_viewer_display_get_session(VIRT_VIEWER_DISPLAY(self)))); - spice_main_set_display(main_channel, - channelid, - 0, 0, dw, dh); + spice_main_set_display(main_channel, nth, 0, 0, dw, dh); } static void @@ -212,7 +210,8 @@ enable_accel_changed(VirtViewerApp *app, GtkWidget * virt_viewer_display_spice_new(VirtViewerSessionSpice *session, - SpiceChannel *channel) + SpiceChannel *channel, + gint monitorid) { VirtViewerDisplaySpice *self; VirtViewerApp *app; @@ -222,15 +221,20 @@ virt_viewer_display_spice_new(VirtViewerSessionSpice *session, g_return_val_if_fail(SPICE_IS_DISPLAY_CHANNEL(channel), NULL); g_object_get(channel, "channel-id", &channelid, NULL); + // We don't allow monitorid != 0 && channelid != 0 + g_return_val_if_fail(channelid == 0 || monitorid == 0, NULL); self = g_object_new(VIRT_VIEWER_TYPE_DISPLAY_SPICE, "session", session, - "nth-display", channelid, + // either monitorid is always 0 or channelid + // is, we can't have display (0, 2) and (2, 0) + // for example + "nth-display", channelid + monitorid, NULL); self->priv->channel = channel; g_object_get(session, "spice-session", &s, NULL); - self->priv->display = spice_display_new(s, channelid); + self->priv->display = spice_display_new_with_monitor(s, channelid, monitorid); g_object_unref(s); virt_viewer_signal_connect_object(self->priv->display, "notify::ready", diff --git a/src/virt-viewer-display-spice.h b/src/virt-viewer-display-spice.h index 701ed85..c2013ec 100644 --- a/src/virt-viewer-display-spice.h +++ b/src/virt-viewer-display-spice.h @@ -66,7 +66,7 @@ struct _VirtViewerDisplaySpiceClass { GType virt_viewer_display_spice_get_type(void); -GtkWidget* virt_viewer_display_spice_new(VirtViewerSessionSpice *session, SpiceChannel *channel); +GtkWidget* virt_viewer_display_spice_new(VirtViewerSessionSpice *session, SpiceChannel *channel, gint monitorid); G_END_DECLS diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c index 6577237..a728cb1 100644 --- a/src/virt-viewer-session-spice.c +++ b/src/virt-viewer-session-spice.c @@ -33,6 +33,7 @@ #include "virt-viewer-session-spice.h" #include "virt-viewer-display-spice.h" #include "virt-viewer-auth.h" +#include "virt-glib-compat.h" #if !GLIB_CHECK_VERSION(2, 26, 0) #include "gbinding.h" @@ -414,6 +415,78 @@ agent_connected_changed(SpiceChannel *cmain, } static void +destroy_display(gpointer data) +{ + VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(data); + VirtViewerSession *session = virt_viewer_display_get_session(display); + + DEBUG_LOG("Destroying spice display %p", display); + virt_viewer_session_remove_display(session, display); + g_object_unref(display); +} + +static void +virt_viewer_session_spice_display_monitors(SpiceChannel *channel, + GParamSpec *pspec G_GNUC_UNUSED, + VirtViewerSessionSpice *self) +{ + GArray *monitors = NULL; + GPtrArray *displays = NULL; + GtkWidget *display; + guint i, monitors_max; + + g_object_get(channel, + "monitors", &monitors, + "monitors-max", &monitors_max, + NULL); + g_return_if_fail(monitors != NULL); + g_return_if_fail(monitors->len <= monitors_max); + + displays = g_object_get_data(G_OBJECT(channel), "virt-viewer-displays"); + if (displays == NULL) { + displays = g_ptr_array_new(); + g_ptr_array_set_free_func(displays, destroy_display); + g_object_set_data_full(G_OBJECT(channel), "virt-viewer-displays", + displays, (GDestroyNotify)g_ptr_array_unref); + } + + g_ptr_array_set_size(displays, monitors_max); + + for (i = 0; i < monitors_max; i++) { + display = g_ptr_array_index(displays, i); + if (display == NULL) { + display = virt_viewer_display_spice_new(self, channel, i); + DEBUG_LOG("creating spice display (#:%d)", i); + g_ptr_array_index(displays, i) = g_object_ref(display); + } + + g_object_freeze_notify(G_OBJECT(display)); + virt_viewer_display_set_enabled(VIRT_VIEWER_DISPLAY(display), FALSE); + virt_viewer_session_add_display(VIRT_VIEWER_SESSION(self), + VIRT_VIEWER_DISPLAY(display)); + } + + for (i = 0; i < monitors->len; i++) { + SpiceDisplayMonitorConfig *monitor = &g_array_index(monitors, SpiceDisplayMonitorConfig, i); + display = g_ptr_array_index(displays, monitor->id); + g_return_if_fail(display != NULL); + + if (monitor->width == 0 || monitor->width == 0) + continue; + + virt_viewer_display_set_enabled(VIRT_VIEWER_DISPLAY(display), TRUE); + virt_viewer_display_set_desktop_size(VIRT_VIEWER_DISPLAY(display), + monitor->width, monitor->height); + } + + for (i = 0; i < monitors_max; i++) + g_object_thaw_notify(g_ptr_array_index(displays, i)); + + g_clear_pointer(&monitors, g_array_unref); + +} + +static void virt_viewer_session_spice_channel_new(SpiceSession *s, SpiceChannel *channel, VirtViewerSession *session) @@ -441,20 +514,17 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, g_signal_connect(channel, "notify::agent-connected", G_CALLBACK(agent_connected_changed), self); agent_connected_changed(channel, NULL, self); + + g_signal_emit_by_name(session, "session-connected"); } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { - GtkWidget *display; - - g_signal_emit_by_name(session, "session-connected"); + g_signal_emit_by_name(session, "session-initialized"); - DEBUG_LOG("new display channel (#%d)", id); - display = virt_viewer_display_spice_new(self, channel); - g_object_set_data(G_OBJECT(channel), "virt-viewer-display", display); - virt_viewer_session_add_display(VIRT_VIEWER_SESSION(session), - VIRT_VIEWER_DISPLAY(display)); + g_signal_connect(channel, "notify::monitors", + G_CALLBACK(virt_viewer_session_spice_display_monitors), self); - g_signal_emit_by_name(session, "session-initialized"); + spice_channel_connect(channel); } if (SPICE_IS_INPUTS_CHANNEL(channel)) { @@ -538,7 +608,6 @@ 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); - virt_viewer_session_remove_display(session, display); } if (SPICE_IS_PLAYBACK_CHANNEL(channel) && self->priv->audio) { -- 1.7.10.4