Only when the agent is running may a display be enabled/disabled. --- src/virt-viewer-app.c | 28 ++++++++++++++++++++++++++- src/virt-viewer-display-spice.c | 40 ++++++++++++++++++++++++++++++++------- src/virt-viewer-display.c | 23 ++++++++++++++++++++++ src/virt-viewer-display.h | 2 ++ src/virt-viewer-session-spice.c | 18 ++++++++++++++---- src/virt-viewer-session.c | 10 ++++++++++ src/virt-viewer-session.h | 1 + src/virt-viewer-window.c | 13 +++++++++++-- src/virt-viewer-window.h | 1 + 9 files changed, 122 insertions(+), 14 deletions(-) diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c index f590641..def52c5 100644 --- a/src/virt-viewer-app.c +++ b/src/virt-viewer-app.c @@ -661,6 +661,7 @@ virt_viewer_app_display_added(VirtViewerSession *session G_GNUC_UNUSED, } virt_viewer_window_set_display(window, display); + virt_viewer_app_update_menu_displays(self); virt_viewer_signal_connect_object(display, "notify::show-hint", G_CALLBACK(display_show_hint), window, 0); g_object_notify(G_OBJECT(display), "show-hint"); /* call display_show_hint */ @@ -684,6 +685,13 @@ virt_viewer_app_display_removed(VirtViewerSession *session G_GNUC_UNUSED, virt_viewer_app_remove_nth_window(self, nth); } +static void +virt_viewer_app_display_updated(VirtViewerSession *session G_GNUC_UNUSED, + VirtViewerApp *self) +{ + virt_viewer_app_update_menu_displays(self); +} + int virt_viewer_app_create_session(VirtViewerApp *self, const gchar *type) { @@ -734,6 +742,8 @@ virt_viewer_app_create_session(VirtViewerApp *self, const gchar *type) G_CALLBACK(virt_viewer_app_display_added), self); g_signal_connect(priv->session, "session-display-removed", G_CALLBACK(virt_viewer_app_display_removed), self); + g_signal_connect(priv->session, "session-display-updated", + G_CALLBACK(virt_viewer_app_display_updated), self); g_signal_connect(priv->session, "session-cut-text", G_CALLBACK(virt_viewer_app_server_cut_text), self); @@ -1634,15 +1644,31 @@ window_update_menu_displays_cb(gpointer key G_GNUC_UNUSED, while (tmp) { int *nth = tmp->data; VirtViewerWindow *vwin = VIRT_VIEWER_WINDOW(g_hash_table_lookup(self->priv->windows, nth)); + VirtViewerDisplay *display = virt_viewer_window_get_display(vwin); GtkWidget *item; - gboolean visible; + gboolean visible, sensitive = FALSE; gchar *label; label = g_strdup_printf(_("Display %d"), *nth + 1); item = gtk_check_menu_item_new_with_label(label); g_free(label); + visible = gtk_widget_get_visible(GTK_WIDGET(virt_viewer_window_get_window(vwin))); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), visible); + + if (display) { + guint hint = virt_viewer_display_get_show_hint(display); + + if (hint & VIRT_VIEWER_DISPLAY_SHOW_HINT_READY) + sensitive = TRUE; + + if ((hint & VIRT_VIEWER_DISPLAY_SHOW_HINT_DISABLED) && + virt_viewer_display_get_selectable(display)) + sensitive = TRUE; + } + + gtk_widget_set_sensitive(item, sensitive); + g_signal_connect(G_OBJECT(item), "toggled", G_CALLBACK(menu_display_visible_toggled_cb), vwin); gtk_menu_shell_append(submenu, item); diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c index ca74c1a..a91d73e 100644 --- a/src/virt-viewer-display-spice.c +++ b/src/virt-viewer-display-spice.c @@ -47,6 +47,7 @@ static void virt_viewer_display_spice_send_keys(VirtViewerDisplay *display, static GdkPixbuf *virt_viewer_display_spice_get_pixbuf(VirtViewerDisplay *display); static void virt_viewer_display_spice_release_cursor(VirtViewerDisplay *display); static void virt_viewer_display_spice_close(VirtViewerDisplay *display G_GNUC_UNUSED); +static gboolean virt_viewer_display_spice_selectable(VirtViewerDisplay *display); static void virt_viewer_display_spice_finalize(GObject *obj) @@ -70,23 +71,36 @@ virt_viewer_display_spice_class_init(VirtViewerDisplaySpiceClass *klass) dclass->get_pixbuf = virt_viewer_display_spice_get_pixbuf; dclass->release_cursor = virt_viewer_display_spice_release_cursor; dclass->close = virt_viewer_display_spice_close; + dclass->selectable = virt_viewer_display_spice_selectable; g_type_class_add_private(klass, sizeof(VirtViewerDisplaySpicePrivate)); } +static SpiceMainChannel* +get_main(VirtViewerDisplay *self) +{ + VirtViewerSessionSpice *session; + + session = VIRT_VIEWER_SESSION_SPICE(virt_viewer_display_get_session(self)); + + return virt_viewer_session_spice_get_main_channel(session); +} + static void show_hint_changed(VirtViewerDisplay *self) { - SpiceMainChannel *main_channel = virt_viewer_session_spice_get_main_channel( - VIRT_VIEWER_SESSION_SPICE(virt_viewer_display_get_session(self))); + SpiceMainChannel *cmain = get_main(self); guint enabled = TRUE; guint nth; + if (!cmain) + return; + g_object_get(self, "nth-display", &nth, NULL); if (virt_viewer_display_get_show_hint(self) & VIRT_VIEWER_DISPLAY_SHOW_HINT_DISABLED) enabled = FALSE; - spice_main_set_display_enabled(main_channel, nth, enabled); + spice_main_set_display_enabled(cmain, nth, enabled); } static void @@ -189,9 +203,8 @@ virt_viewer_display_spice_size_allocate(VirtViewerDisplaySpice *self, 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, nth, 0, 0, dw, dh); + spice_main_set_display(get_main(VIRT_VIEWER_DISPLAY(self)), + nth, 0, 0, dw, dh); } static void @@ -270,12 +283,25 @@ virt_viewer_display_spice_release_cursor(VirtViewerDisplay *display) spice_display_mouse_ungrab(self->priv->display); } - static void virt_viewer_display_spice_close(VirtViewerDisplay *display G_GNUC_UNUSED) { } +static gboolean +virt_viewer_display_spice_selectable(VirtViewerDisplay *self) +{ + gboolean agent_connected; + SpiceMainChannel *mainc; + + mainc = get_main(self); + g_object_get(mainc, + "agent-connected", &agent_connected, + NULL); + + return agent_connected; +} + /* * Local variables: diff --git a/src/virt-viewer-display.c b/src/virt-viewer-display.c index 004f027..4612970 100644 --- a/src/virt-viewer-display.c +++ b/src/virt-viewer-display.c @@ -80,6 +80,7 @@ enum { PROP_ZOOM_LEVEL, PROP_SHOW_HINT, PROP_SESSION, + PROP_SELECTABLE, }; static void @@ -167,6 +168,13 @@ virt_viewer_display_class_init(VirtViewerDisplayClass *class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property(object_class, + PROP_SELECTABLE, + g_param_spec_boolean("selectable", + "Selectable", + "Selectable", + FALSE, + G_PARAM_READABLE)); g_signal_new("display-pointer-grab", G_OBJECT_CLASS_TYPE(object_class), @@ -302,6 +310,9 @@ virt_viewer_display_get_property(GObject *object, case PROP_SESSION: g_value_set_object(value, virt_viewer_display_get_session(display)); break; + case PROP_SELECTABLE: + g_value_set_boolean(value, virt_viewer_display_get_selectable(display)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -601,6 +612,18 @@ void virt_viewer_display_release_cursor(VirtViewerDisplay *self) klass->release_cursor(self); } +gboolean virt_viewer_display_get_selectable(VirtViewerDisplay *self) +{ + VirtViewerDisplayClass *klass; + + g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE); + + klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self); + if (klass->selectable) + return klass->selectable(self); + + return FALSE; +} void virt_viewer_display_close(VirtViewerDisplay *self) { diff --git a/src/virt-viewer-display.h b/src/virt-viewer-display.h index 89b4817..4247570 100644 --- a/src/virt-viewer-display.h +++ b/src/virt-viewer-display.h @@ -77,6 +77,7 @@ struct _VirtViewerDisplayClass { void (*release_cursor)(VirtViewerDisplay *display); void (*close)(VirtViewerDisplay *display); + gboolean (*selectable)(VirtViewerDisplay *display); /* signals */ void (*display_pointer_grab)(VirtViewerDisplay *display); @@ -118,6 +119,7 @@ void virt_viewer_display_release_cursor(VirtViewerDisplay *display); void virt_viewer_display_close(VirtViewerDisplay *display); void virt_viewer_display_set_enabled(VirtViewerDisplay *display, gboolean enabled); +gboolean virt_viewer_display_get_selectable(VirtViewerDisplay *display); G_END_DECLS diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c index 0df11ef..6e9c03d 100644 --- a/src/virt-viewer-session-spice.c +++ b/src/virt-viewer-session-spice.c @@ -405,12 +405,21 @@ virt_viewer_session_spice_usb_device_selection(VirtViewerSession *session, } static void -agent_connected_changed(SpiceChannel *cmain, +agent_connected_changed(SpiceChannel *cmain G_GNUC_UNUSED, GParamSpec *pspec G_GNUC_UNUSED, VirtViewerSessionSpice *self) { + // this will force refresh of application menu + g_signal_emit_by_name(self, "session-display-updated"); +} + +static void +agent_connected_fullscreen_auto_conf(SpiceChannel *cmain, + GParamSpec *pspec G_GNUC_UNUSED, + VirtViewerSessionSpice *self) +{ if (virt_viewer_session_spice_fullscreen_auto_conf(self)) - g_signal_handlers_disconnect_by_func(cmain, agent_connected_changed, self); + g_signal_handlers_disconnect_by_func(cmain, agent_connected_fullscreen_auto_conf, self); } static void @@ -513,8 +522,9 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, G_CALLBACK(virt_viewer_session_spice_main_channel_event), self); self->priv->main_channel = SPICE_MAIN_CHANNEL(channel); - g_signal_connect(channel, "notify::agent-connected", G_CALLBACK(agent_connected_changed), self); - agent_connected_changed(channel, NULL, self); + g_signal_connect(channel, "notify::agent-connected", G_CALLBACK(agent_connected_changed), self); + g_signal_connect(channel, "notify::agent-connected", G_CALLBACK(agent_connected_fullscreen_auto_conf), self); + agent_connected_fullscreen_auto_conf(channel, NULL, self); g_signal_emit_by_name(session, "session-connected"); } diff --git a/src/virt-viewer-session.c b/src/virt-viewer-session.c index 9249a1f..a1d96c2 100644 --- a/src/virt-viewer-session.c +++ b/src/virt-viewer-session.c @@ -233,6 +233,16 @@ virt_viewer_session_class_init(VirtViewerSessionClass *class) 1, VIRT_VIEWER_TYPE_DISPLAY); + g_signal_new("session-display-updated", + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET(VirtViewerSessionClass, session_display_updated), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + g_signal_new("session-cut-text", G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS, diff --git a/src/virt-viewer-session.h b/src/virt-viewer-session.h index 44e4674..38ed988 100644 --- a/src/virt-viewer-session.h +++ b/src/virt-viewer-session.h @@ -88,6 +88,7 @@ struct _VirtViewerSessionClass { VirtViewerDisplay *display); void (*session_display_removed)(VirtViewerSession *session, VirtViewerDisplay *display); + void (*session_display_updated)(VirtViewerSession *session); void (*session_cut_text)(VirtViewerSession *session, const gchar *str); void (*session_bell)(VirtViewerSession *session); diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c index 46e44be..4bc427a 100644 --- a/src/virt-viewer-window.c +++ b/src/virt-viewer-window.c @@ -112,7 +112,8 @@ static void virt_viewer_window_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - VirtViewerWindowPrivate *priv = VIRT_VIEWER_WINDOW(object)->priv; + VirtViewerWindow *self = VIRT_VIEWER_WINDOW(object); + VirtViewerWindowPrivate *priv = self->priv; switch (property_id) { case PROP_SUBTITLE: @@ -124,7 +125,7 @@ virt_viewer_window_get_property (GObject *object, guint property_id, break; case PROP_DISPLAY: - g_value_set_object(value, priv->display); + g_value_set_object(value, virt_viewer_window_get_display(self)); break; case PROP_CONTAINER: @@ -1117,6 +1118,14 @@ virt_viewer_window_get_builder(VirtViewerWindow *self) return self->priv->builder; } +VirtViewerDisplay* +virt_viewer_window_get_display(VirtViewerWindow *self) +{ + g_return_val_if_fail(VIRT_VIEWER_WINDOW(self), FALSE); + + return self->priv->display; +} + /* * Local variables: * c-indent-level: 4 diff --git a/src/virt-viewer-window.h b/src/virt-viewer-window.h index f80c4c7..44db585 100644 --- a/src/virt-viewer-window.h +++ b/src/virt-viewer-window.h @@ -63,6 +63,7 @@ GType virt_viewer_window_get_type (void); GtkWindow* virt_viewer_window_get_window (VirtViewerWindow* window); VirtViewerNotebook* virt_viewer_window_get_notebook (VirtViewerWindow* window); void virt_viewer_window_set_display(VirtViewerWindow *self, VirtViewerDisplay *display); +VirtViewerDisplay* virt_viewer_window_get_display(VirtViewerWindow *self); void virt_viewer_window_set_usb_options_sensitive(VirtViewerWindow *self, gboolean sensitive); void virt_viewer_window_update_title(VirtViewerWindow *self); void virt_viewer_window_show(VirtViewerWindow *self); -- 1.7.10.4