viewer: Add support for Spice

This commit is contained in:
Marc-André Lureau 2010-11-30 13:59:01 +01:00
parent 882ac10d52
commit 155a03f9c8
17 changed files with 1373 additions and 459 deletions

View File

@ -13,6 +13,7 @@ With additional patches from:
Guido G\374nther <agx-at-sigxcpu-dot-org>
Hiroyuki Kaguchi <fj7025cf-at-aa-dot-jp-dot-fujitsu-dot-com>
Ronnie Sahlberg <ronniesahlberg@gmail.com>
Marc-André Lureau <marcandre.lureau-at-redhat-dot-com>
...send patches to get your name here...

View File

@ -33,6 +33,7 @@ PKG_CHECK_MODULES(LIBVIRT, libvirt >= 0.6.0)
PKG_CHECK_MODULES(GTK2, gtk+-2.0 >= 2.10.0)
PKG_CHECK_MODULES(LIBGLADE2, libglade-2.0 >= 2.6.0)
PKG_CHECK_MODULES(GTKVNC, gtk-vnc-1.0 >= 0.3.8)
PKG_CHECK_MODULES(SPICEGTK, spice-client-gtk >= 0.1.0.14)
dnl Decide if this platform can support the SSH tunnel feature.
AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h])

View File

@ -2,6 +2,7 @@
man_MANS = virt-viewer.1
EXTRA_DIST = virt-viewer.pod
DISTCLEANFILES = $(man_MANS)
%.1: %.pod
pod2man $< > $@

View File

@ -10,12 +10,13 @@ B<virt-viewer> [OPTIONS] DOMAIN-NAME|ID|UUID
=head1 DESCRIPTION
B<virt-viewer> is a minimal tool for displaying the graphical console
of a virtual machine. The console is accessed using the VNC protocol.
The guest can be referred to based on its name, ID, or UUID. If the
guest is not already running, then the viewer can be told to wait
until is starts before attempting to connect to the console The viewer
can connect to remote hosts to lookup the console information and then
also connect to the remote console using the same network transport.
of a virtual machine. The console is accessed using the VNC or SPICE
protocol. The guest can be referred to based on its name, ID, or
UUID. If the guest is not already running, then the viewer can be told
to wait until is starts before attempting to connect to the console
The viewer can connect to remote hosts to lookup the console
information and then also connect to the remote console using the same
network transport.
=head1 OPTIONS
@ -49,7 +50,7 @@ Automatically reconnect to the domain if it shuts down and restarts
=item -z PCT, --zoom=PCT
Zoom level of the VNC window in percentage. Range 10-200.
Zoom level of the display window in percentage. Range 10-200.
=item -d, --direct

View File

@ -3,6 +3,8 @@ src/events.c
src/main.c
src/util.c
src/viewer.c
src/display-spice.c
src/display-vnc.c
src/about.glade
src/auth.glade
src/viewer.glade

View File

@ -11,10 +11,15 @@ virt_viewer_SOURCES = \
util.h util.c \
auth.h auth.c \
events.h events.c \
viewer.h viewer.c
viewer.h viewer.c \
viewer-priv.h \
display.h display.c \
display-vnc.h display-vnc.c \
display-spice.h display-spice.c
virt_viewer_LDADD = \
@GTKVNC_LIBS@ \
@SPICEGTK_LIBS@ \
@GTK2_LIBS@ \
@LIBXML2_LIBS@ \
@LIBGLADE2_LIBS@ \
@ -22,6 +27,7 @@ virt_viewer_LDADD = \
virt_viewer_CFLAGS = \
@GTKVNC_CFLAGS@ \
@SPICEGTK_CFLAGS@ \
@GTK2_CFLAGS@ \
@LIBXML2_CFLAGS@ \
@LIBGLADE2_CFLAGS@ \

View File

