mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/virt-viewer
synced 2026-01-07 11:24:16 +00:00
viewer: Add support for Spice
This commit is contained in:
parent
882ac10d52
commit
155a03f9c8
1
AUTHORS
1
AUTHORS
@ -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...
|
||||
|
||||
|
||||
@ -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])
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
man_MANS = virt-viewer.1
|
||||
|
||||
EXTRA_DIST = virt-viewer.pod
|
||||
DISTCLEANFILES = $(man_MANS)
|
||||
|
||||
%.1: %.pod
|
||||
pod2man $< > $@
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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@ \
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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
281
src/display-spice.c
Normal 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
78
src/display-spice.h
Normal 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
333
src/display-vnc.c
Normal 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
75
src/display-vnc.h
Normal 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
90
src/display.c
Normal 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
91
src/display.h
Normal 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
123
src/viewer-priv.h
Normal 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:
|
||||
*/
|
||||
721
src/viewer.c
721
src/viewer.c
@ -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));
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user