spice: implement --fullscreen=auto-conf

- auto-conf is an optionnal argument to --fullscreen:
it will set the guest display configuration to match the client
display configuration, by sending the client monitors size and
position to capable guests.
This commit is contained in:
Marc-André Lureau 2012-03-17 02:04:34 +01:00
parent 395a44bd47
commit cf8e5b029c
7 changed files with 155 additions and 21 deletions

View File

@ -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);

View File

@ -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

View File

@ -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,
@ -393,6 +394,15 @@ virt_viewer_session_spice_usb_device_selection(VirtViewerSession *session,
gtk_widget_destroy(dialog);
}
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,
@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);