--- src/remote-viewer-main.c | 32 +++++++++++++++++-- src/virt-viewer-app.c | 30 +++++++++++++++--- src/virt-viewer-session-spice.c | 62 +++++++++++++++++++++++++++++++++++++- src/virt-viewer-session-spice.h | 2 +- src/virt-viewer-session.c | 30 ++++++++++++++++++- src/virt-viewer-session.h | 2 + src/virt-viewer-window.c | 18 ++++++----- 7 files changed, 155 insertions(+), 21 deletions(-) diff --git a/src/remote-viewer-main.c b/src/remote-viewer-main.c index 6d26605..d857e45 100644 --- a/src/remote-viewer-main.c +++ b/src/remote-viewer-main.c @@ -43,6 +43,28 @@ remote_viewer_version(void) exit(EXIT_SUCCESS); } +gboolean fullscreen = FALSE; +gboolean fullscreen_auto_conf = FALSE; + +static gboolean +option_fullscreen(G_GNUC_UNUSED const gchar *option_name, + const gchar *value, + G_GNUC_UNUSED gpointer data, GError **error) +{ + fullscreen = TRUE; + + if (value == NULL) + return TRUE; + + if (g_str_equal(value, "auto-conf")) { + fullscreen_auto_conf = TRUE; + return TRUE; + } + + g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, _("Invalid full-screen argument: %s"), value); + return FALSE; +} + int main(int argc, char **argv) { @@ -54,7 +76,6 @@ main(int argc, char **argv) gboolean verbose = FALSE; gboolean debug = FALSE; gboolean direct = FALSE; - gboolean fullscreen = FALSE; RemoteViewer *viewer = NULL; #if HAVE_SPICE_GTK gboolean controller = FALSE; @@ -72,8 +93,8 @@ main(int argc, char **argv) N_("Zoom level of window, in percentage"), "ZOOM" }, { "debug", '\0', 0, G_OPTION_ARG_NONE, &debug, N_("Display debugging information"), NULL }, - { "full-screen", 'f', 0, G_OPTION_ARG_NONE, &fullscreen, - N_("Open in full screen mode"), NULL }, + { "full-screen", 'f', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, option_fullscreen, + N_("Open in full screen mode (=<auto-conf>)"), NULL }, #if HAVE_SPICE_GTK { "spice-controller", '\0', 0, G_OPTION_ARG_NONE, &controller, N_("Open connection using Spice controller communication"), NULL }, @@ -144,7 +165,10 @@ main(int argc, char **argv) goto cleanup; app = VIRT_VIEWER_APP(viewer); - g_object_set(app, "fullscreen", fullscreen, NULL); + g_object_set(app, + "fullscreen", fullscreen, + "fullscreen-auto-conf", fullscreen_auto_conf, + NULL); virt_viewer_window_set_zoom_level(virt_viewer_app_get_main_window(app), zoom); virt_viewer_app_set_direct(app, direct); diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c index e30df85..9cffedb 100644 --- a/src/virt-viewer-app.c +++ b/src/virt-viewer-app.c @@ -116,6 +116,7 @@ struct _VirtViewerAppPrivate { gboolean authretry; gboolean started; gboolean fullscreen; + gboolean fullscreen_auto_conf; gboolean attach; gboolean quiting; @@ -157,6 +158,7 @@ enum { PROP_TITLE, PROP_ENABLE_ACCEL, PROP_HAS_FOCUS, + PROP_FULLSCREEN_AUTO_CONF, }; enum { @@ -684,7 +686,7 @@ virt_viewer_app_create_session(VirtViewerApp *self, const gchar *type) GtkWindow *window = virt_viewer_window_get_window(priv->main_window); virt_viewer_app_trace(self, "Guest %s has a %s display\n", priv->guest_name, type); - priv->session = virt_viewer_session_spice_new(window); + priv->session = virt_viewer_session_spice_new(self, window); } else #endif { @@ -1170,6 +1172,10 @@ virt_viewer_app_get_property (GObject *object, guint property_id, g_value_set_boolean(value, priv->focused > 0); break; + case PROP_FULLSCREEN_AUTO_CONF: + g_value_set_boolean(value, priv->fullscreen_auto_conf); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -1218,6 +1224,10 @@ virt_viewer_app_set_property (GObject *object, guint property_id, priv->enable_accel = g_value_get_boolean(value); break; + case PROP_FULLSCREEN_AUTO_CONF: + priv->fullscreen_auto_conf = g_value_get_boolean(value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -1377,8 +1387,16 @@ virt_viewer_app_class_init (VirtViewerAppClass *klass) "Fullscreen", "Fullscreen", FALSE, - G_PARAM_READABLE | - G_PARAM_WRITABLE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_FULLSCREEN_AUTO_CONF, + g_param_spec_boolean("fullscreen-auto-conf", + "auto conf", + "Automatic display configuration in full screen", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, @@ -1503,7 +1521,7 @@ static void fullscreen_cb(gpointer key, DEBUG_LOG("fullscreen display %d: %d", nth, options->fullscreen); if (options->fullscreen) { - GdkScreen *screen = gdk_screen_get_default (); + GdkScreen *screen = gdk_screen_get_default(); GdkRectangle mon; if (nth >= gdk_screen_get_n_monitors(screen)) { @@ -1522,12 +1540,14 @@ virt_viewer_app_set_fullscreen(VirtViewerApp *self, gboolean fullscreen) VirtViewerAppPrivate *priv = self->priv; FullscreenOptions options = { .fullscreen = fullscreen, - .move = virt_viewer_app_get_n_windows_visible(self) > 1, + .move = virt_viewer_app_get_n_windows_visible(self) > 1 || self->priv->fullscreen_auto_conf, }; /* we iterate unconditionnaly, even if it was set before to update new windows */ priv->fullscreen = fullscreen; g_hash_table_foreach(priv->windows, fullscreen_cb, &options); + + g_object_notify(G_OBJECT(self), "fullscreen"); } static void diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c index a4b3a1f..7d14db4 100644 --- a/src/virt-viewer-session-spice.c +++ b/src/virt-viewer-session-spice.c @@ -74,6 +74,7 @@ static void virt_viewer_session_spice_channel_destroy(SpiceSession *s, VirtViewerSession *session); static void virt_viewer_session_spice_smartcard_insert(VirtViewerSession *session); static void virt_viewer_session_spice_smartcard_remove(VirtViewerSession *session); +static gboolean virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self); static void virt_viewer_session_spice_get_property(GObject *object, guint property_id, @@ -394,6 +395,15 @@ virt_viewer_session_spice_usb_device_selection(VirtViewerSession *session, } static void +agent_connected_changed(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); +} + +static void virt_viewer_session_spice_channel_new(SpiceSession *s, SpiceChannel *channel, VirtViewerSession *session) @@ -416,6 +426,9 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, g_signal_connect(channel, "channel-event", 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); } if (SPICE_IS_DISPLAY_CHANNEL(channel)) { @@ -447,6 +460,41 @@ virt_viewer_session_spice_channel_new(SpiceSession *s, self->priv->channel_count++; } +static gboolean +virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) +{ + GdkScreen *screen = gdk_screen_get_default(); + SpiceMainChannel* cmain = virt_viewer_session_spice_get_main_channel(self); + VirtViewerApp *app = NULL; + GdkRectangle dest; + gboolean auto_conf, agent_connected; + gint i; + + app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)); + g_return_val_if_fail(VIRT_VIEWER_IS_APP(app), TRUE); + + g_object_get(app, "fullscreen-auto-conf", &auto_conf, NULL); + if (!auto_conf) + return TRUE; + + if (cmain == NULL) + return FALSE; + + g_object_get(cmain, "agent-connected", &agent_connected, NULL); + if (!agent_connected) + return FALSE; + + 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); + spice_main_set_display(cmain, i, dest.x, dest.y, dest.width, dest.height); + spice_main_set_display_enabled(cmain, i, TRUE); + } + + spice_main_send_monitor_config(cmain); + return TRUE; +} + static void virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s, SpiceChannel *channel, @@ -479,16 +527,26 @@ virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s, g_signal_emit_by_name(self, "session-disconnected"); } +static void +fullscreen_changed(GObject *gobject G_GNUC_UNUSED, + GParamSpec *pspec G_GNUC_UNUSED, + VirtViewerSessionSpice *self) +{ + virt_viewer_session_spice_fullscreen_auto_conf(self); +} + VirtViewerSession * -virt_viewer_session_spice_new(GtkWindow *main_window) +virt_viewer_session_spice_new(VirtViewerApp *app, GtkWindow *main_window) { VirtViewerSessionSpice *self; - self = g_object_new(VIRT_VIEWER_TYPE_SESSION_SPICE, NULL); + self = g_object_new(VIRT_VIEWER_TYPE_SESSION_SPICE, "app", app, NULL); create_spice_session(self); self->priv->main_window = g_object_ref(main_window); + g_signal_connect(app, "notify::fullscreen", G_CALLBACK(fullscreen_changed), self); + return VIRT_VIEWER_SESSION(self); } diff --git a/src/virt-viewer-session-spice.h b/src/virt-viewer-session-spice.h index f0d7e89..95bdcdf 100644 --- a/src/virt-viewer-session-spice.h +++ b/src/virt-viewer-session-spice.h @@ -65,7 +65,7 @@ struct _VirtViewerSessionSpiceClass { GType virt_viewer_session_spice_get_type(void); -VirtViewerSession* virt_viewer_session_spice_new(GtkWindow *main_window); +VirtViewerSession* virt_viewer_session_spice_new(VirtViewerApp *app, GtkWindow *main_window); SpiceMainChannel* virt_viewer_session_spice_get_main_channel(VirtViewerSessionSpice *self); G_END_DECLS diff --git a/src/virt-viewer-session.c b/src/virt-viewer-session.c index c0d6e65..f139c48 100644 --- a/src/virt-viewer-session.c +++ b/src/virt-viewer-session.c @@ -35,7 +35,7 @@ struct _VirtViewerSessionPrivate { GList *displays; - + VirtViewerApp *app; gboolean auto_usbredir; }; @@ -44,6 +44,7 @@ G_DEFINE_ABSTRACT_TYPE(VirtViewerSession, virt_viewer_session, G_TYPE_OBJECT) enum { PROP_0, + PROP_APP, PROP_AUTO_USBREDIR, }; @@ -74,6 +75,11 @@ virt_viewer_session_set_property(GObject *object, case PROP_AUTO_USBREDIR: virt_viewer_session_set_auto_usbredir(self, g_value_get_boolean(value)); break; + + case PROP_APP: + self->priv->app = g_value_get_object(value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -92,6 +98,11 @@ virt_viewer_session_get_property(GObject *object, case PROP_AUTO_USBREDIR: g_value_set_boolean(value, virt_viewer_session_get_auto_usbredir(self)); break; + + case PROP_APP: + g_value_set_object(value, self->priv->app); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -117,6 +128,16 @@ virt_viewer_session_class_init(VirtViewerSessionClass *class) G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(object_class, + PROP_APP, + g_param_spec_object("app", + "VirtViewerApp", + "VirtViewerApp", + VIRT_VIEWER_TYPE_APP, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + g_signal_new("session-connected", G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_FIRST, @@ -408,6 +429,13 @@ void virt_viewer_session_smartcard_remove(VirtViewerSession *self) klass->smartcard_remove(self); } +VirtViewerApp* virt_viewer_session_get_app(VirtViewerSession *self) +{ + g_return_val_if_fail(VIRT_VIEWER_IS_SESSION(self), NULL); + + return self->priv->app; +} + /* * Local variables: * c-indent-level: 4 diff --git a/src/virt-viewer-session.h b/src/virt-viewer-session.h index c20f23d..c53c8b5 100644 --- a/src/virt-viewer-session.h +++ b/src/virt-viewer-session.h @@ -26,6 +26,7 @@ #include <gtk/gtk.h> +#include "virt-viewer-app.h" #include "virt-viewer-display.h" G_BEGIN_DECLS @@ -118,6 +119,7 @@ gboolean virt_viewer_session_has_usb(VirtViewerSession *self); void virt_viewer_session_usb_device_selection(VirtViewerSession *self, GtkWindow *parent); void virt_viewer_session_smartcard_insert(VirtViewerSession *self); void virt_viewer_session_smartcard_remove(VirtViewerSession *self); +VirtViewerApp* virt_viewer_session_get_app(VirtViewerSession *self); G_END_DECLS diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c index f539fb5..62b6052 100644 --- a/src/virt-viewer-window.c +++ b/src/virt-viewer-window.c @@ -493,15 +493,17 @@ virt_viewer_window_enter_fullscreen(VirtViewerWindow *self, gboolean move, gint priv->before_saved = TRUE; } - if (!priv->fullscreen) { - gtk_check_menu_item_set_active(check, TRUE); - priv->fullscreen = TRUE; - gtk_widget_hide(menu); - gtk_widget_show(priv->toolbar); - ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(priv->layout), TRUE); - ViewAutoDrawer_Close(VIEW_AUTODRAWER(priv->layout)); - } + if (priv->fullscreen) + return; + priv->fullscreen = TRUE; + + gtk_check_menu_item_set_active(check, TRUE); + gtk_widget_hide(menu); + gtk_widget_show(priv->toolbar); + ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(priv->layout), TRUE); + ViewAutoDrawer_Close(VIEW_AUTODRAWER(priv->layout)); + /* g_debug("enter fullscreen move:%d %d+%d", move, x, y); */ if (move) gtk_window_move(GTK_WINDOW(priv->window), x, y); -- 1.7.7.6