@ -30,11 +30,8 @@
#include "auth.h"
static int
viewer_auth_collect_credentials(const char *type,
const char *address,
char **username,
char **password)
int viewer_auth_collect_credentials(const char *type, const char *address,
char **username, char **password)
{
GtkWidget *dialog = NULL;
GladeXML *creds = viewer_load_glade("auth.glade", "auth");

View File

@ -29,6 +29,9 @@
void viewer_auth_vnc_credentials(GtkWidget *vnc, GValueArray *credList, char **message);
int viewer_auth_collect_credentials(const char *type, const char *address,
char **username, char **password);
int viewer_auth_libvirt_credentials(virConnectCredentialPtr cred,
unsigned int ncred,
void *cbdata);

281
src/display-spice.c Normal file
View File

@ -0,0 +1,281 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <spice-audio.h>
#include "util.h"
#include "display-spice.h"
#include "auth.h"
G_DEFINE_TYPE (VirtViewerDisplaySpice, virt_viewer_display_spice, VIRT_VIEWER_TYPE_DISPLAY)
static void _spice_close(VirtViewerDisplay* display);
static void _spice_send_keys(VirtViewerDisplay* display, const guint *keyvals, int nkeyvals);
static GdkPixbuf* _spice_get_pixbuf(VirtViewerDisplay* display);
static gboolean _spice_open_fd(VirtViewerDisplay* display, int fd);
static gboolean _spice_open_host(VirtViewerDisplay* display, char *host, char *port);
static gboolean _spice_channel_open_fd(VirtViewerDisplay* display, VirtViewerDisplayChannel* channel, int fd);
static void
virt_viewer_display_spice_class_init(VirtViewerDisplaySpiceClass *klass)
{
VirtViewerDisplayClass *dclass = VIRT_VIEWER_DISPLAY_CLASS(klass);
dclass->close = _spice_close;
dclass->send_keys = _spice_send_keys;
dclass->get_pixbuf = _spice_get_pixbuf;
dclass->open_fd = _spice_open_fd;
dclass->open_host = _spice_open_host;
dclass->channel_open_fd = _spice_channel_open_fd;
}
static void
virt_viewer_display_spice_init(VirtViewerDisplaySpice *self G_GNUC_UNUSED)
{
}
static void _spice_send_keys(VirtViewerDisplay* display, const guint *keyvals, int nkeyvals)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_if_fail(self != NULL);
g_return_if_fail(self->display != NULL);
spice_display_send_keys(self->display, keyvals, nkeyvals, SPICE_DISPLAY_KEY_EVENT_CLICK);
}
static GdkPixbuf* _spice_get_pixbuf(VirtViewerDisplay* display)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_val_if_fail(self != NULL, NULL);
g_return_val_if_fail(self->display != NULL, NULL);
return spice_display_get_pixbuf(self->display);
}
static void _spice_close(VirtViewerDisplay* display)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_if_fail(self != NULL);
if (self->session == NULL)
return;
spice_session_disconnect(self->session);
if (self->session) /* let viewer_quit() be reentrant */
g_object_unref(self->session);
self->session = NULL;
if (self->audio)
g_object_unref(self->audio);
self->audio = NULL;
}
static gboolean _spice_open_host(VirtViewerDisplay* display, char *host, char *port)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_val_if_fail(self != NULL, FALSE);
g_return_val_if_fail(self->session != NULL, FALSE);
g_object_set(self->session,
"host", host,
"port", port,
NULL);
return spice_session_connect(self->session);
}
static gboolean _spice_open_fd(VirtViewerDisplay* display, int fd)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_val_if_fail(self != NULL, FALSE);
return spice_session_open_fd(self->session, fd);
}
static gboolean _spice_channel_open_fd(VirtViewerDisplay* display,
VirtViewerDisplayChannel* channel, int fd)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_val_if_fail(self != NULL, FALSE);
return spice_channel_open_fd(SPICE_CHANNEL(channel), fd);
}
static void _spice_channel_open_fd_request(SpiceChannel *channel,
G_GNUC_UNUSED gint tls,
VirtViewerDisplay *display)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
g_return_if_fail(self != NULL);
viewer_channel_open_fd(display->viewer, (VirtViewerDisplayChannel *)channel);
}
static void _spice_main_channel_event(G_GNUC_UNUSED SpiceChannel *channel,
SpiceChannelEvent event,
VirtViewerDisplay *display)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
char *password = NULL;
g_return_if_fail(self != NULL);
g_return_if_fail(display->viewer != NULL);
switch (event) {
case SPICE_CHANNEL_OPENED:
DEBUG_LOG("main channel: opened");
break;
case SPICE_CHANNEL_CLOSED:
DEBUG_LOG("main channel: closed");
viewer_quit(display->viewer);
break;
case SPICE_CHANNEL_ERROR_CONNECT:
DEBUG_LOG("main channel: failed to connect");
viewer_disconnected(display->viewer);
break;
case SPICE_CHANNEL_ERROR_AUTH:
DEBUG_LOG("main channel: auth failure (wrong password?)");
int ret = viewer_auth_collect_credentials("SPICE",
display->viewer->pretty_address,
NULL, &password);
if (ret < 0) {
viewer_quit(display->viewer);
} else {
g_object_set(self->session, "password", password, NULL);
spice_session_connect(self->session);
}
break;
default:
g_warning("unknown main channel event: %d", event);
viewer_disconnected(display->viewer);
break;
}
g_free(password);
}
static void _spice_channel_new(SpiceSession *s, SpiceChannel *channel,
VirtViewerDisplay *display)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
int id;
g_return_if_fail(self != NULL);
g_signal_connect(channel, "open-fd",
G_CALLBACK(_spice_channel_open_fd_request), self);
g_object_get(channel, "channel-id", &id, NULL);
if (SPICE_IS_MAIN_CHANNEL(channel)) {
g_signal_connect(channel, "channel-event",
G_CALLBACK(_spice_main_channel_event), self);
}
if (SPICE_IS_DISPLAY_CHANNEL(channel)) {
DEBUG_LOG("new display channel (#%d)", id);
if (display->widget != NULL)
return;
self->display = spice_display_new(s, id);
display->widget = GTK_WIDGET(self->display);
g_object_set(self->display,
"grab-keyboard", TRUE,
"grab-mouse", TRUE,
NULL);
viewer_add_display_and_realize(display->viewer);
viewer_initialized(display->viewer);
}
if (SPICE_IS_INPUTS_CHANNEL(channel)) {
DEBUG_LOG("new inputs channel");
}
if (SPICE_IS_PLAYBACK_CHANNEL(channel)) {
DEBUG_LOG("new audio channel");
if (self->audio != NULL)
return;
self->audio = spice_audio_new(s, NULL, NULL);
}
}
static void _spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s, SpiceChannel *channel,
VirtViewerDisplay *display)
{
VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display);
int id;
g_return_if_fail(self != NULL);
g_object_get(channel, "channel-id", &id, NULL);
if (SPICE_IS_MAIN_CHANNEL(channel)) {
DEBUG_LOG("zap main channel");
}
if (SPICE_IS_DISPLAY_CHANNEL(channel)) {
DEBUG_LOG("zap display channel (#%d)", id);
}
if (SPICE_IS_PLAYBACK_CHANNEL(channel)) {
if (self->audio == NULL)
return;
DEBUG_LOG("zap audio channel");
}
}
VirtViewerDisplaySpice* virt_viewer_display_spice_new(VirtViewer *viewer)
{
VirtViewerDisplaySpice *self;
VirtViewerDisplay *d;
g_return_val_if_fail(viewer != NULL, NULL);
self = g_object_new(VIRT_VIEWER_TYPE_DISPLAY_SPICE, NULL);
d = VIRT_VIEWER_DISPLAY(self);
d->viewer = viewer;
self->session = spice_session_new();
g_signal_connect(self->session, "channel-new",
G_CALLBACK(_spice_channel_new), self);
g_signal_connect(self->session, "channel-destroy",
G_CALLBACK(_spice_channel_destroy), self);
return self;
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

78
src/display-spice.h Normal file
View File

@ -0,0 +1,78 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef _VIRT_VIEWER_DISPLAY_SPICE_H
#define _VIRT_VIEWER_DISPLAY_SPICE_H
#include <glib-object.h>
#include <spice-widget.h>
#include <spice-audio.h>
#include "display.h"
G_BEGIN_DECLS
#define VIRT_VIEWER_TYPE_DISPLAY_SPICE virt_viewer_display_spice_get_type()
#define VIRT_VIEWER_DISPLAY_SPICE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), VIRT_VIEWER_TYPE_DISPLAY_SPICE, VirtViewerDisplaySpice))
#define VIRT_VIEWER_DISPLAY_SPICE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), VIRT_VIEWER_TYPE_DISPLAY_SPICE, VirtViewerDisplaySpiceClass))
#define VIRT_IS_VIEWER_DISPLAY_SPICE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIRT_VIEWER_TYPE_DISPLAY_SPICE))
#define VIRT_IS_VIEWER_DISPLAY_SPICE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), VIRT_VIEWER_TYPE_DISPLAY_SPICE))
#define VIRT_VIEWER_DISPLAY_SPICE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), VIRT_VIEWER_TYPE_DISPLAY_SPICE, VirtViewerDisplaySpiceClass))
typedef struct {
VirtViewerDisplay parent;
SpiceSession *session;
SpiceDisplay *display;
SpiceAudio *audio;
} VirtViewerDisplaySpice;
typedef struct {
VirtViewerDisplayClass parent_class;
} VirtViewerDisplaySpiceClass;
GType virt_viewer_display_spice_get_type(void);
VirtViewerDisplaySpice* virt_viewer_display_spice_new(VirtViewer *viewer);
G_END_DECLS
#endif /* _VIRT_VIEWER_DISPLAY_SPICE_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

333
src/display-vnc.c Normal file
View File

@ -0,0 +1,333 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include "auth.h"
#include "display-vnc.h"
G_DEFINE_TYPE(VirtViewerDisplayVNC, virt_viewer_display_vnc, VIRT_VIEWER_TYPE_DISPLAY)
static void _vnc_close(VirtViewerDisplay* display);
static void _vnc_send_keys(VirtViewerDisplay* display, const guint *keyvals, int nkeyvals);
static GdkPixbuf* _vnc_get_pixbuf(VirtViewerDisplay* display);
static gboolean _vnc_open_fd(VirtViewerDisplay* display, int fd);
static gboolean _vnc_open_host(VirtViewerDisplay* display, char *host, char *port);
static gboolean _vnc_channel_open_fd(VirtViewerDisplay* display,
VirtViewerDisplayChannel* channel, int fd);
static void virt_viewer_display_vnc_class_init(VirtViewerDisplayVNCClass *klass)
{
VirtViewerDisplayClass *dclass = VIRT_VIEWER_DISPLAY_CLASS(klass);
dclass->close = _vnc_close;
dclass->send_keys = _vnc_send_keys;
dclass->get_pixbuf = _vnc_get_pixbuf;
dclass->open_fd = _vnc_open_fd;
dclass->open_host = _vnc_open_host;
dclass->channel_open_fd = _vnc_channel_open_fd;
}
static void virt_viewer_display_vnc_init(VirtViewerDisplayVNC *self G_GNUC_UNUSED)
{
}
static void _vnc_mouse_grab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewerDisplayVNC *self)
{
viewer_set_title(VIRT_VIEWER_DISPLAY(self)->viewer, TRUE);
}
static void _vnc_mouse_ungrab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewerDisplayVNC *self)
{
viewer_set_title(VIRT_VIEWER_DISPLAY(self)->viewer, FALSE);
}
static void _vnc_key_grab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewerDisplayVNC *self)
{
viewer_disable_modifiers(VIRT_VIEWER_DISPLAY(self)->viewer);
}
static void _vnc_key_ungrab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewerDisplayVNC *self)
{
viewer_enable_modifiers(VIRT_VIEWER_DISPLAY(self)->viewer);
}
static void _vnc_send_keys(VirtViewerDisplay* display, const guint *keyvals, int nkeyvals)
{
VirtViewerDisplayVNC *self = VIRT_VIEWER_DISPLAY_VNC(display);
g_return_if_fail(self != NULL);
g_return_if_fail(keyvals != NULL);
g_return_if_fail(self->vnc != NULL);
vnc_display_send_keys(self->vnc, keyvals, nkeyvals);
}
static GdkPixbuf* _vnc_get_pixbuf(VirtViewerDisplay* display)
{
VirtViewerDisplayVNC *self = VIRT_VIEWER_DISPLAY_VNC(display);
g_return_val_if_fail(self != NULL, NULL);
g_return_val_if_fail(self->vnc != NULL, NULL);
return vnc_display_get_pixbuf(self->vnc);
}
static gboolean _vnc_open_fd(VirtViewerDisplay* display, int fd)
{
VirtViewerDisplayVNC *self = VIRT_VIEWER_DISPLAY_VNC(display);
g_return_val_if_fail(self != NULL, FALSE);
g_return_val_if_fail(self->vnc != NULL, FALSE);
return vnc_display_open_fd(self->vnc, fd);
}
static gboolean _vnc_channel_open_fd(VirtViewerDisplay* display G_GNUC_UNUSED,
VirtViewerDisplayChannel* channel G_GNUC_UNUSED,
int fd G_GNUC_UNUSED)
{
g_warning("channel_open_fd is not supported by VNC");
return FALSE;
}
static gboolean _vnc_open_host(VirtViewerDisplay* display, char *host, char *port)
{
VirtViewerDisplayVNC *self = VIRT_VIEWER_DISPLAY_VNC(display);
g_return_val_if_fail(self != NULL, FALSE);
g_return_val_if_fail(self->vnc != NULL, FALSE);
return vnc_display_open_host(self->vnc, host, port);
}
static void _vnc_close(VirtViewerDisplay* display)
{
VirtViewerDisplayVNC *self = VIRT_VIEWER_DISPLAY_VNC(display);
g_return_if_fail(self != NULL);
if (self->vnc != NULL)
vnc_display_close(self->vnc);
}
static void viewer_bell(VirtViewer *viewer, gpointer data G_GNUC_UNUSED)
{
gdk_window_beep(GTK_WIDGET(viewer->window)->window);
}
static void viewer_vnc_auth_unsupported(VirtViewer *viewer,
unsigned int authType, gpointer data G_GNUC_UNUSED)
{
viewer_simple_message_dialog(viewer->window,
_("Unable to authenticate with VNC server at %s\n"
"Unsupported authentication type %d"),
viewer->pretty_address, authType);
}
static void viewer_vnc_auth_failure(VirtViewer *viewer,
const char *reason, gpointer data G_GNUC_UNUSED)
{
GtkWidget *dialog;
int ret;
dialog = gtk_message_dialog_new(GTK_WINDOW(viewer->window),
GTK_DIALOG_MODAL |
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_YES_NO,
_("Unable to authenticate with VNC server at %s: %s\n"
"Retry connection again?"),
viewer->pretty_address, reason);
ret = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (ret == GTK_RESPONSE_YES)
viewer->authretry = TRUE;
else
viewer->authretry = FALSE;
}
/*
* Triggers a resize of the main container to indirectly cause
* the display widget to be resized to fit the available space
*/
static void
viewer_resize_display_widget(VirtViewer *viewer)
{
GtkWidget *align;
align = glade_xml_get_widget(viewer->glade, "display-align");
gtk_widget_queue_resize(align);
}
/*
* Called when desktop size changes.
*
* It either tries to resize the main window, or it triggers
* recalculation of the display within existing window size
*/
static void viewer_resize_desktop(VirtViewer *viewer, gint width, gint height)
{
DEBUG_LOG("desktop resize %dx%d", width, height);
viewer->desktopWidth = width;
viewer->desktopHeight = height;
if (viewer->autoResize && viewer->window && !viewer->fullscreen) {
viewer_resize_main_window(viewer);
} else {
viewer_resize_display_widget(viewer);
}
}
/*
* Called when the main container widget's size has been set.
* It attempts to fit the display widget into this space while
* maintaining aspect ratio
*/
static gboolean viewer_resize_align(GtkWidget *widget,
GtkAllocation *alloc,
VirtViewer *viewer)
{
double desktopAspect;
double scrollAspect;
int height, width;
GtkAllocation child;
int dx = 0, dy = 0;
if (!viewer->active) {
DEBUG_LOG("Skipping inactive resize");
return TRUE;
}
desktopAspect = (double)viewer->desktopWidth / (double)viewer->desktopHeight;
scrollAspect = (double)alloc->width / (double)alloc->height;
if (scrollAspect > desktopAspect) {
width = alloc->height * desktopAspect;
dx = (alloc->width - width) / 2;
height = alloc->height;
} else {
width = alloc->width;
height = alloc->width / desktopAspect;
dy = (alloc->height - height) / 2;
}
DEBUG_LOG("Align widget=%p is %dx%d, desktop is %dx%d, setting display to %dx%d",
widget,
alloc->width, alloc->height,
viewer->desktopWidth, viewer->desktopHeight,
width, height);
child.x = alloc->x + dx;
child.y = alloc->y + dy;
child.width = width;
child.height = height;
if (viewer->display && viewer->display->widget)
gtk_widget_size_allocate(viewer->display->widget, &child);
return FALSE;
}
VirtViewerDisplayVNC* virt_viewer_display_vnc_new(VirtViewer *viewer)
{
VirtViewerDisplayVNC *self;
VirtViewerDisplay *d;
GtkWidget *align;
g_return_val_if_fail(viewer != NULL, NULL);
self = g_object_new(VIRT_VIEWER_TYPE_DISPLAY_VNC, NULL);
d = VIRT_VIEWER_DISPLAY(self);
d->viewer = viewer;
viewer->display = d;
d->widget = vnc_display_new();
self->vnc = VNC_DISPLAY(d->widget);
vnc_display_set_keyboard_grab(self->vnc, TRUE);
vnc_display_set_pointer_grab(self->vnc, TRUE);
/*
* In auto-resize mode we have things setup so that we always
* automatically resize the top level window to be exactly the
* same size as the VNC desktop, except when it won't fit on
* the local screen, at which point we let it scale down.
* The upshot is, we always want scaling enabled.
* We disable force_size because we want to allow user to
* manually size the widget smaller too
*/
vnc_display_set_force_size(self->vnc, FALSE);
vnc_display_set_scaling(self->vnc, TRUE);
g_signal_connect_swapped(self->vnc, "vnc-connected",
G_CALLBACK(viewer_connected), viewer);
g_signal_connect_swapped(self->vnc, "vnc-initialized",
G_CALLBACK(viewer_initialized), viewer);
g_signal_connect_swapped(self->vnc, "vnc-disconnected",
G_CALLBACK(viewer_disconnected), viewer);
/* When VNC desktop resizes, we have to resize the containing widget */
g_signal_connect_swapped(self->vnc, "vnc-desktop-resize",
G_CALLBACK(viewer_resize_desktop), viewer);
g_signal_connect_swapped(self->vnc, "vnc-bell",
G_CALLBACK(viewer_bell), NULL);
g_signal_connect_swapped(self->vnc, "vnc-auth-failure",
G_CALLBACK(viewer_vnc_auth_failure), viewer);
g_signal_connect_swapped(self->vnc, "vnc-auth-unsupported",
G_CALLBACK(viewer_vnc_auth_unsupported), viewer);
g_signal_connect_swapped(self->vnc, "vnc-server-cut-text",
G_CALLBACK(viewer_server_cut_text), viewer);
g_signal_connect(self->vnc, "vnc-pointer-grab",
G_CALLBACK(_vnc_mouse_grab), self);
g_signal_connect(self->vnc, "vnc-pointer-ungrab",
G_CALLBACK(_vnc_mouse_ungrab), self);
g_signal_connect(self->vnc, "vnc-keyboard-grab",
G_CALLBACK(_vnc_key_grab), self);
g_signal_connect(self->vnc, "vnc-keyboard-ungrab",
G_CALLBACK(_vnc_key_ungrab), self);
g_signal_connect(self->vnc, "vnc-auth-credential",
G_CALLBACK(viewer_auth_vnc_credentials), &viewer->pretty_address);
viewer_add_display_and_realize(viewer);
align = glade_xml_get_widget(viewer->glade, "display-align");
g_signal_connect(align, "size-allocate",
G_CALLBACK(viewer_resize_align), viewer);
return self;
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

75
src/display-vnc.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef _VIRT_VIEWER_DISPLAY_VNC_H
#define _VIRT_VIEWER_DISPLAY_VNC_H
#include <glib-object.h>
#include <vncdisplay.h>
#include "display.h"
G_BEGIN_DECLS
#define VIRT_VIEWER_TYPE_DISPLAY_VNC virt_viewer_display_vnc_get_type()
#define VIRT_VIEWER_DISPLAY_VNC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), VIRT_VIEWER_TYPE_DISPLAY_VNC, VirtViewerDisplayVNC))
#define VIRT_VIEWER_DISPLAY_VNC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), VIRT_VIEWER_TYPE_DISPLAY_VNC, VirtViewerDisplayVNCClass))
#define VIRT_IS_VIEWER_DISPLAY_VNC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIRT_VIEWER_TYPE_DISPLAY_VNC))
#define VIRT_IS_VIEWER_DISPLAY_VNC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), VIRT_VIEWER_TYPE_DISPLAY_VNC))
#define VIRT_VIEWER_DISPLAY_VNC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), VIRT_VIEWER_TYPE_DISPLAY_VNC, VirtViewerDisplayVNCClass))
typedef struct {
VirtViewerDisplay parent;
VncDisplay *vnc;
} VirtViewerDisplayVNC;
typedef struct {
VirtViewerDisplayClass parent_class;
} VirtViewerDisplayVNCClass;
GType virt_viewer_display_vnc_get_type(void);
VirtViewerDisplayVNC* virt_viewer_display_vnc_new(VirtViewer *viewer);
G_END_DECLS
#endif /* _VIRT_VIEWER_DISPLAY_VNC_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

90
src/display.c Normal file
View File

@ -0,0 +1,90 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include "display.h"
G_DEFINE_ABSTRACT_TYPE(VirtViewerDisplay, virt_viewer_display, G_TYPE_OBJECT)
static void virt_viewer_display_class_init(VirtViewerDisplayClass *klass G_GNUC_UNUSED)
{
}
static void virt_viewer_display_init(VirtViewerDisplay *self G_GNUC_UNUSED)
{
}
void virt_viewer_display_close(VirtViewerDisplay *self)
{
g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
VIRT_VIEWER_DISPLAY_GET_CLASS(self)->close(self);
}
void virt_viewer_display_send_keys(VirtViewerDisplay *self,
const guint *keyvals, int nkeyvals)
{
g_return_if_fail(VIRT_VIEWER_IS_DISPLAY(self));
VIRT_VIEWER_DISPLAY_GET_CLASS(self)->send_keys(self, keyvals, nkeyvals);
}
GdkPixbuf* virt_viewer_display_get_pixbuf(VirtViewerDisplay *self)
{
g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), NULL);
return VIRT_VIEWER_DISPLAY_GET_CLASS(self)->get_pixbuf(self);
}
gboolean virt_viewer_display_open_fd(VirtViewerDisplay *self, int fd)
{
g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE);
return VIRT_VIEWER_DISPLAY_GET_CLASS(self)->open_fd(self, fd);
}
gboolean virt_viewer_display_open_host(VirtViewerDisplay *self, char *host, char *port)
{
VirtViewerDisplayClass *klass;
g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE);
klass = VIRT_VIEWER_DISPLAY_GET_CLASS(self);
return klass->open_host(self, host, port);
}
gboolean virt_viewer_display_channel_open_fd(VirtViewerDisplay *self,
VirtViewerDisplayChannel *channel, int fd)
{
g_return_val_if_fail(VIRT_VIEWER_IS_DISPLAY(self), FALSE);
return VIRT_VIEWER_DISPLAY_GET_CLASS(self)->channel_open_fd(self, channel, fd);
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

91
src/display.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef _VIRT_VIEWER_DISPLAY_H
#define _VIRT_VIEWER_DISPLAY_H
#include <glib-object.h>
#include "viewer-priv.h"
G_BEGIN_DECLS
#define VIRT_VIEWER_TYPE_DISPLAY virt_viewer_display_get_type()
#define VIRT_VIEWER_DISPLAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), VIRT_VIEWER_TYPE_DISPLAY, VirtViewerDisplay))
#define VIRT_VIEWER_DISPLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), VIRT_VIEWER_TYPE_DISPLAY, VirtViewerDisplayClass))
#define VIRT_VIEWER_IS_DISPLAY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIRT_VIEWER_TYPE_DISPLAY))
#define VIRT_VIEWER_IS_DISPLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), VIRT_VIEWER_TYPE_DISPLAY))
#define VIRT_VIEWER_DISPLAY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), VIRT_VIEWER_TYPE_DISPLAY, VirtViewerDisplayClass))
/* perhaps this become an interface, and be pushed in gtkvnc and spice? */
struct _VirtViewerDisplay {
GObject parent;
VirtViewer *viewer;
GtkWidget *widget;
};
struct _VirtViewerDisplayClass {
GObjectClass parent_class;
/* virtual methods */
void (* close) (VirtViewerDisplay* display);
void (* send_keys) (VirtViewerDisplay* display,
const guint *keyvals, int nkeyvals);
GdkPixbuf* (* get_pixbuf) (VirtViewerDisplay* display);
gboolean (* open_fd) (VirtViewerDisplay* display, int fd);
gboolean (* open_host) (VirtViewerDisplay* display, char *host, char *port);
gboolean (* channel_open_fd) (VirtViewerDisplay* display,
VirtViewerDisplayChannel* channel, int fd);
};
GType virt_viewer_display_get_type(void);
void virt_viewer_display_close(VirtViewerDisplay* display);
void virt_viewer_display_send_keys(VirtViewerDisplay* display,
const guint *keyvals, int nkeyvals);
GdkPixbuf* virt_viewer_display_get_pixbuf(VirtViewerDisplay* display);
gboolean virt_viewer_display_open_fd(VirtViewerDisplay* display, int fd);
gboolean virt_viewer_display_open_host(VirtViewerDisplay* display, char *host, char *port);
GObject* virt_viewer_display_get(VirtViewerDisplay* display);
gboolean virt_viewer_display_channel_open_fd(VirtViewerDisplay* display,
VirtViewerDisplayChannel* channel, int fd);
G_END_DECLS
#endif /* _VIRT_VIEWER_DISPLAY_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

123
src/viewer-priv.h Normal file
View File

@ -0,0 +1,123 @@
/*
* Virt Viewer: A virtual machine console viewer
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef _VIRT_VIEWER_PRIV_H
# define _VIRT_VIEWER_PRIV_H
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <glib/gi18n.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <libxml/xpath.h>
#include <libxml/uri.h>
typedef struct _VirtViewerDisplay VirtViewerDisplay;
typedef struct _VirtViewerDisplayClass VirtViewerDisplayClass;
typedef struct _VirtViewer VirtViewer;
typedef struct _VirtViewerSize VirtViewerSize;
typedef struct _VirtViewerDisplayChanne VirtViewerDisplayChannel;
enum menuNums {
FILE_MENU,
VIEW_MENU,
SEND_KEY_MENU,
HELP_MENU,
LAST_MENU // sentinel
};
struct _VirtViewer {
char *uri;
virConnectPtr conn;
char *domkey;
char *domtitle;
GladeXML *glade;
GtkWidget *window;
GtkWidget *container;
char *pretty_address;
int zoomlevel;
int desktopWidth;
int desktopHeight;
gboolean autoResize;
gboolean fullscreen;
gboolean withEvents;
gboolean active;
gboolean accelEnabled;
GValue accelSetting;
GSList *accelList;
int accelMenuSig[LAST_MENU];
gboolean waitvm;
gboolean reconnect;
gboolean direct;
gboolean verbose;
gboolean authretry;
gboolean connected;
gchar *clipboard;
VirtViewerDisplay *display;
char *gport;
char *host;
char *transport;
char *user;
int port;
};
struct _VirtViewerSize {
VirtViewer *viewer;
gint width, height;
gulong sig_id;
};
void viewer_connected(VirtViewer *viewer);
void viewer_initialized(VirtViewer *viewer);
void viewer_disconnected(VirtViewer *viewer);
void viewer_set_status(VirtViewer *viewer, const char *text);
void viewer_set_title(VirtViewer *viewer, gboolean grabbed);
void viewer_enable_modifiers(VirtViewer *viewer);
void viewer_disable_modifiers(VirtViewer *viewer);
void viewer_add_display_and_realize(VirtViewer *viewer);
void viewer_server_cut_text(VirtViewer *viewer, const gchar *text);
void viewer_resize_main_window(VirtViewer *viewer);
void viewer_channel_open_fd(VirtViewer *viewer, VirtViewerDisplayChannel *channel);
void viewer_quit(VirtViewer *viewer);
void viewer_simple_message_dialog(GtkWidget *window, const char *fmt, ...);
#endif // _VIRT_VIEWER_PRIV_H
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 2007-2009 Red Hat,
* Copyright (C) 2009 Daniel P. Berrange
* Copyright (C) 2010 Marc-André Lureau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -23,7 +24,6 @@
#include <config.h>
#include <vncdisplay.h>
#include <gdk/gdkkeysyms.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -31,11 +31,6 @@
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <glib/gi18n.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <libxml/xpath.h>
#include <libxml/uri.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@ -50,105 +45,54 @@
#endif
#include "viewer.h"
#include "viewer-priv.h"
#include "events.h"
#include "auth.h"
#include "display-vnc.h"
#include "display-spice.h"
#define SCALE(x) do { x = viewer->fullscreen ? x : x * viewer->zoomlevel / 100; } while (0);
gboolean doDebug = FALSE;
enum menuNums {
FILE_MENU,
VIEW_MENU,
SEND_KEY_MENU,
HELP_MENU,
LAST_MENU // sentinel
};
static const char * const menuNames[LAST_MENU] = {
"menu-file", "menu-view", "menu-send", "menu-help"
};
#define MAX_KEY_COMBO 3
struct keyComboDef {
struct keyComboDef {
guint keys[MAX_KEY_COMBO];
guint nkeys;
const char *label;
};
static const struct keyComboDef keyCombos[] = {
{ { GDK_Control_L, GDK_Alt_L, GDK_Delete }, 3, "Ctrl+Alt+_Del"},
{ { GDK_Control_L, GDK_Alt_L, GDK_BackSpace }, 3, "Ctrl+Alt+_Backspace"},
{ {}, 0, "" },
{ { GDK_Control_L, GDK_Alt_L, GDK_F1 }, 3, "Ctrl+Alt+F_1"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F2 }, 3, "Ctrl+Alt+F_2"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F3 }, 3, "Ctrl+Alt+F_3"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F4 }, 3, "Ctrl+Alt+F_4"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_5"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F_6"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F_7"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F_8"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_9"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F1_0"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F11"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F12"},
{ {}, 0, "" },
{ { GDK_Print }, 1, "_PrintScreen"},
{ { GDK_Control_L, GDK_Alt_L, GDK_Delete }, 3, "Ctrl+Alt+_Del"},
{ { GDK_Control_L, GDK_Alt_L, GDK_BackSpace }, 3, "Ctrl+Alt+_Backspace"},
{ {}, 0, "" },
{ { GDK_Control_L, GDK_Alt_L, GDK_F1 }, 3, "Ctrl+Alt+F_1"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F2 }, 3, "Ctrl+Alt+F_2"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F3 }, 3, "Ctrl+Alt+F_3"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F4 }, 3, "Ctrl+Alt+F_4"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_5"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F_6"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F_7"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F_8"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_9"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F1_0"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F11"},
{ { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F12"},
{ {}, 0, "" },
{ { GDK_Print }, 1, "_PrintScreen"},
};
typedef struct VirtViewer {
char *uri;
virConnectPtr conn;
char *domkey;
char *domtitle;
GladeXML *glade;
GtkWidget *window;
GtkWidget *container;
GtkWidget *vnc;
int zoomlevel;
int desktopWidth;
int desktopHeight;
gboolean autoResize;
gboolean fullscreen;
gboolean withEvents;
gboolean active;
char *vncAddress;
gboolean accelEnabled;
GValue accelSetting;
GSList *accelList;
int accelMenuSig[LAST_MENU];
gboolean waitvm;
gboolean reconnect;
gboolean direct;
gboolean verbose;
gboolean authretry;
gboolean connected;
gchar *clipboard;
} VirtViewer;
typedef struct VirtViewerSize {
VirtViewer *viewer;
gint width, height;
gulong sig_id;
} VirtViewerSize;
static gboolean viewer_connect_timer(void *opaque);
static int viewer_initial_connect(VirtViewer *viewer);
static void viewer_init_vnc_display(VirtViewer *viewer);
static void viewer_simple_message_dialog(GtkWidget *window, const char *fmt, ...)
void viewer_simple_message_dialog(GtkWidget *window, const char *fmt, ...)
{
GtkWidget *dialog;
char *msg;
@ -176,6 +120,27 @@ static void viewer_simple_message_dialog(GtkWidget *window, const char *fmt, ...
}
void viewer_add_display_and_realize(VirtViewer *viewer)
{
GtkWidget *notebook;
GtkWidget *align;
g_return_if_fail(viewer != NULL);
g_return_if_fail(viewer->display != NULL);
g_return_if_fail(viewer->display->widget != NULL);
notebook = glade_xml_get_widget(viewer->glade, "notebook");
align = glade_xml_get_widget(viewer->glade, "display-align");
gtk_container_add(GTK_CONTAINER(align), viewer->display->widget);
if (!viewer->window) {
gtk_container_add(GTK_CONTAINER(viewer->container), GTK_WIDGET(notebook));
gtk_widget_show_all(viewer->container);
}
gtk_widget_realize(viewer->display->widget);
}
/* Now that the size is set to our preferred sizing, this
* triggers another resize calculation but without our
* scrolled window callback active. This is the key that
@ -240,73 +205,13 @@ viewer_set_widget_size(VirtViewer *viewer,
}
/*
* Called when the main container widget's size has been set.
* It attempts to fit the VNC widget into this space while
* maintaining aspect ratio
*/
static gboolean viewer_resize_align(GtkWidget *widget,
GtkAllocation *alloc,
VirtViewer *viewer)
{
double desktopAspect = (double)viewer->desktopWidth / (double)viewer->desktopHeight;
double scrollAspect = (double)alloc->width / (double)alloc->height;
int height, width;
GtkAllocation child;
int dx = 0, dy = 0;
if (!viewer->active) {
DEBUG_LOG("Skipping inactive resize");
return TRUE;
}
if (scrollAspect > desktopAspect) {
width = alloc->height * desktopAspect;
dx = (alloc->width - width) / 2;
height = alloc->height;
} else {
width = alloc->width;
height = alloc->width / desktopAspect;
dy = (alloc->height - height) / 2;
}
DEBUG_LOG("Align widget=%p is %dx%d, desktop is %dx%d, setting VNC to %dx%d",
widget,
alloc->width, alloc->height,
viewer->desktopWidth, viewer->desktopHeight,
width, height);
child.x = alloc->x + dx;
child.y = alloc->y + dy;
child.width = width;
child.height = height;
gtk_widget_size_allocate(viewer->vnc, &child);
return FALSE;
}
/*
* Triggers a resize of the main container to indirectly cause
* the VNC widget to be resized to fit the available space
*/
static void
viewer_resize_vnc_widget(VirtViewer *viewer)
{
GtkWidget *align;
align = glade_xml_get_widget(viewer->glade, "vnc-align");
gtk_widget_queue_resize(align);
}
/*
* This code attempts to resize the top level window to be large enough
* to contain the entire VNC desktop at 1:1 ratio. If the local desktop
* isn't large enough that it goes as large as possible and lets VNC
* to contain the entire display desktop at 1:1 ratio. If the local desktop
* isn't large enough that it goes as large as possible and lets the display
* scale down to fit, maintaining aspect ratio
*/
static void
viewer_resize_main_window(VirtViewer *viewer)
void viewer_resize_main_window(VirtViewer *viewer)
{
GdkRectangle fullscreen;
GdkScreen *screen;
@ -351,7 +256,7 @@ viewer_resize_main_window(VirtViewer *viewer)
SCALE(height);
viewer_set_widget_size(viewer,
glade_xml_get_widget(viewer->glade, "vnc-align"),
glade_xml_get_widget(viewer->glade, "display-align"),
width,
height);
}
@ -381,27 +286,7 @@ static void viewer_menu_view_zoom_reset(G_GNUC_UNUSED GtkWidget *menu, VirtViewe
viewer_resize_main_window(viewer);
}
/*
* Called when VNC desktop size changes.
*
* It either tries to resize the main window, or it triggers
* recalculation of VNC within existing window size
*/
static void viewer_resize_desktop(GtkWidget *vnc G_GNUC_UNUSED, gint width, gint height, VirtViewer *viewer)
{
DEBUG_LOG("VNC desktop resize %dx%d", width, height);
viewer->desktopWidth = width;
viewer->desktopHeight = height;
if (viewer->autoResize && viewer->window && !viewer->fullscreen) {
viewer_resize_main_window(viewer);
} else {
viewer_resize_vnc_widget(viewer);
}
}
static void viewer_set_title(VirtViewer *viewer, gboolean grabbed)
void viewer_set_title(VirtViewer *viewer, gboolean grabbed)
{
char *title;
const char *subtitle;
@ -430,7 +315,7 @@ static gboolean viewer_ignore_accel(GtkWidget *menu G_GNUC_UNUSED,
}
static void viewer_disable_modifiers(VirtViewer *viewer)
void viewer_disable_modifiers(VirtViewer *viewer)
{
GtkSettings *settings = gtk_settings_get_default();
GValue empty;
@ -466,7 +351,7 @@ static void viewer_disable_modifiers(VirtViewer *viewer)
}
static void viewer_enable_modifiers(VirtViewer *viewer)
void viewer_enable_modifiers(VirtViewer *viewer)
{
GtkSettings *settings = gtk_settings_get_default();
GSList *accels;
@ -495,38 +380,23 @@ static void viewer_enable_modifiers(VirtViewer *viewer)
viewer->accelEnabled = TRUE;
}
static void viewer_mouse_grab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
void viewer_quit(VirtViewer *viewer)
{
viewer_set_title(viewer, TRUE);
}
g_return_if_fail(viewer != NULL);
static void viewer_mouse_ungrab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer_set_title(viewer, FALSE);
}
static void viewer_key_grab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer_disable_modifiers(viewer);
}
static void viewer_key_ungrab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer_enable_modifiers(viewer);
}
static void viewer_shutdown(GtkWidget *src G_GNUC_UNUSED, void *dummy G_GNUC_UNUSED, VirtViewer *viewer)
{
vnc_display_close(VNC_DISPLAY(viewer->vnc));
if (viewer->display)
virt_viewer_display_close(viewer->display);
gtk_main_quit();
}
static void viewer_delete(GtkWidget *src G_GNUC_UNUSED, void *dummy G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer_quit(viewer);
}
static void viewer_menu_file_quit(GtkWidget *src G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer_shutdown(src, NULL, viewer);
viewer_quit(viewer);
}
static void viewer_menu_view_fullscreen(GtkWidget *menu, VirtViewer *viewer)
@ -558,26 +428,26 @@ static void viewer_menu_view_resize(GtkWidget *menu, VirtViewer *viewer)
static void viewer_menu_send(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer)
{
int i;
GtkWidget *label = gtk_bin_get_child(GTK_BIN(menu));
const char *text = gtk_label_get_label(GTK_LABEL(label));
int i;
GtkWidget *label = gtk_bin_get_child(GTK_BIN(menu));
const char *text = gtk_label_get_label(GTK_LABEL(label));
for (i = 0 ; i < G_N_ELEMENTS(keyCombos) ; i++) {
if (!strcmp(text, keyCombos[i].label)) {
DEBUG_LOG("Sending key combo %s", gtk_label_get_text(GTK_LABEL(label)));
vnc_display_send_keys(VNC_DISPLAY(viewer->vnc),
keyCombos[i].keys,
keyCombos[i].nkeys);
return;
}
}
for (i = 0 ; i < G_N_ELEMENTS(keyCombos) ; i++) {
if (!strcmp(text, keyCombos[i].label)) {
DEBUG_LOG("Sending key combo %s", gtk_label_get_text(GTK_LABEL(label)));
virt_viewer_display_send_keys(viewer->display,
keyCombos[i].keys,
keyCombos[i].nkeys);
return;
}
}
DEBUG_LOG("Failed to find key combo %s", gtk_label_get_text(GTK_LABEL(label)));
}
static void viewer_save_screenshot(GtkWidget *vnc, const char *file)
static void viewer_save_screenshot(VirtViewer *viewer, const char *file)
{
GdkPixbuf *pix = vnc_display_get_pixbuf(VNC_DISPLAY(vnc));
GdkPixbuf *pix = virt_viewer_display_get_pixbuf(viewer->display);
gdk_pixbuf_save(pix, file, "png", NULL,
"tEXt::Generator App", PACKAGE, NULL);
gdk_pixbuf_unref(pix);
@ -587,6 +457,8 @@ static void viewer_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED, VirtViewe
{
GtkWidget *dialog;
g_return_if_fail(viewer->display != NULL);
dialog = gtk_file_chooser_dialog_new ("Save screenshot",
NULL,
GTK_FILE_CHOOSER_ACTION_SAVE,
@ -602,7 +474,7 @@ static void viewer_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED, VirtViewe
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
viewer_save_screenshot(viewer->vnc, filename);
viewer_save_screenshot(viewer, filename);
g_free (filename);
}
@ -811,37 +683,37 @@ static int viewer_extract_host(const char *uristr, char **host, char **transport
static int viewer_open_tunnel(const char **cmd)
{
int fd[2];
pid_t pid;
int fd[2];
pid_t pid;
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0)
return -1;
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0)
return -1;
pid = fork();
if (pid == -1) {
pid = fork();
if (pid == -1) {
close(fd[0]);
close(fd[1]);
return -1;
}
if (pid == 0) { /* child */
close(fd[0]);
close(0);
close(1);
if (dup(fd[1]) < 0)
_exit(1);
if (dup(fd[1]) < 0)
_exit(1);
close(fd[1]);
execvp("ssh", (char *const*)cmd);
_exit(1);
}
close(fd[1]);
if (pid == 0) { /* child */
close(fd[0]);
close(0);
close(1);
if (dup(fd[1]) < 0)
_exit(1);
if (dup(fd[1]) < 0)
_exit(1);
close(fd[1]);
execvp("ssh", (char *const*)cmd);
_exit(1);
}
close(fd[1]);
return fd[0];
}
static int viewer_open_tunnel_ssh(const char *sshhost, int sshport, const char *sshuser, const char *vncport)
static int viewer_open_tunnel_ssh(const char *sshhost, int sshport, const char *sshuser, const char *port)
{
const char *cmd[10];
char portstr[50];
@ -862,7 +734,7 @@ static int viewer_open_tunnel_ssh(const char *sshhost, int sshport, const char *
cmd[n++] = sshhost;
cmd[n++] = "nc";
cmd[n++] = "localhost";
cmd[n++] = vncport;
cmd[n++] = port;
cmd[n++] = NULL;
return viewer_open_tunnel(cmd);
@ -870,7 +742,7 @@ static int viewer_open_tunnel_ssh(const char *sshhost, int sshport, const char *
#endif /* defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) */
static void viewer_set_status(VirtViewer *viewer, const char *text)
void viewer_set_status(VirtViewer *viewer, const char *text)
{
GtkWidget *status, *notebook;
@ -882,63 +754,136 @@ static void viewer_set_status(VirtViewer *viewer, const char *text)
}
static void viewer_set_vnc(VirtViewer *viewer)
static void viewer_show_display(VirtViewer *viewer)
{
GtkWidget *notebook;
g_return_if_fail(viewer != NULL);
g_return_if_fail(viewer->display != NULL);
g_return_if_fail(viewer->display->widget != NULL);
notebook = glade_xml_get_widget(viewer->glade, "notebook");
gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 1);
gtk_widget_show(viewer->vnc);
gtk_widget_show(viewer->display->widget);
}
static void viewer_connect_info_free(VirtViewer *viewer)
{
free(viewer->host);
free(viewer->gport);
free(viewer->transport);
free(viewer->user);
viewer->host = NULL;
viewer->gport = NULL;
viewer->transport = NULL;
viewer->user = NULL;
viewer->port = 0;
}
static gboolean viewer_extract_connect_info(VirtViewer *viewer,
virDomainPtr dom)
{
char *type = NULL;
char *xpath = NULL;
gboolean retval = FALSE;
viewer_connect_info_free(viewer);
if ((type = viewer_extract_xpath_string(dom, "string(/domain/devices/graphics/@type)")) == NULL) {
viewer_simple_message_dialog(viewer->window, _("Cannot determine the graphic type for the guest %s"),
viewer->domkey);
goto cleanup;
}
if (g_strcasecmp(type, "vnc") == 0)
viewer->display = VIRT_VIEWER_DISPLAY(virt_viewer_display_vnc_new(viewer));
else if (g_strcasecmp(type, "spice") == 0)
viewer->display = VIRT_VIEWER_DISPLAY(virt_viewer_display_spice_new(viewer));
else {
viewer_simple_message_dialog(viewer->window, _("Unknown graphic type for the guest %s"),
viewer->domkey);
goto cleanup;
}
xpath = g_strdup_printf("string(/domain/devices/graphics[@type='%s']/@port)", type);
if ((viewer->gport = viewer_extract_xpath_string(dom, xpath)) == NULL) {
viewer_simple_message_dialog(viewer->window, _("Cannot determine the graphic port for the guest %s"),
viewer->domkey);
goto cleanup;
}
if (viewer_extract_host(viewer->uri, &viewer->host, &viewer->transport, &viewer->user, &viewer->port) < 0) {
viewer_simple_message_dialog(viewer->window, _("Cannot determine the host for the guest %s"),
viewer->domkey);
goto cleanup;
}
DEBUG_LOG("Remote host is %s and transport %s user %s",
viewer->host, viewer->transport ? viewer->transport : "", viewer->user ? viewer->user : "");
retval = TRUE;
cleanup:
free(xpath);
return retval;
}
void viewer_channel_open_fd(VirtViewer *viewer, VirtViewerDisplayChannel *channel)
{
#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK)
int fd = -1;
g_return_if_fail(viewer != NULL);
g_return_if_fail(viewer->display != NULL);
if (viewer->transport && g_strcasecmp(viewer->transport, "ssh") == 0 &&
!viewer->direct) {
if ((fd = viewer_open_tunnel_ssh(viewer->host, viewer->port, viewer->user, viewer->gport)) < 0)
viewer_simple_message_dialog(viewer->window, _("Connect to ssh failed."));
} else
viewer_simple_message_dialog(viewer->window, _("Can't connect to channel, SSH only supported."));
if (fd >= 0)
virt_viewer_display_channel_open_fd(viewer->display, channel, fd);
#else
viewer_simple_message_dialog(viewer->window, _("Connect to channel unsupported."));
#endif
}
static int viewer_activate(VirtViewer *viewer,
virDomainPtr dom)
{
char *vncport = NULL;
char *host = NULL;
char *transport = NULL;
char *user = NULL;
int port, fd = -1;
int fd = -1;
int ret = -1;
g_return_val_if_fail(viewer->display == NULL, -1);
if (viewer->active)
goto cleanup;
viewer_init_vnc_display(viewer);
if ((vncport = viewer_extract_xpath_string(dom, "string(/domain/devices/graphics[@type='vnc']/@port)")) == NULL) {
viewer_simple_message_dialog(viewer->window, _("Cannot determine the VNC port for the guest %s"),
viewer->domkey);
if (!viewer_extract_connect_info(viewer, dom))
goto cleanup;
}
if (viewer_extract_host(viewer->uri, &host, &transport, &user, &port) < 0) {
viewer_simple_message_dialog(viewer->window, _("Cannot determine the VNC host for the guest %s"),
viewer->domkey);
goto cleanup;
}
DEBUG_LOG("Remote host is %s and transport %s user %s",
host, transport ? transport : "", user ? user : "");
viewer->vncAddress = g_strdup_printf("%s:%s", host, vncport);
viewer->pretty_address = g_strdup_printf("%s:%s", viewer->host, viewer->gport);
#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK)
if (transport && g_strcasecmp(transport, "ssh") == 0 &&
if (viewer->transport && g_strcasecmp(viewer->transport, "ssh") == 0 &&
!viewer->direct)
if ((fd = viewer_open_tunnel_ssh(host, port, user, vncport)) < 0)
if ((fd = viewer_open_tunnel_ssh(viewer->host, viewer->port,
viewer->user, viewer->gport)) < 0)
return -1;
#endif
if (fd >= 0) {
vnc_display_open_fd(VNC_DISPLAY(viewer->vnc), fd);
ret = virt_viewer_display_open_fd(viewer->display, fd);
} else {
vnc_display_open_host(VNC_DISPLAY(viewer->vnc), host, vncport);
ret = virt_viewer_display_open_host(viewer->display,
viewer->host, viewer->gport);
}
viewer_set_status(viewer, "Connecting to VNC server");
viewer_set_status(viewer, "Connecting to graphic server");
free(viewer->domtitle);
viewer->domtitle = g_strdup(virDomainGetName(dom));
@ -947,121 +892,10 @@ static int viewer_activate(VirtViewer *viewer,
viewer->active = TRUE;
viewer_set_title(viewer, FALSE);
ret = 0;
cleanup:
free(host);
free(transport);
free(user);
free(vncport);
cleanup:
return ret;
}
static gboolean viewer_retryauth(gpointer opaque)
{
VirtViewer *viewer = opaque;
viewer_initial_connect(viewer);
return FALSE;
}
static void viewer_deactivate(VirtViewer *viewer)
{
if (!viewer->active)
return;
vnc_display_close(VNC_DISPLAY(viewer->vnc));
free(viewer->domtitle);
viewer->domtitle = NULL;
viewer->connected = FALSE;
viewer->active = FALSE;
g_free(viewer->vncAddress);
viewer->vncAddress = NULL;
viewer_set_title(viewer, FALSE);
if (viewer->authretry) {
viewer->authretry = FALSE;
g_idle_add(viewer_retryauth, viewer);
} else if (viewer->reconnect) {
if (!viewer->withEvents) {
DEBUG_LOG("No domain events, falling back to polling");
g_timeout_add(500,
viewer_connect_timer,
viewer);
}
viewer_set_status(viewer, "Waiting for guest domain to re-start");
} else {
viewer_set_status(viewer, "Guest domain has shutdown");
gtk_main_quit();
}
}
static void viewer_connected(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer->connected = TRUE;
viewer_set_status(viewer, "Connected to VNC server");
}
static void viewer_initialized(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
viewer_set_vnc(viewer);
viewer_set_title(viewer, FALSE);
}
static void viewer_disconnected(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
if (!viewer->connected) {
viewer_simple_message_dialog(viewer->window, _("Unable to connect to the VNC server %s"),
viewer->vncAddress);
}
viewer_deactivate(viewer);
}
static void viewer_vnc_auth_failure(GtkWidget *vnc G_GNUC_UNUSED, const char *reason, VirtViewer *viewer)
{
GtkWidget *dialog;
int ret;
dialog = gtk_message_dialog_new(GTK_WINDOW(viewer->window),
GTK_DIALOG_MODAL |
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_YES_NO,
_("Unable to authenticate with VNC server at %s: %s\n"
"Retry connection again?"),
viewer->vncAddress, reason);
ret = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (ret == GTK_RESPONSE_YES)
viewer->authretry = TRUE;
else
viewer->authretry = FALSE;
}
static void viewer_vnc_auth_unsupported(GtkWidget *vnc G_GNUC_UNUSED, unsigned int authType, VirtViewer *viewer)
{
viewer_simple_message_dialog(viewer->window,
_("Unable to authenticate with VNC server at %s\n"
"Unsupported authentication type %d"),
viewer->vncAddress, authType);
}
static void viewer_vnc_bell(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
{
gdk_window_beep(GTK_WIDGET(viewer->window)->window);
}
/* text was actually requested */
static void viewer_vnc_clipboard_copy(GtkClipboard *clipboard G_GNUC_UNUSED,
GtkSelectionData *data,
@ -1071,12 +905,11 @@ static void viewer_vnc_clipboard_copy(GtkClipboard *clipboard G_GNUC_UNUSED,
gtk_selection_data_set_text(data, viewer->clipboard, -1);
}
static void viewer_vnc_server_cut_text(VncDisplay *vnc G_GNUC_UNUSED,
const gchar *text, VirtViewer *viewer)
void viewer_server_cut_text(VirtViewer *viewer, const gchar *text)
{
GtkClipboard *cb;
gsize a, b;
GtkTargetEntry targets[] = {
GtkTargetEntry targets[] = {
{g_strdup("UTF8_STRING"), 0, 0},
{g_strdup("COMPOUND_TEXT"), 0, 0},
{g_strdup("TEXT"), 0, 0},
@ -1101,6 +934,69 @@ static void viewer_vnc_server_cut_text(VncDisplay *vnc G_GNUC_UNUSED,
}
}
static gboolean viewer_retryauth(gpointer opaque)
{
VirtViewer *viewer = opaque;
viewer_initial_connect(viewer);
return FALSE;
}
static void viewer_deactivate(VirtViewer *viewer)
{
if (!viewer->active)
return;
if (viewer->display)
virt_viewer_display_close(viewer->display);
free(viewer->domtitle);
viewer->domtitle = NULL;
viewer->connected = FALSE;
viewer->active = FALSE;
g_free(viewer->pretty_address);
viewer->pretty_address = NULL;
viewer_set_title(viewer, FALSE);
if (viewer->authretry) {
viewer->authretry = FALSE;
g_idle_add(viewer_retryauth, viewer);
} else if (viewer->reconnect) {
if (!viewer->withEvents) {
DEBUG_LOG("No domain events, falling back to polling");
g_timeout_add(500,
viewer_connect_timer,
viewer);
}
viewer_set_status(viewer, "Waiting for guest domain to re-start");
} else {
viewer_set_status(viewer, "Guest domain has shutdown");
gtk_main_quit();
}
}
void viewer_connected(VirtViewer *viewer)
{
viewer->connected = TRUE;
viewer_set_status(viewer, "Connected to graphic server");
}
void viewer_initialized(VirtViewer *viewer)
{
viewer_show_display(viewer);
viewer_set_title(viewer, FALSE);
}
void viewer_disconnected(VirtViewer *viewer)
{
if (!viewer->connected) {
viewer_simple_message_dialog(viewer->window, _("Unable to connect to the graphic server %s"),
viewer->pretty_address);
}
viewer_deactivate(viewer);
}
static int viewer_domain_event(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
@ -1158,13 +1054,18 @@ static int viewer_initial_connect(VirtViewer *viewer)
if (info.state == VIR_DOMAIN_SHUTOFF) {
viewer_set_status(viewer, "Waiting for guest domain to start");
} else {
if (viewer_activate(viewer, dom) < 0) {
ret = viewer_activate(viewer, dom);
if (ret < 0) {
if (viewer->waitvm) {
viewer_set_status(viewer, "Waiting for guest domain to start VNC");
viewer_set_status(viewer, "Waiting for guest domain to start server");
} else {
DEBUG_LOG("Failed to activate viewer");
goto cleanup;
}
} else if (ret == 0) {
DEBUG_LOG("Failed to activate viewer");
ret = -1;
goto cleanup;
}
}
@ -1197,72 +1098,6 @@ static void viewer_error_func (void *data G_GNUC_UNUSED, virErrorPtr error G_GNU
/* nada */
}
static void viewer_init_vnc_display(VirtViewer *viewer)
{
GtkWidget *notebook;
GtkWidget *align;
g_return_if_fail(viewer != NULL);
viewer->vnc = vnc_display_new();
vnc_display_set_keyboard_grab(VNC_DISPLAY(viewer->vnc), TRUE);
vnc_display_set_pointer_grab(VNC_DISPLAY(viewer->vnc), TRUE);
/*
* In auto-resize mode we have things setup so that we always
* automatically resize the top level window to be exactly the
* same size as the VNC desktop, except when it won't fit on
* the local screen, at which point we let it scale down.
* The upshot is, we always want scaling enabled.
* We disable force_size because we want to allow user to
* manually size the widget smaller too
*/
vnc_display_set_force_size(VNC_DISPLAY(viewer->vnc), FALSE);
vnc_display_set_scaling(VNC_DISPLAY(viewer->vnc), TRUE);
g_signal_connect(viewer->vnc, "vnc-connected",
G_CALLBACK(viewer_connected), viewer);
g_signal_connect(viewer->vnc, "vnc-initialized",
G_CALLBACK(viewer_initialized), viewer);
g_signal_connect(viewer->vnc, "vnc-disconnected",
G_CALLBACK(viewer_disconnected), viewer);
/* When VNC desktop resizes, we have to resize the containing widget */
g_signal_connect(viewer->vnc, "vnc-desktop-resize",
G_CALLBACK(viewer_resize_desktop), viewer);
g_signal_connect(viewer->vnc, "vnc-pointer-grab",
G_CALLBACK(viewer_mouse_grab), viewer);
g_signal_connect(viewer->vnc, "vnc-pointer-ungrab",
G_CALLBACK(viewer_mouse_ungrab), viewer);
g_signal_connect(viewer->vnc, "vnc-keyboard-grab",
G_CALLBACK(viewer_key_grab), viewer);
g_signal_connect(viewer->vnc, "vnc-keyboard-ungrab",
G_CALLBACK(viewer_key_ungrab), viewer);
g_signal_connect(viewer->vnc, "vnc-auth-credential",
G_CALLBACK(viewer_auth_vnc_credentials), &viewer->vncAddress);
g_signal_connect(viewer->vnc, "vnc-auth-failure",
G_CALLBACK(viewer_vnc_auth_failure), viewer);
g_signal_connect(viewer->vnc, "vnc-auth-unsupported",
G_CALLBACK(viewer_vnc_auth_unsupported), viewer);
g_signal_connect(viewer->vnc, "vnc-bell",
G_CALLBACK(viewer_vnc_bell), viewer);
g_signal_connect(viewer->vnc, "vnc-server-cut-text",
G_CALLBACK(viewer_vnc_server_cut_text), viewer);
notebook = glade_xml_get_widget(viewer->glade, "notebook");
align = glade_xml_get_widget(viewer->glade, "vnc-align");
gtk_container_add(GTK_CONTAINER(align), viewer->vnc);
if (!viewer->window) {
gtk_container_add(GTK_CONTAINER(viewer->container), GTK_WIDGET(notebook));
gtk_widget_show_all(viewer->container);
}
gtk_widget_realize(viewer->vnc);
}
int
viewer_start (const char *uri,
const char *name,
@ -1276,7 +1111,6 @@ viewer_start (const char *uri,
{
VirtViewer *viewer;
GtkWidget *notebook;
GtkWidget *align;
GtkWidget *menu;
int cred_types[] =
{ VIR_CRED_AUTHNAME, VIR_CRED_PASSPHRASE };
@ -1291,7 +1125,7 @@ viewer_start (const char *uri,
viewer = g_new0(VirtViewer, 1);
viewer->active = 0;
viewer->active = FALSE;
viewer->autoResize = TRUE;
viewer->direct = direct;
viewer->waitvm = waitvm;
@ -1347,9 +1181,6 @@ viewer_start (const char *uri,
notebook = glade_xml_get_widget(viewer->glade, "notebook");
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
align = glade_xml_get_widget(viewer->glade, "vnc-align");
g_signal_connect(align, "size-allocate",
G_CALLBACK(viewer_resize_align), viewer);
if (container) {
viewer->container = container;
@ -1359,7 +1190,7 @@ viewer_start (const char *uri,
viewer->container = window;
viewer->window = window;
g_signal_connect(window, "delete-event",
G_CALLBACK(viewer_shutdown), viewer);
G_CALLBACK(viewer_delete), viewer);
gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
viewer->accelEnabled = TRUE;
accels = gtk_accel_groups_from_object(G_OBJECT(window));

View File

@ -309,7 +309,7 @@
</packing>
</child>
<child>
<widget class="GtkAlignment" id="vnc-align">
<widget class="GtkAlignment" id="display-align">
<property name="visible">True</property>
<property name="xscale">0</property>
<property name="yscale">0</property>