Implement SPICE desktop resizing that takes account of zoom level

The standard SPICE widget guest resize implementation does not
take into account the zoom level settings in virt-viewer, because
it has no knowledge of this functionality. The guest resize can,
however, be done by calling spice_main_set_display() directly.
This allows virt-viewer to resize the guest taking into account
zoom levels.

 ie, if virt-viewer is run with --zoom 50 and the window
     is resized to 400x300, then the guest agent should
     be told to set its resolution to 800x600
This commit is contained in:
Daniel P. Berrange 2012-02-07 17:04:57 +00:00
parent 3a8cdd901f
commit 50632ea038
7 changed files with 110 additions and 5 deletions

View File

@ -151,8 +151,35 @@ virt_viewer_display_spice_mouse_grab(SpiceDisplay *display G_GNUC_UNUSED,
}
static void
virt_viewer_display_spice_size_allocate(SpiceDisplay *display G_GNUC_UNUSED,
GtkAllocation *allocation,
VirtViewerDisplaySpice *self G_GNUC_UNUSED)
{
gdouble dw = allocation->width, dh = allocation->height;
guint zoom = 100;
guint channelid;
if (virt_viewer_display_get_zoom(VIRT_VIEWER_DISPLAY(self))) {
zoom = virt_viewer_display_get_zoom_level(VIRT_VIEWER_DISPLAY(self));
dw /= ((double)zoom / 100.0);
dh /= ((double)zoom / 100.0);
}
g_object_get(self->priv->channel, "channel-id", &channelid, 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);
}
GtkWidget *
virt_viewer_display_spice_new(SpiceChannel *channel,
virt_viewer_display_spice_new(VirtViewerSessionSpice *session,
SpiceChannel *channel,
SpiceDisplay *display)
{
VirtViewerDisplaySpice *self;
@ -164,6 +191,7 @@ virt_viewer_display_spice_new(SpiceChannel *channel,
g_object_get(channel, "channel-id", &channelid, NULL);
self = g_object_new(VIRT_VIEWER_TYPE_DISPLAY_SPICE,
"session", session,
"nth-display", channelid,
NULL);
self->priv->channel = g_object_ref(channel);
@ -189,6 +217,10 @@ virt_viewer_display_spice_new(SpiceChannel *channel,
g_signal_connect(self->priv->display,
"mouse-grab",
G_CALLBACK(virt_viewer_display_spice_mouse_grab), self);
g_signal_connect(self->priv->display,
"size-allocate",
G_CALLBACK(virt_viewer_display_spice_size_allocate), self);
return GTK_WIDGET(self);
}

View File

@ -29,6 +29,7 @@
#include <spice-audio.h>
#include "virt-viewer-display.h"
#include "virt-viewer-session-spice.h"
G_BEGIN_DECLS
@ -65,7 +66,8 @@ struct _VirtViewerDisplaySpiceClass {
GType virt_viewer_display_spice_get_type(void);
GtkWidget* virt_viewer_display_spice_new(SpiceChannel *channel,
GtkWidget* virt_viewer_display_spice_new(VirtViewerSessionSpice *session,
SpiceChannel *channel,
SpiceDisplay *display);
G_END_DECLS

View File

@ -26,6 +26,7 @@
#include <locale.h>
#include "virt-viewer-session.h"
#include "virt-viewer-display.h"
#include "virt-viewer-util.h"
@ -40,6 +41,7 @@ struct _VirtViewerDisplayPrivate
gboolean zoom;
gint nth_display;
gint show_hint;
VirtViewerSession *session;
};
static void virt_viewer_display_size_request(GtkWidget *widget,
@ -75,6 +77,7 @@ enum {
PROP_ZOOM,
PROP_ZOOM_LEVEL,
PROP_SHOW_HINT,
PROP_SESSION,
};
static void
@ -154,6 +157,15 @@ virt_viewer_display_class_init(VirtViewerDisplayClass *class)
0,
G_PARAM_READABLE));
g_object_class_install_property(object_class,
PROP_SESSION,
g_param_spec_object("session",
"Session",
"VirtSession",
VIRT_VIEWER_TYPE_SESSION,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_signal_new("display-pointer-grab",
G_OBJECT_CLASS_TYPE(object_class),
@ -252,6 +264,11 @@ virt_viewer_display_set_property(GObject *object,
case PROP_NTH_DISPLAY:
priv->nth_display = g_value_get_int(value);
break;
case PROP_SESSION:
g_warn_if_fail(priv->session == NULL);
priv->session = g_value_dup_object(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -280,6 +297,9 @@ virt_viewer_display_get_property(GObject *object,
case PROP_SHOW_HINT:
g_value_set_int(value, priv->show_hint);
break;
case PROP_SESSION:
g_value_set_object(value, virt_viewer_display_get_session(display));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -468,6 +488,13 @@ void virt_viewer_display_set_zoom_level(VirtViewerDisplay *display,
}
guint virt_viewer_display_get_zoom_level(VirtViewerDisplay *display)
{
VirtViewerDisplayPrivate *priv = display->priv;
return priv->zoom_level;
}
void virt_viewer_display_set_zoom(VirtViewerDisplay *display,
gboolean zoom)
{
@ -481,6 +508,14 @@ void virt_viewer_display_set_zoom(VirtViewerDisplay *display,
}
}
gboolean virt_viewer_display_get_zoom(VirtViewerDisplay *display)
{
VirtViewerDisplayPrivate *priv = display->priv;
return priv->zoom;
}
void virt_viewer_display_send_keys(VirtViewerDisplay *display,
const guint *keyvals, int nkeyvals)
{
@ -509,6 +544,13 @@ void virt_viewer_display_set_show_hint(VirtViewerDisplay *self, gint hint)
g_object_notify(G_OBJECT(self), "show-hint");
}
VirtViewerSession* virt_viewer_display_get_session(VirtViewerDisplay *self)
{
g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), NULL);
return self->priv->session;
}
/*
* Local variables:
* c-indent-level: 4

View File

@ -45,6 +45,9 @@ G_BEGIN_DECLS
#define VIRT_VIEWER_DISPLAY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), VIRT_VIEWER_TYPE_DISPLAY, VirtViewerDisplayClass))
typedef struct _VirtViewerSession VirtViewerSession;
typedef struct _VirtViewerSessionClass VirtViewerSessionClass;
typedef struct _VirtViewerDisplay VirtViewerDisplay;
typedef struct _VirtViewerDisplayClass VirtViewerDisplayClass;
typedef struct _VirtViewerDisplayPrivate VirtViewerDisplayPrivate;
@ -94,13 +97,16 @@ void virt_viewer_display_get_desktop_size(VirtViewerDisplay *display,
void virt_viewer_display_set_zoom_level(VirtViewerDisplay *display,
guint zoom);
guint virt_viewer_display_get_zoom_level(VirtViewerDisplay *display);
void virt_viewer_display_set_zoom(VirtViewerDisplay *display,
gboolean zoom);
gboolean virt_viewer_display_get_zoom(VirtViewerDisplay *display);
void virt_viewer_display_send_keys(VirtViewerDisplay *display,
const guint *keyvals, int nkeyvals);
GdkPixbuf* virt_viewer_display_get_pixbuf(VirtViewerDisplay *display);
void virt_viewer_display_set_show_hint(VirtViewerDisplay *display, gint hint);
VirtViewerSession* virt_viewer_display_get_session(VirtViewerDisplay *display);
G_END_DECLS

View File

@ -40,6 +40,7 @@ G_DEFINE_TYPE (VirtViewerSessionSpice, virt_viewer_session_spice, VIRT_VIEWER_TY
struct _VirtViewerSessionSpicePrivate {
SpiceSession *session;
SpiceGtkSession *gtk_session;
SpiceMainChannel *main_channel;
SpiceAudio *audio;
};
@ -103,6 +104,8 @@ virt_viewer_session_spice_dispose(GObject *obj)
}
if (spice->priv->audio)
g_object_unref(spice->priv->audio);
if (spice->priv->main_channel)
g_object_unref(spice->priv->main_channel);
G_OBJECT_CLASS(virt_viewer_session_spice_parent_class)->finalize(obj);
}
@ -370,8 +373,16 @@ virt_viewer_session_spice_channel_new(SpiceSession *s,
g_object_get(channel, "channel-id", &id, NULL);
if (SPICE_IS_MAIN_CHANNEL(channel)) {
if (self->priv->main_channel != NULL) {
/* FIXME: use telepathy-glib g_signal_connect_object to automatically disconnect.. */
g_signal_handlers_disconnect_by_func(self->priv->main_channel,
virt_viewer_session_spice_main_channel_event, self);
g_object_unref(self->priv->main_channel);
}
g_signal_connect(channel, "channel-event",
G_CALLBACK(virt_viewer_session_spice_main_channel_event), self);
self->priv->main_channel = g_object_ref(channel);
}
if (SPICE_IS_DISPLAY_CHANNEL(channel)) {
@ -380,7 +391,8 @@ virt_viewer_session_spice_channel_new(SpiceSession *s,
g_signal_emit_by_name(session, "session-connected");
DEBUG_LOG("new session channel (#%d)", id);
display = virt_viewer_display_spice_new(channel,
display = virt_viewer_display_spice_new(self,
channel,
spice_display_new(s, id));
virt_viewer_session_add_display(VIRT_VIEWER_SESSION(session),
@ -414,6 +426,10 @@ virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s,
g_object_get(channel, "channel-id", &id, NULL);
if (SPICE_IS_MAIN_CHANNEL(channel)) {
DEBUG_LOG("zap main channel");
if (channel == SPICE_CHANNEL(self->priv->main_channel)) {
g_object_unref(self->priv->main_channel);
self->priv->main_channel = NULL;
}
}
if (SPICE_IS_DISPLAY_CHANNEL(channel)) {
@ -439,6 +455,14 @@ virt_viewer_session_spice_new(void)
return VIRT_VIEWER_SESSION(self);
}
SpiceMainChannel*
virt_viewer_session_spice_get_main_channel(VirtViewerSessionSpice *self)
{
g_return_val_if_fail(VIRT_VIEWER_IS_SESSION_SPICE(self), NULL);
return self->priv->main_channel;
}
/*
* Local variables:
* c-indent-level: 4

View File

@ -66,6 +66,7 @@ struct _VirtViewerSessionSpiceClass {
GType virt_viewer_session_spice_get_type(void);
VirtViewerSession* virt_viewer_session_spice_new(void);
SpiceMainChannel* virt_viewer_session_spice_get_main_channel(VirtViewerSessionSpice *self);
G_END_DECLS

View File

@ -47,8 +47,6 @@ G_BEGIN_DECLS
#define VIRT_VIEWER_SESSION_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), VIRT_VIEWER_TYPE_SESSION, VirtViewerSessionClass))
typedef struct _VirtViewerSession VirtViewerSession;
typedef struct _VirtViewerSessionClass VirtViewerSessionClass;
typedef struct _VirtViewerSessionPrivate VirtViewerSessionPrivate;
typedef struct _VirtViewerSessionChannel VirtViewerSessionChannel;