summaryrefslogtreecommitdiffstats
path: root/src/display-vnc.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2010-11-30 13:59:01 +0100
committerMarc-André Lureau <marcandre.lureau@redhat.com>2010-11-30 13:59:01 +0100
commit155a03f9c83ade6b849dca401f5c176bccf4123a (patch)
treea16200eecf836e145fd34e328c9881bbba93cb00 /src/display-vnc.c
parent882ac10d527d89ba643f38ec4460438a012fcb27 (diff)
downloadvirt-viewer-155a03f9c83ade6b849dca401f5c176bccf4123a.tar.gz
virt-viewer-155a03f9c83ade6b849dca401f5c176bccf4123a.tar.xz
virt-viewer-155a03f9c83ade6b849dca401f5c176bccf4123a.zip
viewer: Add support for Spice
Diffstat (limited to 'src/display-vnc.c')
-rw-r--r--src/display-vnc.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/display-vnc.c b/src/display-vnc.c
new file mode 100644
index 0000000..96bc382
--- /dev/null
+++ b/src/display-vnc.c
@@ -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:
+ */