[virt-tools-list] [PATCH 4 of 5] viewer: Add support for Spice
Marc-André Lureau
marcandre.lureau at redhat.com
Tue Nov 30 15:08:32 UTC 2010
# HG changeset patch
# User Marc-André Lureau <marcandre.lureau at redhat.com>
# Date 1291121941 -3600
# Node ID 4ac66a955d7bf718ce85e8ffd0be00f0c4ad8ac6
# Parent 9f8a6e933516586fc82982cffb4721f5539c9d2f
viewer: Add support for Spice
diff -r 9f8a6e933516 -r 4ac66a955d7b AUTHORS
--- a/AUTHORS Fri Nov 19 18:09:42 2010 +0100
+++ b/AUTHORS Tue Nov 30 13:59:01 2010 +0100
@@ -13,6 +13,7 @@
Guido G\374nther <agx-at-sigxcpu-dot-org>
Hiroyuki Kaguchi <fj7025cf-at-aa-dot-jp-dot-fujitsu-dot-com>
Ronnie Sahlberg <ronniesahlberg at gmail.com>
+ Marc-André Lureau <marcandre.lureau-at-redhat-dot-com>
...send patches to get your name here...
diff -r 9f8a6e933516 -r 4ac66a955d7b configure.ac
--- a/configure.ac Fri Nov 19 18:09:42 2010 +0100
+++ b/configure.ac Tue Nov 30 13:59:01 2010 +0100
@@ -33,6 +33,7 @@
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])
diff -r 9f8a6e933516 -r 4ac66a955d7b man/Makefile.am
--- a/man/Makefile.am Fri Nov 19 18:09:42 2010 +0100
+++ b/man/Makefile.am Tue Nov 30 13:59:01 2010 +0100
@@ -2,6 +2,7 @@
man_MANS = virt-viewer.1
EXTRA_DIST = virt-viewer.pod
+DISTCLEANFILES = $(man_MANS)
%.1: %.pod
pod2man $< > $@
diff -r 9f8a6e933516 -r 4ac66a955d7b man/virt-viewer.pod
--- a/man/virt-viewer.pod Fri Nov 19 18:09:42 2010 +0100
+++ b/man/virt-viewer.pod Tue Nov 30 13:59:01 2010 +0100
@@ -10,12 +10,13 @@
=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 @@
=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
diff -r 9f8a6e933516 -r 4ac66a955d7b po/POTFILES.in
--- a/po/POTFILES.in Fri Nov 19 18:09:42 2010 +0100
+++ b/po/POTFILES.in Tue Nov 30 13:59:01 2010 +0100
@@ -3,6 +3,8 @@
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
diff -r 9f8a6e933516 -r 4ac66a955d7b src/Makefile.am
--- a/src/Makefile.am Fri Nov 19 18:09:42 2010 +0100
+++ b/src/Makefile.am Tue Nov 30 13:59:01 2010 +0100
@@ -11,10 +11,15 @@
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_CFLAGS = \
@GTKVNC_CFLAGS@ \
+ @SPICEGTK_CFLAGS@ \
@GTK2_CFLAGS@ \
@LIBXML2_CFLAGS@ \
@LIBGLADE2_CFLAGS@ \
diff -r 9f8a6e933516 -r 4ac66a955d7b src/auth.c
--- a/src/auth.c Fri Nov 19 18:09:42 2010 +0100
+++ b/src/auth.c Tue Nov 30 13:59:01 2010 +0100
@@ -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");
diff -r 9f8a6e933516 -r 4ac66a955d7b src/auth.h
--- a/src/auth.h Fri Nov 19 18:09:42 2010 +0100
+++ b/src/auth.h Tue Nov 30 13:59:01 2010 +0100
@@ -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);
diff -r 9f8a6e933516 -r 4ac66a955d7b src/display-spice.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/display-spice.c Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/display-spice.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/display-spice.h Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/display-vnc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/display-vnc.c Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/display-vnc.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/display-vnc.h Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/display.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/display.c Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/display.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/display.h Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/viewer-priv.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer-priv.h Tue Nov 30 13:59:01 2010 +0100
@@ -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 at 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:
+ */
diff -r 9f8a6e933516 -r 4ac66a955d7b src/viewer.c
--- a/src/viewer.c Fri Nov 19 18:09:42 2010 +0100
+++ b/src/viewer.c Tue Nov 30 13:59:01 2010 +0100
@@ -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 @@
}
+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
@@ -241,72 +206,12 @@
/*
- * 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 @@
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 @@
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 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_enable_modifiers(VirtViewer *viewer)
+void viewer_enable_modifiers(VirtViewer *viewer)
{
GtkSettings *settings = gtk_settings_get_default();
GSList *accels;
@@ -495,38 +380,23 @@
viewer->accelEnabled = TRUE;
}
+void viewer_quit(VirtViewer *viewer)
+{
+ g_return_if_fail(viewer != NULL);
-
-static void viewer_mouse_grab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
-{
- viewer_set_title(viewer, TRUE);
+ if (viewer->display)
+ virt_viewer_display_close(viewer->display);
+ gtk_main_quit();
}
-static void viewer_mouse_ungrab(GtkWidget *vnc G_GNUC_UNUSED, VirtViewer *viewer)
+static void viewer_delete(GtkWidget *src G_GNUC_UNUSED, void *dummy 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));
- gtk_main_quit();
+ 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_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 @@
{
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 @@
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_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 @@
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 @@
#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_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 (!viewer_extract_connect_info(viewer, dom))
+ goto cleanup;
- 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);
- 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 @@
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 @@
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 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 @@
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 @@
/* 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 @@
{
VirtViewer *viewer;
GtkWidget *notebook;
- GtkWidget *align;
GtkWidget *menu;
int cred_types[] =
{ VIR_CRED_AUTHNAME, VIR_CRED_PASSPHRASE };
@@ -1291,7 +1125,7 @@
viewer = g_new0(VirtViewer, 1);
- viewer->active = 0;
+ viewer->active = FALSE;
viewer->autoResize = TRUE;
viewer->direct = direct;
viewer->waitvm = waitvm;
@@ -1347,9 +1181,6 @@
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->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));
diff -r 9f8a6e933516 -r 4ac66a955d7b src/viewer.glade
--- a/src/viewer.glade Fri Nov 19 18:09:42 2010 +0100
+++ b/src/viewer.glade Tue Nov 30 13:59:01 2010 +0100
@@ -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>
More information about the virt-tools-list
mailing list