From f3fa999769afbd1463597b5cb0483f5072ce66d8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 1 Jul 2011 16:12:20 +0100 Subject: Introduce standard naming convention to files & methods All source files must be named virt-viewer-XXXX All methods named virt_viewer_XXX --- configure.ac | 2 +- mingw32-virt-viewer.spec.in | 6 +- plugin/Makefile.am | 8 +- src/Makefile.am | 23 +- src/about.xml | 56 -- src/auth.c | 231 ------ src/auth.h | 39 - src/auth.xml | 127 ---- src/display-spice.c | 379 ---------- src/display-spice.h | 78 -- src/display-vnc.c | 329 --------- src/display-vnc.h | 75 -- src/display.c | 90 --- src/display.h | 91 --- src/events.c | 317 --------- src/events.h | 30 - src/main.c | 122 ---- src/util.c | 61 -- src/util.h | 37 - src/viewer-priv.h | 131 ---- src/viewer.c | 1410 ------------------------------------ src/viewer.h | 38 - src/viewer.xml | 291 -------- src/virt-viewer-about.xml | 56 ++ src/virt-viewer-auth.c | 237 +++++++ src/virt-viewer-auth.h | 43 ++ src/virt-viewer-auth.xml | 127 ++++ src/virt-viewer-display-spice.c | 405 +++++++++++ src/virt-viewer-display-spice.h | 78 ++ src/virt-viewer-display-vnc.c | 359 ++++++++++ src/virt-viewer-display-vnc.h | 75 ++ src/virt-viewer-display.c | 90 +++ src/virt-viewer-display.h | 92 +++ src/virt-viewer-events.c | 317 +++++++++ src/virt-viewer-events.h | 30 + src/virt-viewer-main.c | 122 ++++ src/virt-viewer-priv.h | 131 ++++ src/virt-viewer-util.c | 61 ++ src/virt-viewer-util.h | 37 + src/virt-viewer.c | 1496 +++++++++++++++++++++++++++++++++++++++ src/virt-viewer.h | 38 + src/virt-viewer.xml | 291 ++++++++ virt-viewer.spec.in | 6 +- 43 files changed, 4109 insertions(+), 3953 deletions(-) delete mode 100644 src/about.xml delete mode 100644 src/auth.c delete mode 100644 src/auth.h delete mode 100644 src/auth.xml delete mode 100644 src/display-spice.c delete mode 100644 src/display-spice.h delete mode 100644 src/display-vnc.c delete mode 100644 src/display-vnc.h delete mode 100644 src/display.c delete mode 100644 src/display.h delete mode 100644 src/events.c delete mode 100644 src/events.h delete mode 100644 src/main.c delete mode 100644 src/util.c delete mode 100644 src/util.h delete mode 100644 src/viewer-priv.h delete mode 100644 src/viewer.c delete mode 100644 src/viewer.h delete mode 100644 src/viewer.xml create mode 100644 src/virt-viewer-about.xml create mode 100644 src/virt-viewer-auth.c create mode 100644 src/virt-viewer-auth.h create mode 100644 src/virt-viewer-auth.xml create mode 100644 src/virt-viewer-display-spice.c create mode 100644 src/virt-viewer-display-spice.h create mode 100644 src/virt-viewer-display-vnc.c create mode 100644 src/virt-viewer-display-vnc.h create mode 100644 src/virt-viewer-display.c create mode 100644 src/virt-viewer-display.h create mode 100644 src/virt-viewer-events.c create mode 100644 src/virt-viewer-events.h create mode 100644 src/virt-viewer-main.c create mode 100644 src/virt-viewer-priv.h create mode 100644 src/virt-viewer-util.c create mode 100644 src/virt-viewer-util.h create mode 100644 src/virt-viewer.c create mode 100644 src/virt-viewer.h create mode 100644 src/virt-viewer.xml diff --git a/configure.ac b/configure.ac index 004dd70..b1d3377 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_INIT(virt-viewer, 0.3.1) -AC_CONFIG_SRCDIR(src/main.c) +AC_CONFIG_SRCDIR(src/virt-viewer-main.c) AM_CONFIG_HEADER(config.h) dnl Make automake keep quiet about wildcards & other GNUmake-isms AM_INIT_AUTOMAKE([-Wno-portability]) diff --git a/mingw32-virt-viewer.spec.in b/mingw32-virt-viewer.spec.in index 04dba9e..531fbb9 100644 --- a/mingw32-virt-viewer.spec.in +++ b/mingw32-virt-viewer.spec.in @@ -55,9 +55,9 @@ rm -rf $RPM_BUILD_ROOT %dir %{_mingw32_datadir}/virt-viewer/ %dir %{_mingw32_datadir}/virt-viewer/ui/ -%{_mingw32_datadir}/virt-viewer/ui/about.xml -%{_mingw32_datadir}/virt-viewer/ui/auth.xml -%{_mingw32_datadir}/virt-viewer/ui/viewer.xml +%{_mingw32_datadir}/virt-viewer/ui/virt-viewer.xml +%{_mingw32_datadir}/virt-viewer/ui/virt-viewer-about.xml +%{_mingw32_datadir}/virt-viewer/ui/virt-viewer-auth.xml %{_mingw32_mandir}/man1/virt-viewer.1* diff --git a/plugin/Makefile.am b/plugin/Makefile.am index 93284cc..34dbd02 100644 --- a/plugin/Makefile.am +++ b/plugin/Makefile.am @@ -4,10 +4,10 @@ plugindir = $(libdir)/mozilla/plugins plugin_LTLIBRARIES = virt-viewer-plugin.la virt_viewer_plugin_la_SOURCES = \ - ../src/util.c ../src/util.h \ - ../src/auth.c ../src/auth.h \ - ../src/viewer.c ../src/viewer.h \ - ../src/events.c ../src/events.h \ + ../src/virt-viewer-util.c ../src/virt-viewer-util.h \ + ../src/virt-viewer-auth.c ../src/virt-viewer-auth.h \ + ../src/virt-viewer.c ../src/virt-viewer.h \ + ../src/virt-viewer-events.c ../src/virt-viewer-events.h \ virt-viewer-plugin.c virt-viewer-plugin.h \ npshell.c npunix.c virt_viewer_plugin_la_LIBADD = \ diff --git a/src/Makefile.am b/src/Makefile.am index 2f5b955..ba8ab92 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,19 +2,22 @@ bin_PROGRAMS = virt-viewer builderxmldir = $(pkgdatadir)/ui -builderxml_DATA = viewer.xml about.xml auth.xml +builderxml_DATA = \ + virt-viewer.xml \ + virt-viewer-about.xml \ + virt-viewer-auth.xml EXTRA_DIST = $(builderxml_DATA) virt_viewer_SOURCES = \ - main.c \ - util.h util.c \ - auth.h auth.c \ - events.h events.c \ - viewer.h viewer.c \ - viewer-priv.h \ - display.h display.c \ - display-vnc.h display-vnc.c \ + virt-viewer-main.c \ + virt-viewer-util.h virt-viewer-util.c \ + virt-viewer-auth.h virt-viewer-auth.c \ + virt-viewer-events.h virt-viewer-events.c \ + virt-viewer.h virt-viewer.c \ + virt-viewer-priv.h \ + virt-viewer-display.h virt-viewer-display.c \ + virt-viewer-display-vnc.h virt-viewer-display-vnc.c \ view/autoDrawer.c \ view/autoDrawer.h \ view/drawer.c \ @@ -25,7 +28,7 @@ virt_viewer_SOURCES = \ if HAVE_SPICE_GTK virt_viewer_SOURCES += \ - display-spice.h display-spice.c + virt-viewer-display-spice.h virt-viewer-display-spice.c endif virt_viewer_LDADD = \ diff --git a/src/about.xml b/src/about.xml deleted file mode 100644 index c7978a9..0000000 --- a/src/about.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - 5 - About Glade - False - center-on-parent - dialog - Virtual Machine Viewer - Copyright 2007-2008 Daniel P. Berrange -Copyright 2007-2008 Red Hat, Inc. - A remote desktop client built with GTK-VNC and libvirt - http://virt-manager.org/ - virt-manager.org - 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 - - Daniel P. Berrange - The Fedora Translation Team - - - - - True - 2 - - - - - - True - end - - - False - end - 0 - - - - - - diff --git a/src/auth.c b/src/auth.c deleted file mode 100644 index 3625bc1..0000000 --- a/src/auth.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Virt Viewer: A virtual machine console viewer - * - * Copyright (C) 2007-2009 Red Hat, - * - * 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 - */ - -#include - -#include -#include -#include - -#include "auth.h" - - -int viewer_auth_collect_credentials(const char *type, const char *address, - char **username, char **password) -{ - GtkWidget *dialog = NULL; - GtkBuilder *creds = viewer_load_ui("auth.xml"); - GtkWidget *credUsername; - GtkWidget *credPassword; - GtkWidget *promptUsername; - GtkWidget *promptPassword; - GtkWidget *labelMessage; - int response; - char *message; - - dialog = GTK_WIDGET(gtk_builder_get_object(creds, "auth")); - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); - - labelMessage = GTK_WIDGET(gtk_builder_get_object(creds, "message")); - credUsername = GTK_WIDGET(gtk_builder_get_object(creds, "cred-username")); - promptUsername = GTK_WIDGET(gtk_builder_get_object(creds, "prompt-username")); - credPassword = GTK_WIDGET(gtk_builder_get_object(creds, "cred-password")); - promptPassword = GTK_WIDGET(gtk_builder_get_object(creds, "prompt-password")); - - gtk_widget_set_sensitive(credUsername, username != NULL); - gtk_widget_set_sensitive(promptUsername, username != NULL); - gtk_widget_set_sensitive(credPassword, password != NULL); - gtk_widget_set_sensitive(promptPassword, password != NULL); - - if (address) { - message = g_strdup_printf("Authentication is required for the %s connection to:\n\n" - "%s\n\n", - type, - address ? address : "[unknown]"); - } else { - message = g_strdup_printf("Authentication is required for the %s connection:\n", - type); - } - - gtk_label_set_markup(GTK_LABEL(labelMessage), message); - g_free(message); - - gtk_widget_show_all(dialog); - response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_hide(dialog); - - if (response == GTK_RESPONSE_OK) { - if (username) - *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(credUsername))); - if (password) - *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(credPassword))); - } - - gtk_widget_destroy(GTK_WIDGET(dialog)); - - return response == GTK_RESPONSE_OK ? 0 : -1; -} - -void viewer_auth_vnc_credentials(GtkWidget *vnc, GValueArray *credList, char **vncAddress) -{ - char *username = NULL, *password = NULL; - gboolean wantPassword = FALSE, wantUsername = FALSE; - int i; - - DEBUG_LOG("Got VNC credential request for %d credential(s)", credList->n_values); - - for (i = 0 ; i < credList->n_values ; i++) { - GValue *cred = g_value_array_get_nth(credList, i); - switch (g_value_get_enum(cred)) { - case VNC_DISPLAY_CREDENTIAL_USERNAME: - wantUsername = TRUE; - break; - case VNC_DISPLAY_CREDENTIAL_PASSWORD: - wantPassword = TRUE; - break; - case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: - break; - default: - DEBUG_LOG("Unsupported credential type %d", g_value_get_enum(cred)); - vnc_display_close(VNC_DISPLAY(vnc)); - goto cleanup; - } - } - - if (wantUsername || wantPassword) { - int ret = viewer_auth_collect_credentials("VNC", vncAddress ? *vncAddress : NULL, - wantUsername ? &username : NULL, - wantPassword ? &password : NULL); - - if (ret < 0) { - vnc_display_close(VNC_DISPLAY(vnc)); - goto cleanup; - } - } - - for (i = 0 ; i < credList->n_values ; i++) { - GValue *cred = g_value_array_get_nth(credList, i); - switch (g_value_get_enum(cred)) { - case VNC_DISPLAY_CREDENTIAL_USERNAME: - if (!username || - vnc_display_set_credential(VNC_DISPLAY(vnc), - g_value_get_enum(cred), - username)) { - DEBUG_LOG("Failed to set credential type %d", g_value_get_enum(cred)); - vnc_display_close(VNC_DISPLAY(vnc)); - } - break; - case VNC_DISPLAY_CREDENTIAL_PASSWORD: - if (!password || - vnc_display_set_credential(VNC_DISPLAY(vnc), - g_value_get_enum(cred), - password)) { - DEBUG_LOG("Failed to set credential type %d", g_value_get_enum(cred)); - vnc_display_close(VNC_DISPLAY(vnc)); - } - break; - case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: - if (vnc_display_set_credential(VNC_DISPLAY(vnc), - g_value_get_enum(cred), - "libvirt")) { - DEBUG_LOG("Failed to set credential type %d", g_value_get_enum(cred)); - vnc_display_close(VNC_DISPLAY(vnc)); - } - break; - default: - DEBUG_LOG("Unsupported credential type %d", g_value_get_enum(cred)); - vnc_display_close(VNC_DISPLAY(vnc)); - } - } - - cleanup: - g_free(username); - g_free(password); -} - - - -int -viewer_auth_libvirt_credentials(virConnectCredentialPtr cred, - unsigned int ncred, - void *cbdata) -{ - char **username = NULL, **password = NULL; - const char *uri = cbdata; - int i; - int ret = -1; - - DEBUG_LOG("Got libvirt credential request for %d credential(s)", ncred); - - for (i = 0 ; i < ncred ; i++) { - switch (cred[i].type) { - case VIR_CRED_USERNAME: - case VIR_CRED_AUTHNAME: - username = &cred[i].result; - break; - case VIR_CRED_PASSPHRASE: - password = &cred[i].result; - break; - default: - DEBUG_LOG("Unsupported libvirt credential %d", cred[i].type); - return -1; - } - } - - if (username || password) { - ret = viewer_auth_collect_credentials("libvirt", uri, - username, password); - if (ret < 0) - goto cleanup; - } else { - ret = 0; - } - - for (i = 0 ; i < ncred ; i++) { - switch (cred[i].type) { - case VIR_CRED_AUTHNAME: - case VIR_CRED_USERNAME: - case VIR_CRED_PASSPHRASE: - if (cred[i].result) - cred[i].resultlen = strlen(cred[i].result); - else - cred[i].resultlen = 0; - DEBUG_LOG("Got '%s' %d %d", cred[i].result, cred[i].resultlen, cred[i].type); - break; - } - } - - cleanup: - DEBUG_LOG("Return %d", ret); - return ret; -} - - - - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/src/auth.h b/src/auth.h deleted file mode 100644 index 18d9a13..0000000 --- a/src/auth.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Virt Viewer: A virtual machine console viewer - * - * Copyright (C) 2007-2009 Red Hat, - * - * 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 - */ - -#ifndef VIRT_VIEWER_AUTH_H -#define VIRT_VIEWER_AUTH_H - -#include - -#include "util.h" - -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); - -#endif diff --git a/src/auth.xml b/src/auth.xml deleted file mode 100644 index f45143d..0000000 --- a/src/auth.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - 5 - Authentication required - center-on-parent - dialog - - - True - 2 - - - True - 0 - 0 - label - True - - - 1 - - - - - True - 2 - 2 - 6 - 6 - - - True - 1 - Password: - - - 1 - 2 - - - - - True - 1 - Username: - - - - - True - True - - - 1 - 2 - - - - - True - True - False - - - 1 - 2 - 1 - 2 - - - - - 2 - - - - - True - end - - - gtk-cancel - True - True - True - True - - - False - False - 0 - - - - - gtk-ok - True - True - True - True - True - True - - - False - False - 3 - - - - - False - end - 0 - - - - - - button-cancel - button-ok - - - diff --git a/src/display-spice.c b/src/display-spice.c deleted file mode 100644 index 6ff764e..0000000 --- a/src/display-spice.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * 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 - */ - -#include -#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); -} - - -/* - * 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) -{ - gtk_widget_queue_resize(viewer->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(SpiceChannel *channel G_GNUC_UNUSED, gint format G_GNUC_UNUSED, - gint width, gint height, gint stride G_GNUC_UNUSED, - gint shmid G_GNUC_UNUSED, gpointer imgdata G_GNUC_UNUSED, - VirtViewer *viewer) -{ - 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; - } - - if (viewer->desktopWidth == 0 || viewer->desktopHeight == 0) - desktopAspect = 1; - else - 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; -} - -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; - - g_signal_connect(channel, "display-primary-create", - G_CALLBACK(viewer_resize_desktop), display->viewer); - - self->display = spice_display_new(s, id); - display->widget = GTK_WIDGET(self->display); - g_object_set(self->display, - "grab-keyboard", TRUE, - "grab-mouse", TRUE, - "resize-guest", FALSE, - "scaling", TRUE, - "auto-clipboard", TRUE, - NULL); - viewer_add_display_and_realize(display->viewer); - - g_signal_connect(display->viewer->align, "size-allocate", - G_CALLBACK(viewer_resize_align), 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 --git a/src/display-spice.h b/src/display-spice.h deleted file mode 100644 index d1da86b..0000000 --- a/src/display-spice.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 - */ -#ifndef _VIRT_VIEWER_DISPLAY_SPICE_H -#define _VIRT_VIEWER_DISPLAY_SPICE_H - -#include -#include -#include - -#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 --git a/src/display-vnc.c b/src/display-vnc.c deleted file mode 100644 index f3afd46..0000000 --- a/src/display-vnc.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * 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 - */ - -#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) -{ - gtk_widget_queue_resize(viewer->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; - - 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); - - g_signal_connect(viewer->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 --git a/src/display-vnc.h b/src/display-vnc.h deleted file mode 100644 index 15a7d5b..0000000 --- a/src/display-vnc.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 - */ -#ifndef _VIRT_VIEWER_DISPLAY_VNC_H -#define _VIRT_VIEWER_DISPLAY_VNC_H - -#include -#include - -#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 --git a/src/display.c b/src/display.c deleted file mode 100644 index 2d95a58..0000000 --- a/src/display.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 - */ -#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 --git a/src/display.h b/src/display.h deleted file mode 100644 index 45931b4..0000000 --- a/src/display.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 - */ -#ifndef _VIRT_VIEWER_DISPLAY_H -#define _VIRT_VIEWER_DISPLAY_H - -#include -#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 --git a/src/events.c b/src/events.c deleted file mode 100644 index 9f893be..0000000 --- a/src/events.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * events.c: event loop integration - * - * Copyright (C) 2008-2009 Daniel P. Berrange - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Daniel P. Berrange - */ - - -#include -#include -#include -#include -#include - -#include "events.h" - -struct viewer_event_handle -{ - int watch; - int fd; - int events; - int enabled; - GIOChannel *channel; - guint source; - virEventHandleCallback cb; - void *opaque; - virFreeCallback ff; -}; - -static int nextwatch = 1; -static unsigned int nhandles = 0; -static struct viewer_event_handle **handles = NULL; - -static gboolean -viewer_event_dispatch_handle(GIOChannel *source G_GNUC_UNUSED, - GIOCondition condition, - gpointer opaque) -{ - struct viewer_event_handle *data = opaque; - int events = 0; - - if (condition & G_IO_IN) - events |= VIR_EVENT_HANDLE_READABLE; - if (condition & G_IO_OUT) - events |= VIR_EVENT_HANDLE_WRITABLE; - if (condition & G_IO_HUP) - events |= VIR_EVENT_HANDLE_HANGUP; - if (condition & G_IO_ERR) - events |= VIR_EVENT_HANDLE_ERROR; - - DEBUG_LOG("Dispatch handler %d %d %p\n", data->fd, events, data->opaque); - - (data->cb)(data->watch, data->fd, events, data->opaque); - - return TRUE; -} - - -static -int viewer_event_add_handle(int fd, - int events, - virEventHandleCallback cb, - void *opaque, - virFreeCallback ff) -{ - struct viewer_event_handle *data; - GIOCondition cond = 0; - - handles = g_realloc(handles, sizeof(*handles)*(nhandles+1)); - data = g_malloc(sizeof(*data)); - memset(data, 0, sizeof(*data)); - - if (events & VIR_EVENT_HANDLE_READABLE) - cond |= G_IO_IN; - if (events & VIR_EVENT_HANDLE_WRITABLE) - cond |= G_IO_OUT; - - data->watch = nextwatch++; - data->fd = fd; - data->events = events; - data->cb = cb; - data->opaque = opaque; - data->channel = g_io_channel_unix_new(fd); - data->ff = ff; - - DEBUG_LOG("Add handle %d %d %p\n", data->fd, events, data->opaque); - - data->source = g_io_add_watch(data->channel, - cond, - viewer_event_dispatch_handle, - data); - - handles[nhandles++] = data; - - return data->watch; -} - -static struct viewer_event_handle * -viewer_event_find_handle(int watch) -{ - unsigned int i; - for (i = 0 ; i < nhandles ; i++) - if (handles[i]->watch == watch) - return handles[i]; - - return NULL; -} - -static void -viewer_event_update_handle(int watch, - int events) -{ - struct viewer_event_handle *data = viewer_event_find_handle(watch); - - if (!data) { - DEBUG_LOG("Update for missing handle watch %d", watch); - return; - } - - if (events) { - GIOCondition cond = 0; - if (events == data->events) - return; - - if (data->source) - g_source_remove(data->source); - - cond |= G_IO_HUP; - if (events & VIR_EVENT_HANDLE_READABLE) - cond |= G_IO_IN; - if (events & VIR_EVENT_HANDLE_WRITABLE) - cond |= G_IO_OUT; - data->source = g_io_add_watch(data->channel, - cond, - viewer_event_dispatch_handle, - data); - data->events = events; - } else { - if (!data->source) - return; - - g_source_remove(data->source); - data->source = 0; - data->events = 0; - } -} - -static int -viewer_event_remove_handle(int watch) -{ - struct viewer_event_handle *data = viewer_event_find_handle(watch); - - if (!data) { - DEBUG_LOG("Remove of missing watch %d", watch); - return -1; - } - - DEBUG_LOG("Remove handle %d %d\n", watch, data->fd); - - g_source_remove(data->source); - data->source = 0; - data->events = 0; - if (data->ff) - (data->ff)(data->opaque); - free(data); - - return 0; -} - -struct viewer_event_timeout -{ - int timer; - int interval; - guint source; - virEventTimeoutCallback cb; - void *opaque; - virFreeCallback ff; -}; - - -static int nexttimer = 1; -static unsigned int ntimeouts = 0; -static struct viewer_event_timeout **timeouts = NULL; - -static gboolean -viewer_event_dispatch_timeout(void *opaque) -{ - struct viewer_event_timeout *data = opaque; - DEBUG_LOG("Dispatch timeout %p %p %d %p\n", data, data->cb, data->timer, data->opaque); - (data->cb)(data->timer, data->opaque); - - return TRUE; -} - -static int -viewer_event_add_timeout(int interval, - virEventTimeoutCallback cb, - void *opaque, - virFreeCallback ff) -{ - struct viewer_event_timeout *data; - - timeouts = g_realloc(timeouts, sizeof(*timeouts)*(ntimeouts+1)); - data = g_malloc(sizeof(*data)); - memset(data, 0, sizeof(*data)); - - data->timer = nexttimer++; - data->interval = interval; - data->cb = cb; - data->opaque = opaque; - data->ff = ff; - if (interval >= 0) - data->source = g_timeout_add(interval, - viewer_event_dispatch_timeout, - data); - - timeouts[ntimeouts++] = data; - - DEBUG_LOG("Add timeout %p %d %p %p %d\n", data, interval, cb, opaque, data->timer); - - return data->timer; -} - - -static struct viewer_event_timeout * -viewer_event_find_timeout(int timer) -{ - unsigned int i; - for (i = 0 ; i < ntimeouts ; i++) - if (timeouts[i]->timer == timer) - return timeouts[i]; - - return NULL; -} - - -static void -viewer_event_update_timeout(int timer, - int interval) -{ - struct viewer_event_timeout *data = viewer_event_find_timeout(timer); - - if (!data) { - DEBUG_LOG("Update of missing timer %d", timer); - return; - } - - DEBUG_LOG("Update timeout %p %d %d\n", data, timer, interval); - - if (interval >= 0) { - if (data->source) - return; - - data->interval = interval; - data->source = g_timeout_add(data->interval, - viewer_event_dispatch_timeout, - data); - } else { - if (!data->source) - return; - - g_source_remove(data->source); - data->source = 0; - } -} - -static int -viewer_event_remove_timeout(int timer) -{ - struct viewer_event_timeout *data = viewer_event_find_timeout(timer); - - if (!data) { - DEBUG_LOG("Remove of missing timer %d", timer); - return -1; - } - - DEBUG_LOG("Remove timeout %p %d\n", data, timer); - - if (!data->source) - return -1; - - g_source_remove(data->source); - data->source = 0; - - if (data->ff) - (data->ff)(data->opaque); - - free(data); - - return 0; -} - - -void viewer_event_register(void) { - virEventRegisterImpl(viewer_event_add_handle, - viewer_event_update_handle, - viewer_event_remove_handle, - viewer_event_add_timeout, - viewer_event_update_timeout, - viewer_event_remove_timeout); -} - diff --git a/src/events.h b/src/events.h deleted file mode 100644 index 02a7345..0000000 --- a/src/events.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * events.h: event loop integration - * - * Copyright (C) 2008-2009 Daniel P. Berrange - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Daniel P. Berrange - */ - -#ifndef VIRT_VIEWER_EVENT_H -#define VIRT_VIEWER_EVENT_H - -#include "util.h" - -void viewer_event_register(void); - -#endif diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 9f841b3..0000000 --- a/src/main.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Virt Viewer: A virtual machine console viewer - * - * Copyright (C) 2007 Red Hat, - * - * 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 - */ - -#include -#include -#include -#include -#include -#include - -#include "viewer.h" - -static void viewer_version(void) -{ - g_print(_("%s version %s\n"), PACKAGE, VERSION); - - exit(0); -} - - -int main(int argc, char **argv) -{ - GOptionContext *context; - GError *error = NULL; - int ret; - char *uri = NULL; - int zoom = 100; - gchar **args = NULL; - gboolean verbose = FALSE; - gboolean debug = FALSE; - gboolean direct = FALSE; - gboolean waitvm = FALSE; - gboolean reconnect = FALSE; - const char *help_msg = N_("Run '" PACKAGE " --help' to see a full list of available command line options"); - const GOptionEntry options [] = { - { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - viewer_version, N_("display version information"), NULL }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - N_("display verbose information"), NULL }, - { "direct", 'd', 0, G_OPTION_ARG_NONE, &direct, - N_("direct connection with no automatic tunnels"), NULL }, - { "connect", 'c', 0, G_OPTION_ARG_STRING, &uri, - N_("connect to hypervisor"), "URI"}, - { "wait", 'w', 0, G_OPTION_ARG_NONE, &waitvm, - N_("wait for domain to start"), NULL }, - { "reconnect", 'r', 0, G_OPTION_ARG_NONE, &reconnect, - N_("reconnect to domain upon restart"), NULL }, - { "zoom", 'z', 0, G_OPTION_ARG_INT, &zoom, - N_("Zoom level of window, in percentage"), "ZOOM" }, - { "debug", '\0', 0, G_OPTION_ARG_NONE, &debug, - N_("display debugging information"), NULL }, - { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args, - NULL, "DOMAIN-NAME|ID|UUID" }, - { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } - }; - - setlocale(LC_ALL, ""); - bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR); - bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); - textdomain(GETTEXT_PACKAGE); - - /* Setup command line options */ - context = g_option_context_new (_("- Virtual machine graphical console")); - g_option_context_add_main_entries (context, options, NULL); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - g_option_context_add_group (context, vnc_display_get_option_group ()); - g_option_context_parse (context, &argc, &argv, &error); - if (error) { - g_printerr("%s\n%s\n", - error->message, - gettext(help_msg)); - g_error_free(error); - return 1; - } - - g_option_context_free(context); - - if (!args || (g_strv_length(args) != 1)) { - fprintf(stderr, _("\nUsage: %s [OPTIONS] DOMAIN-NAME|ID|UUID\n\n%s\n\n"), argv[0], help_msg); - return 1; - } - - if (zoom < 10 || zoom > 200) { - fprintf(stderr, "Zoom level must be within 10-200\n"); - return 1; - } - - ret = viewer_start (uri, args[0], zoom, direct, waitvm, reconnect, verbose, debug, NULL); - if (ret != 0) - return ret; - - gtk_main(); - - return 0; -} - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 680c617..0000000 --- a/src/util.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Virt Viewer: A virtual machine console viewer - * - * Copyright (C) 2007-2009 Red Hat, - * Copyright (C) 2009 Daniel P. Berrange - * - * 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 - */ - -#include - -#include -#include -#include - -#include "util.h" - -GtkBuilder *viewer_load_ui(const char *name) -{ - struct stat sb; - GtkBuilder *builder; - GError *error = NULL; - - builder = gtk_builder_new(); - if (stat(name, &sb) >= 0) { - gtk_builder_add_from_file(builder, name, &error); - } else { - gchar *path = g_strdup_printf("%s/%s", BUILDER_XML_DIR, name); - gtk_builder_add_from_file(builder, path, &error); - g_free(path); - } - - if (error) - g_error("Cannot load UI description %s: %s", name, - error->message); - - return builder; -} - - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/src/util.h b/src/util.h deleted file mode 100644 index f9af8f7..0000000 --- a/src/util.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Virt Viewer: A virtual machine console viewer - * - * Copyright (C) 2007-2009 Red Hat, - * Copyright (C) 2009 Daniel P. Berrange - * - * 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 - */ - -#ifndef VIRT_VIEWER_UTIL_H -#define VIRT_VIEWER_UTIL_H - -#include - -extern gboolean doDebug; - -#define DEBUG_LOG(s, ...) do { if (doDebug) g_debug((s), ## __VA_ARGS__); } while (0) -#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array)) - - -GtkBuilder *viewer_load_ui(const char *name); - -#endif diff --git a/src/viewer-priv.h b/src/viewer-priv.h deleted file mode 100644 index be220f5..0000000 --- a/src/viewer-priv.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 - */ -#ifndef _VIRT_VIEWER_PRIV_H -# define _VIRT_VIEWER_PRIV_H - -#include -#include - -#include -#include -#include -#include - -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; - - GtkBuilder *builder; - GtkWidget *window; - GtkWidget *container; - - GtkWidget *notebook; - GtkWidget *align; - GtkWidget *status; - - GtkWidget *toolbar; - GtkWidget *layout; - - 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 *unixsock; - char *ghost; - 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 --git a/src/viewer.c b/src/viewer.c deleted file mode 100644 index 27ea056..0000000 --- a/src/viewer.c +++ /dev/null @@ -1,1410 +0,0 @@ -/* - * 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 - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef HAVE_SYS_UN_H -#include -#endif - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "viewer.h" -#include "viewer-priv.h" -#include "events.h" -#include "auth.h" -#include "display-vnc.h" - -#ifdef HAVE_SPICE_GTK -#include "display-spice.h" -#endif - -#include "view/autoDrawer.h" - -#define SCALE(x) do { x = viewer->fullscreen ? x : x * viewer->zoomlevel / 100; } while (0); - -gboolean doDebug = FALSE; - -void viewer_menu_view_zoom_out(G_GNUC_UNUSED GtkWidget *menu, VirtViewer *viewer); -void viewer_menu_view_zoom_in(G_GNUC_UNUSED GtkWidget *menu, VirtViewer *viewer); -void viewer_menu_view_zoom_reset(G_GNUC_UNUSED GtkWidget *menu, VirtViewer *viewer); -void viewer_delete(GtkWidget *src G_GNUC_UNUSED, void *dummy G_GNUC_UNUSED, VirtViewer *viewer); -void viewer_menu_file_quit(GtkWidget *src G_GNUC_UNUSED, VirtViewer *viewer); -void viewer_about_close(GtkWidget *dialog, VirtViewer *viewer G_GNUC_UNUSED); -void viewer_about_delete(GtkWidget *dialog, void *dummy G_GNUC_UNUSED, VirtViewer *viewer G_GNUC_UNUSED); -void viewer_menu_help_about(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer); -void viewer_menu_view_fullscreen(GtkWidget *menu, VirtViewer *viewer); -void viewer_menu_view_resize(GtkWidget *menu, VirtViewer *viewer); -void viewer_menu_send(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer); -void viewer_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer); - -static const char * const menuNames[LAST_MENU] = { - "menu-file", "menu-view", "menu-send", "menu-help" -}; - - -#define MAX_KEY_COMBO 3 -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"}, -}; - - -static gboolean viewer_connect_timer(void *opaque); -static int viewer_initial_connect(VirtViewer *viewer); - - -void viewer_simple_message_dialog(GtkWidget *window, const char *fmt, ...) -{ - GtkWidget *dialog; - char *msg; - va_list vargs; - - va_start(vargs, fmt); - - msg = g_strdup_vprintf(fmt, vargs); - - va_end(vargs); - - dialog = gtk_message_dialog_new(GTK_WINDOW(window), - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - "%s", - msg); - - gtk_dialog_run(GTK_DIALOG(dialog)); - - gtk_widget_destroy(dialog); - - g_free(msg); -} - - -void viewer_add_display_and_realize(VirtViewer *viewer) -{ - g_return_if_fail(viewer != NULL); - g_return_if_fail(viewer->display != NULL); - g_return_if_fail(viewer->display->widget != NULL); - - gtk_container_add(GTK_CONTAINER(viewer->align), viewer->display->widget); - - if (!viewer->window) { - gtk_container_add(GTK_CONTAINER(viewer->container), GTK_WIDGET(viewer->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 - * allows us to set the fixed size, but then allow the user - * to later resize it smaller again - */ -static gboolean -viewer_unset_widget_size_cb(gpointer data) -{ - GtkWidget *widget = data; - DEBUG_LOG("Unset requisition on widget=%p", widget); - - gtk_widget_queue_resize_no_redraw (widget); - - return FALSE; -} - -/* - * This sets the actual size of the widget, and then - * sets an idle callback to resize again, without constraints - * activated - */ -static gboolean -viewer_set_widget_size_cb(GtkWidget *widget, - GtkRequisition *req, - gpointer data) -{ - VirtViewerSize *size = data; - DEBUG_LOG("Set requisition on widget=%p to %dx%d", widget, size->width, size->height); - - req->width = size->width; - req->height = size->height; - - g_signal_handler_disconnect (widget, size->sig_id); - g_free (size); - g_idle_add (viewer_unset_widget_size_cb, widget); - - return FALSE; -} - - -/* - * Registers a callback used to set the widget size once - */ -static void -viewer_set_widget_size(VirtViewer *viewer, - GtkWidget *widget, - int width, - int height) -{ - VirtViewerSize *size = g_new (VirtViewerSize, 1); - DEBUG_LOG("Queue resize widget=%p width=%d height=%d", widget, width, height); - size->viewer = viewer; - size->width = width; - size->height = height; - size->sig_id = g_signal_connect - (widget, "size-request", - G_CALLBACK (viewer_set_widget_size_cb), - size); - - gtk_widget_queue_resize (widget); -} - - -/* - * This code attempts to resize the top level window to be large enough - * 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 - */ -void viewer_resize_main_window(VirtViewer *viewer) -{ - GdkRectangle fullscreen; - GdkScreen *screen; - int width, height; - double desktopAspect; - double screenAspect; - - DEBUG_LOG("Preparing main window resize"); - if (!viewer->active) { - DEBUG_LOG("Skipping inactive resize"); - return; - } - - gtk_window_resize(GTK_WINDOW (viewer->window), 1, 1); - - screen = gdk_drawable_get_screen(gtk_widget_get_window(viewer->window)); - gdk_screen_get_monitor_geometry(screen, - gdk_screen_get_monitor_at_window - (screen, gtk_widget_get_window(viewer->window)), - &fullscreen); - - desktopAspect = (double)viewer->desktopWidth / (double)viewer->desktopHeight; - screenAspect = (double)(fullscreen.width - 128) / (double)(fullscreen.height - 128); - - if ((viewer->desktopWidth > (fullscreen.width - 128)) || - (viewer->desktopHeight > (fullscreen.height - 128))) { - /* Doesn't fit native res, so go as large as possible - maintaining aspect ratio */ - if (screenAspect > desktopAspect) { - width = viewer->desktopHeight * desktopAspect; - height = viewer->desktopHeight; - } else { - width = viewer->desktopWidth; - height = viewer->desktopWidth / desktopAspect; - } - } else { - width = viewer->desktopWidth; - height = viewer->desktopHeight; - } - - SCALE(width); - SCALE(height); - - viewer_set_widget_size(viewer, - viewer->align, - width, - height); -} - -void viewer_menu_view_zoom_out(G_GNUC_UNUSED GtkWidget *menu, VirtViewer *viewer) -{ - viewer->zoomlevel -= 10; - if (viewer->zoomlevel < 10) - viewer->zoomlevel = 10; - - viewer_resize_main_window(viewer); -} - -void viewer_menu_view_zoom_in(G_GNUC_UNUSED GtkWidget *menu, VirtViewer *viewer) -{ - viewer->zoomlevel += 10; - if (viewer->zoomlevel > 200) - viewer->zoomlevel = 200; - - viewer_resize_main_window(viewer); -} - -void viewer_menu_view_zoom_reset(G_GNUC_UNUSED GtkWidget *menu, VirtViewer *viewer) -{ - viewer->zoomlevel = 100; - - viewer_resize_main_window(viewer); -} - -void viewer_set_title(VirtViewer *viewer, gboolean grabbed) -{ - char *title; - const char *subtitle; - - if (!viewer->window) - return; - - if (grabbed) - subtitle = "(Press Ctrl+Alt to release pointer) "; - else - subtitle = ""; - - title = g_strdup_printf("%s%s - Virt Viewer", - subtitle, viewer->domtitle); - - gtk_window_set_title(GTK_WINDOW(viewer->window), title); - - g_free(title); -} - -static gboolean viewer_ignore_accel(GtkWidget *menu G_GNUC_UNUSED, - VirtViewer *viewer G_GNUC_UNUSED) -{ - /* ignore accelerator */ - return TRUE; -} - - -void viewer_disable_modifiers(VirtViewer *viewer) -{ - GtkSettings *settings = gtk_settings_get_default(); - GValue empty; - GSList *accels; - int i; - - if (!viewer->window) - return; - - if (!viewer->accelEnabled) - return; - - /* This stops F10 activating menu bar */ - memset(&empty, 0, sizeof empty); - g_value_init(&empty, G_TYPE_STRING); - g_object_get_property(G_OBJECT(settings), "gtk-menu-bar-accel", &viewer->accelSetting); - g_object_set_property(G_OBJECT(settings), "gtk-menu-bar-accel", &empty); - - /* This stops global accelerators like Ctrl+Q == Quit */ - for (accels = viewer->accelList ; accels ; accels = accels->next) { - gtk_window_remove_accel_group(GTK_WINDOW(viewer->window), accels->data); - } - - /* This stops menu bar shortcuts like Alt+F == File */ - for (i = 0 ; i < LAST_MENU ; i++) { - GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, menuNames[i])); - viewer->accelMenuSig[i] = - g_signal_connect(menu, "mnemonic-activate", - G_CALLBACK(viewer_ignore_accel), viewer); - } - - viewer->accelEnabled = FALSE; -} - - -void viewer_enable_modifiers(VirtViewer *viewer) -{ - GtkSettings *settings = gtk_settings_get_default(); - GSList *accels; - int i; - - if (!viewer->window) - return; - - if (viewer->accelEnabled) - return; - - /* This allows F10 activating menu bar */ - g_object_set_property(G_OBJECT(settings), "gtk-menu-bar-accel", &viewer->accelSetting); - - /* This allows global accelerators like Ctrl+Q == Quit */ - for (accels = viewer->accelList ; accels ; accels = accels->next) { - gtk_window_add_accel_group(GTK_WINDOW(viewer->window), accels->data); - } - - /* This allows menu bar shortcuts like Alt+F == File */ - for (i = 0 ; i < LAST_MENU ; i++) { - GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, menuNames[i])); - g_signal_handler_disconnect(menu, viewer->accelMenuSig[i]); - } - - viewer->accelEnabled = TRUE; -} - -void viewer_quit(VirtViewer *viewer) -{ - g_return_if_fail(viewer != NULL); - - if (viewer->display) - virt_viewer_display_close(viewer->display); - gtk_main_quit(); -} - -void viewer_delete(GtkWidget *src G_GNUC_UNUSED, void *dummy G_GNUC_UNUSED, VirtViewer *viewer) -{ - viewer_quit(viewer); -} - -void viewer_menu_file_quit(GtkWidget *src G_GNUC_UNUSED, VirtViewer *viewer) -{ - viewer_quit(viewer); -} - - -static void viewer_leave_fullscreen(VirtViewer *viewer) -{ - GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "top-menu")); - if (!viewer->fullscreen) - return; - viewer->fullscreen = FALSE; - ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(viewer->layout), FALSE); - gtk_widget_show(menu); - gtk_widget_hide(viewer->toolbar); - gtk_window_unfullscreen(GTK_WINDOW(viewer->window)); - if (viewer->autoResize) - viewer_resize_main_window(viewer); -} - -static void viewer_enter_fullscreen(VirtViewer *viewer) -{ - GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "top-menu")); - if (viewer->fullscreen) - return; - viewer->fullscreen = TRUE; - gtk_widget_hide(menu); - gtk_window_fullscreen(GTK_WINDOW(viewer->window)); - gtk_widget_show(viewer->toolbar); - ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(viewer->layout), TRUE); -} - - -static void viewer_toolbar_leave_fullscreen(GtkWidget *button G_GNUC_UNUSED, VirtViewer *viewer) -{ - GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "menu-view-fullscreen")); - - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE); - viewer_leave_fullscreen(viewer); -} - - -void viewer_menu_view_fullscreen(GtkWidget *menu, VirtViewer *viewer) -{ - if (!viewer->window) - return; - - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu))) { - viewer_enter_fullscreen(viewer); - } else { - viewer_leave_fullscreen(viewer); - } -} - -void viewer_menu_view_resize(GtkWidget *menu, VirtViewer *viewer) -{ - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu))) { - viewer->autoResize = TRUE; - if (!viewer->fullscreen) - viewer_resize_main_window(viewer); - } else { - viewer->autoResize = FALSE; - } -} - -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)); - - 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(VirtViewer *viewer, const char *file) -{ - 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); -} - -void viewer_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer) -{ - GtkWidget *dialog; - - g_return_if_fail(viewer->display != NULL); - - dialog = gtk_file_chooser_dialog_new ("Save screenshot", - NULL, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); - - //gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), default_folder_for_saving); - //gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "Screenshot"); - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename; - - filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - viewer_save_screenshot(viewer, filename); - g_free (filename); - } - - gtk_widget_destroy (dialog); -} - -void viewer_about_close(GtkWidget *dialog, VirtViewer *viewer G_GNUC_UNUSED) -{ - gtk_widget_hide(dialog); - gtk_widget_destroy(dialog); -} - -void viewer_about_delete(GtkWidget *dialog, void *dummy G_GNUC_UNUSED, VirtViewer *viewer G_GNUC_UNUSED) -{ - gtk_widget_hide(dialog); - gtk_widget_destroy(dialog); -} - -void viewer_menu_help_about(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer) -{ - GtkBuilder *about = viewer_load_ui("about.xml"); - - GtkWidget *dialog = GTK_WIDGET(gtk_builder_get_object(about, "about")); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION); - - gtk_builder_connect_signals(about, viewer); - - gtk_widget_show_all(dialog); - - g_object_unref(G_OBJECT(about)); -} - - - -static int viewer_parse_uuid(const char *name, unsigned char *uuid) -{ - int i; - - const char *cur = name; - for (i = 0;i < 16;) { - uuid[i] = 0; - if (*cur == 0) - return -1; - if ((*cur == '-') || (*cur == ' ')) { - cur++; - continue; - } - if ((*cur >= '0') && (*cur <= '9')) - uuid[i] = *cur - '0'; - else if ((*cur >= 'a') && (*cur <= 'f')) - uuid[i] = *cur - 'a' + 10; - else if ((*cur >= 'A') && (*cur <= 'F')) - uuid[i] = *cur - 'A' + 10; - else - return -1; - uuid[i] *= 16; - cur++; - if (*cur == 0) - return -1; - if ((*cur >= '0') && (*cur <= '9')) - uuid[i] += *cur - '0'; - else if ((*cur >= 'a') && (*cur <= 'f')) - uuid[i] += *cur - 'a' + 10; - else if ((*cur >= 'A') && (*cur <= 'F')) - uuid[i] += *cur - 'A' + 10; - else - return -1; - i++; - cur++; - } - - return 0; -} - - -static virDomainPtr viewer_lookup_domain(VirtViewer *viewer) -{ - char *end; - int id = strtol(viewer->domkey, &end, 10); - virDomainPtr dom = NULL; - unsigned char uuid[16]; - - if (id >= 0 && end && !*end) { - dom = virDomainLookupByID(viewer->conn, id); - } - if (!dom && viewer_parse_uuid(viewer->domkey, uuid) == 0) { - dom = virDomainLookupByUUID(viewer->conn, uuid); - } - if (!dom) { - dom = virDomainLookupByName(viewer->conn, viewer->domkey); - } - return dom; -} - -static int viewer_matches_domain(VirtViewer *viewer, - virDomainPtr dom) -{ - char *end; - const char *name; - int id = strtol(viewer->domkey, &end, 10); - unsigned char wantuuid[16]; - unsigned char domuuid[16]; - - if (id >= 0 && end && !*end) { - if (virDomainGetID(dom) == id) - return 1; - } - if (viewer_parse_uuid(viewer->domkey, wantuuid) == 0) { - virDomainGetUUID(dom, domuuid); - if (memcmp(wantuuid, domuuid, VIR_UUID_BUFLEN) == 0) - return 1; - } - - name = virDomainGetName(dom); - if (strcmp(name, viewer->domkey) == 0) - return 1; - - return 0; -} - -static char * viewer_extract_xpath_string(const gchar *xmldesc, const gchar *xpath) -{ - xmlDocPtr xml = NULL; - xmlParserCtxtPtr pctxt = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - char *port = NULL; - - pctxt = xmlNewParserCtxt(); - if (!pctxt || !pctxt->sax) - goto error; - - xml = xmlCtxtReadDoc(pctxt, (const xmlChar *)xmldesc, "domain.xml", NULL, - XML_PARSE_NOENT | XML_PARSE_NONET | - XML_PARSE_NOWARNING); - if (!xml) - goto error; - - ctxt = xmlXPathNewContext(xml); - if (!ctxt) - goto error; - - obj = xmlXPathEval((const xmlChar *)xpath, ctxt); - if (!obj || obj->type != XPATH_STRING || !obj->stringval || !obj->stringval[0]) - goto error; - if (!strcmp((const char*)obj->stringval, "-1")) - goto error; - - port = g_strdup((const char*)obj->stringval); - xmlXPathFreeObject(obj); - obj = NULL; - - error: - if (obj) - xmlXPathFreeObject(obj); - if (ctxt) - xmlXPathFreeContext(ctxt); - if (xml) - xmlFreeDoc(xml); - if (pctxt) - xmlFreeParserCtxt(pctxt); - return port; -} - - -static int viewer_extract_host(const char *uristr, char **host, char **transport, char **user, int *port) -{ - xmlURIPtr uri; - char *offset; - - *host = NULL; - *transport = NULL; - *user = NULL; - - if (uristr == NULL || - !g_strcasecmp(uristr, "xen")) - uristr = "xen:///"; - - uri = xmlParseURI(uristr); - if (!uri || !uri->server) { - *host = g_strdup("localhost"); - } else { - *host = g_strdup(uri->server); - } - - if (uri->user) - *user = g_strdup(uri->user); - *port = uri->port; - - offset = strchr(uri->scheme, '+'); - if (offset) - *transport = g_strdup(offset+1); - - xmlFreeURI(uri); - return 0; -} - -#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) - -static int viewer_open_tunnel(const char **cmd) -{ - int fd[2]; - pid_t pid; - - if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0) - return -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]); - return fd[0]; -} - - -static int viewer_open_tunnel_ssh(const char *sshhost, int sshport, const char *sshuser, - const char *host, const char *port, const char *unixsock) -{ - const char *cmd[10]; - char portstr[50]; - int n = 0; - - if (!sshport) - sshport = 22; - - sprintf(portstr, "%d", sshport); - - cmd[n++] = "ssh"; - cmd[n++] = "-p"; - cmd[n++] = portstr; - if (sshuser) { - cmd[n++] = "-l"; - cmd[n++] = sshuser; - } - cmd[n++] = sshhost; - cmd[n++] = "nc"; - if (port) { - cmd[n++] = host; - cmd[n++] = port; - } else { - cmd[n++] = "-U"; - cmd[n++] = unixsock; - } - cmd[n++] = NULL; - - return viewer_open_tunnel(cmd); -} - -static int viewer_open_unix_sock(const char *unixsock) -{ - struct sockaddr_un addr; - int fd; - - memset(&addr, 0, sizeof addr); - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, unixsock); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - - if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { - close(fd); - return -1; - } - - return fd; -} - -#endif /* defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) */ - -static void viewer_trace(VirtViewer *viewer, const char *fmt, ...) -{ - va_list ap; - - if (doDebug) { - va_start(ap, fmt); - g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fmt, ap); - va_end(ap); - } - - if (viewer->verbose) { - va_start(ap, fmt); - g_vprintf(fmt, ap); - va_end(ap); - } -} - -void viewer_set_status(VirtViewer *viewer, const char *text) -{ - gtk_notebook_set_current_page(GTK_NOTEBOOK(viewer->notebook), 0); - gtk_label_set_text(GTK_LABEL(viewer->status), text); -} - - -static void viewer_show_display(VirtViewer *viewer) -{ - g_return_if_fail(viewer != NULL); - g_return_if_fail(viewer->display != NULL); - g_return_if_fail(viewer->display->widget != NULL); - - gtk_widget_show(viewer->display->widget); - gtk_widget_grab_focus(viewer->display->widget); - gtk_notebook_set_current_page(GTK_NOTEBOOK(viewer->notebook), 1); -} - -static void viewer_connect_info_free(VirtViewer *viewer) -{ - free(viewer->host); - free(viewer->ghost); - free(viewer->gport); - free(viewer->transport); - free(viewer->user); - free(viewer->unixsock); - - viewer->host = NULL; - viewer->ghost = NULL; - viewer->gport = NULL; - viewer->transport = NULL; - viewer->user = NULL; - viewer->unixsock = NULL; - viewer->port = 0; -} - -static gboolean viewer_extract_connect_info(VirtViewer *viewer, - virDomainPtr dom) -{ - char *type = NULL; - char *xpath = NULL; - gboolean retval = FALSE; - char *xmldesc = virDomainGetXMLDesc(dom, 0); - - viewer_connect_info_free(viewer); - - if ((type = viewer_extract_xpath_string(xmldesc, "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_trace(viewer, "Guest %s has a %s display\n", - viewer->domkey, type); - viewer->display = VIRT_VIEWER_DISPLAY(virt_viewer_display_vnc_new(viewer)); -#ifdef HAVE_SPICE_GTK - } else if (g_strcasecmp(type, "spice") == 0) { - viewer_trace(viewer, "Guest %s has a %s display\n", - viewer->domkey, type); - viewer->display = VIRT_VIEWER_DISPLAY(virt_viewer_display_spice_new(viewer)); -#endif - } else { - viewer_trace(viewer, "Guest %s has unsupported %s display type\n", - viewer->domkey, type); - 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(xmldesc, xpath)) == NULL) { - free(xpath); - xpath = g_strdup_printf("string(/domain/devices/graphics[@type='%s']/@socket)", type); - if ((viewer->unixsock = viewer_extract_xpath_string(xmldesc, xpath)) == NULL) { - viewer_simple_message_dialog(viewer->window, _("Cannot determine the graphic address for the guest %s"), - viewer->domkey); - goto cleanup; - } - } else { - free(xpath); - xpath = g_strdup_printf("string(/domain/devices/graphics[@type='%s']/@listen)", type); - viewer->ghost = viewer_extract_xpath_string(xmldesc, xpath); - if (viewer->ghost == NULL) - viewer->ghost = g_strdup("localhost"); - } - - if (viewer->gport) - DEBUG_LOG("Guest graphics address is %s:%s", viewer->ghost, viewer->gport); - else - DEBUG_LOG("Guest graphics address is %s", viewer->unixsock); - - 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; - } - - retval = TRUE; - -cleanup: - free(xpath); - free(xmldesc); - return retval; -} - -#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) -void viewer_channel_open_fd(VirtViewer *viewer, VirtViewerDisplayChannel *channel) -{ - 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->ghost, viewer->gport, NULL)) < 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 -void viewer_channel_open_fd(VirtViewer *viewer G_GNUC_UNUSED, - VirtViewerDisplayChannel *channel G_GNUC_UNUSED) -{ - viewer_simple_message_dialog(viewer->window, _("Connect to channel unsupported.")); -} -#endif - -static int viewer_activate(VirtViewer *viewer, - virDomainPtr dom) -{ - int fd = -1; - int ret = -1; - - if (viewer->active) - goto cleanup; - - viewer_trace(viewer, "Guest %s is running, determining display\n", - viewer->domkey); - if (viewer->display == NULL) { - if (!viewer_extract_connect_info(viewer, dom)) - goto cleanup; - - if (viewer->gport) - viewer->pretty_address = g_strdup_printf("%s:%s", viewer->ghost, viewer->gport); - else - viewer->pretty_address = g_strdup_printf("%s:%s", viewer->host, viewer->unixsock); - } - -#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) - if (viewer->transport && - g_strcasecmp(viewer->transport, "ssh") == 0 && - !viewer->direct) { - char *dst; - - if (viewer->gport) { - viewer_trace(viewer, "Opening indirect TCP connection to display at %s:%s\n", - viewer->ghost, viewer->gport); - } else { - viewer_trace(viewer, "Opening indirect UNIX connection to display at %s\n", - viewer->unixsock); - dst = g_strdup(viewer->unixsock); - } - viewer_trace(viewer, "Setting up SSH tunnel via %s@%s:%d\n", - viewer->user, viewer->host, viewer->port ? viewer->port : 22); - - if ((fd = viewer_open_tunnel_ssh(viewer->host, viewer->port, - viewer->user, viewer->ghost, - viewer->gport, viewer->unixsock)) < 0) - return -1; - } else if (viewer->unixsock) { - viewer_trace(viewer, "Opening direct UNIX connection to display at %s", - viewer->unixsock); - if ((fd = viewer_open_unix_sock(viewer->unixsock)) < 0) - return -1; - } -#endif - - if (fd >= 0) { - ret = virt_viewer_display_open_fd(viewer->display, fd); - } else { - viewer_trace(viewer, "Opening direct TCP connection to display at %s:%s\n", - viewer->ghost, viewer->gport); - ret = virt_viewer_display_open_host(viewer->display, - viewer->ghost, viewer->gport); - } - - viewer_set_status(viewer, "Connecting to graphic server"); - - free(viewer->domtitle); - viewer->domtitle = g_strdup(virDomainGetName(dom)); - - viewer->connected = FALSE; - viewer->active = TRUE; - viewer_set_title(viewer, FALSE); - -cleanup: - return ret; -} - -/* text was actually requested */ -static void viewer_vnc_clipboard_copy(GtkClipboard *clipboard G_GNUC_UNUSED, - GtkSelectionData *data, - guint info G_GNUC_UNUSED, - VirtViewer *viewer) -{ - gtk_selection_data_set_text(data, viewer->clipboard, -1); -} - -void viewer_server_cut_text(VirtViewer *viewer, const gchar *text) -{ - GtkClipboard *cb; - gsize a, b; - GtkTargetEntry targets[] = { - {g_strdup("UTF8_STRING"), 0, 0}, - {g_strdup("COMPOUND_TEXT"), 0, 0}, - {g_strdup("TEXT"), 0, 0}, - {g_strdup("STRING"), 0, 0}, - }; - - if (!text) - return; - - g_free (viewer->clipboard); - viewer->clipboard = g_convert (text, -1, "utf-8", "iso8859-1", &a, &b, NULL); - - if (viewer->clipboard) { - cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - - gtk_clipboard_set_with_owner (cb, - targets, - G_N_ELEMENTS(targets), - (GtkClipboardGetFunc)viewer_vnc_clipboard_copy, - NULL, - G_OBJECT (viewer)); - } -} - -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"); - viewer_trace(viewer, "Guest %s display has disconnected, waiting to reconnect", - viewer->domkey); - } else { - viewer_set_status(viewer, "Guest domain has shutdown"); - viewer_trace(viewer, "Guest %s display has disconnected, shutting down", - viewer->domkey); - 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, - int event, - int detail G_GNUC_UNUSED, - void *opaque) -{ - VirtViewer *viewer = opaque; - - DEBUG_LOG("Got domain event %d %d", event, detail); - - if (!viewer_matches_domain(viewer, dom)) - return 0; - - switch (event) { - case VIR_DOMAIN_EVENT_STOPPED: - viewer_deactivate(viewer); - break; - - case VIR_DOMAIN_EVENT_STARTED: - viewer_activate(viewer, dom); - break; - } - - return 0; -} - - -static int viewer_initial_connect(VirtViewer *viewer) -{ - virDomainPtr dom = NULL; - virDomainInfo info; - int ret = -1; - - viewer_set_status(viewer, "Finding guest domain"); - dom = viewer_lookup_domain(viewer); - if (!dom) { - if (viewer->waitvm) { - viewer_set_status(viewer, "Waiting for guest domain to be created"); - viewer_trace(viewer, "Guest %s does not yet exist, waiting for it to be created\n", - viewer->domkey); - goto done; - } else { - viewer_simple_message_dialog(viewer->window, _("Cannot find guest domain %s"), - viewer->domkey); - DEBUG_LOG("Cannot find guest %s", viewer->domkey); - goto cleanup; - } - } - - viewer_set_status(viewer, "Checking guest domain status"); - if (virDomainGetInfo(dom, &info) < 0) { - DEBUG_LOG("Cannot get guest state"); - goto cleanup; - } - - if (info.state == VIR_DOMAIN_SHUTOFF) { - viewer_set_status(viewer, "Waiting for guest domain to start"); - } else { - ret = viewer_activate(viewer, dom); - if (ret < 0) { - if (viewer->waitvm) { - viewer_set_status(viewer, "Waiting for guest domain to start server"); - viewer_trace(viewer, "Guest %s has not activated its display yet, waiting for it to start\n", - viewer->domkey); - } else { - DEBUG_LOG("Failed to activate viewer"); - goto cleanup; - } - } else if (ret == 0) { - DEBUG_LOG("Failed to activate viewer"); - ret = -1; - goto cleanup; - } - } - - done: - ret = 0; - cleanup: - if (dom) - virDomainFree(dom); - return ret; -} - -static gboolean viewer_connect_timer(void *opaque) -{ - VirtViewer *viewer = opaque; - - DEBUG_LOG("Connect timer fired"); - - if (!viewer->active && - viewer_initial_connect(viewer) < 0) - gtk_main_quit(); - - if (viewer->active) - return FALSE; - - return TRUE; -} - -static void viewer_toolbar_setup(VirtViewer *viewer) -{ - GtkWidget *button; - - viewer->toolbar = gtk_toolbar_new(); - gtk_toolbar_set_show_arrow(GTK_TOOLBAR(viewer->toolbar), FALSE); - gtk_widget_set_no_show_all(viewer->toolbar, TRUE); - gtk_toolbar_set_style(GTK_TOOLBAR(viewer->toolbar), GTK_TOOLBAR_BOTH_HORIZ); - - /* Close connection */ - button = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_CLOSE)); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), _("Disconnect")); - gtk_widget_show(GTK_WIDGET(button)); - gtk_toolbar_insert(GTK_TOOLBAR(viewer->toolbar), GTK_TOOL_ITEM (button), 0); - g_signal_connect(button, "clicked", G_CALLBACK(gtk_main_quit), NULL); - - /* Leave fullscreen */ - button = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_LEAVE_FULLSCREEN)); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), _("Leave fullscreen")); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), _("Leave fullscreen")); - gtk_tool_item_set_is_important(GTK_TOOL_ITEM(button), TRUE); - gtk_widget_show(GTK_WIDGET(button)); - gtk_toolbar_insert(GTK_TOOLBAR(viewer->toolbar), GTK_TOOL_ITEM(button), 0); - g_signal_connect(button, "clicked", G_CALLBACK(viewer_toolbar_leave_fullscreen), viewer); - - viewer->layout = ViewAutoDrawer_New(); - - ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(viewer->layout), FALSE); - ViewOvBox_SetOver(VIEW_OV_BOX(viewer->layout), viewer->toolbar); - ViewOvBox_SetUnder(VIEW_OV_BOX(viewer->layout), viewer->notebook); - ViewAutoDrawer_SetOffset(VIEW_AUTODRAWER(viewer->layout), -1); - ViewAutoDrawer_SetFill(VIEW_AUTODRAWER(viewer->layout), FALSE); - ViewAutoDrawer_SetOverlapPixels(VIEW_AUTODRAWER(viewer->layout), 1); - ViewAutoDrawer_SetNoOverlapPixels(VIEW_AUTODRAWER(viewer->layout), 0); -} - - -static void viewer_error_func (void *data G_GNUC_UNUSED, virErrorPtr error G_GNUC_UNUSED) -{ - /* nada */ -} - -int -viewer_start (const char *uri, - const char *name, - gint zoom, - gboolean direct, - gboolean waitvm, - gboolean reconnect, - gboolean verbose, - gboolean debug, - GtkWidget *container) -{ - VirtViewer *viewer; - GtkWidget *menu; - int cred_types[] = - { VIR_CRED_AUTHNAME, VIR_CRED_PASSPHRASE }; - virConnectAuth auth_libvirt = { - .credtype = cred_types, - .ncredtype = ARRAY_CARDINALITY(cred_types), - .cb = viewer_auth_libvirt_credentials, - .cbdata = (void *)uri, - }; - - doDebug = debug; - - viewer = g_new0(VirtViewer, 1); - - viewer->active = FALSE; - viewer->autoResize = TRUE; - viewer->direct = direct; - viewer->waitvm = waitvm; - viewer->reconnect = reconnect; - viewer->verbose = verbose; - viewer->domkey = g_strdup(name); - viewer->uri = g_strdup(uri); - viewer->zoomlevel = zoom; - - g_value_init(&viewer->accelSetting, G_TYPE_STRING); - - viewer_event_register(); - - virSetErrorFunc(NULL, viewer_error_func); - - viewer_trace(viewer, "Opening connection to libvirt with URI %s\n", - uri ? uri : ""); - viewer->conn = virConnectOpenAuth(uri, - //virConnectAuthPtrDefault, - &auth_libvirt, - VIR_CONNECT_RO); - if (!viewer->conn) { - viewer_simple_message_dialog(NULL, _("Unable to connect to libvirt with URI %s"), - uri ? uri : _("[none]")); - return -1; - } - - if (!container) { - viewer->builder = viewer_load_ui("viewer.xml"); - - menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "menu-view-resize")); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE); - - gtk_builder_connect_signals(viewer->builder, viewer); - } - - viewer->status = gtk_label_new(""); - viewer->align = gtk_alignment_new(0.5, 0.5, 0, 0); - - viewer->notebook = gtk_notebook_new(); - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(viewer->notebook), FALSE); - gtk_notebook_set_show_border(GTK_NOTEBOOK(viewer->notebook), FALSE); - - gtk_notebook_append_page(GTK_NOTEBOOK(viewer->notebook), viewer->status, NULL); - gtk_notebook_append_page(GTK_NOTEBOOK(viewer->notebook), viewer->align, NULL); - - if (container) { - viewer->container = container; - - gtk_box_pack_end(GTK_BOX(container), viewer->notebook, TRUE, TRUE, 0); - gtk_widget_show_all(GTK_WIDGET(container)); - } else { - GtkWidget *vbox = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "viewer-box")); - viewer_toolbar_setup(viewer); - - //gtk_box_pack_end(GTK_BOX(vbox), viewer->toolbar, TRUE, TRUE, 0); - //gtk_box_pack_end(GTK_BOX(vbox), viewer->notebook, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(vbox), viewer->layout, TRUE, TRUE, 0); - gtk_widget_show_all(GTK_WIDGET(vbox)); - - GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "viewer")); - GSList *accels; - viewer->container = window; - viewer->window = window; - gtk_window_set_resizable(GTK_WINDOW(window), TRUE); - viewer->accelEnabled = TRUE; - accels = gtk_accel_groups_from_object(G_OBJECT(window)); - for ( ; accels ; accels = accels->next) { - viewer->accelList = g_slist_append(viewer->accelList, accels->data); - g_object_ref(G_OBJECT(accels->data)); - } - gtk_widget_show_all(viewer->window); - } - - if (viewer_initial_connect(viewer) < 0) - return -1; - - if (virConnectDomainEventRegister(viewer->conn, - viewer_domain_event, - viewer, - NULL) < 0) - viewer->withEvents = FALSE; - else - viewer->withEvents = TRUE; - - if (!viewer->withEvents && - !viewer->active) { - DEBUG_LOG("No domain events, falling back to polling"); - g_timeout_add(500, - viewer_connect_timer, - viewer); - } - - return 0; -} - - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/src/viewer.h b/src/viewer.h deleted file mode 100644 index 554a6e6..0000000 --- a/src/viewer.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Virt Viewer: A virtual machine console viewer - * - * Copyright (C) 2007 Red Hat, - * - * 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 - */ - -#ifndef VIRT_VIEWER_H -#define VIRT_VIEWER_H - -#include "util.h" - -extern int viewer_start (const char *uri, - const char *name, - gint zoom, - gboolean direct, - gboolean waitvm, - gboolean reconnect, - gboolean verbose, - gboolean debug, - GtkWidget *container); - -#endif /* VIRT_VIEWER_H */ diff --git a/src/viewer.xml b/src/viewer.xml deleted file mode 100644 index 9241877..0000000 --- a/src/viewer.xml +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - 400 - 400 - - - - True - vertical - - - True - - - True - _File - True - - - True - - - True - Screenshot - True - - - - - - True - - - - - gtk-quit - True - True - True - - - - - - - - - - True - _View - True - - - True - - - True - Full screen - True - - - - - - True - _Zoom - True - - - True - - - True - gtk-zoom-in - - - - - - - True - gtk-zoom-out - - - - - - - True - - - - - True - gtk-zoom-100 - - - - - - - - - - - True - Automatically resize - True - - - - - - - - - - True - _Send key - True - - - True - - - True - Ctrl+Alt+_Del - True - - - - - - True - Ctrl+Alt+_Backspace - True - - - - - - True - - - - - True - Ctrl+Alt+F_1 - True - - - - - - True - Ctrl+Alt+F_2 - True - - - - - - True - Ctrl+Alt+F_3 - True - - - - - - True - Ctrl+Alt+F_4 - True - - - - - - True - Ctrl+Alt+F_5 - True - - - - - - True - Ctrl+Alt+F_6 - True - - - - - - True - Ctrl+Alt+F_7 - True - - - - - - True - Ctrl+Alt+F_8 - True - - - - - - True - Ctrl+Alt+F_9 - True - - - - - - True - Ctrl+Alt+F1_0 - True - - - - - - True - Ctrl+Alt+F11 - True - - - - - - True - Ctrl+Alt+F12 - True - - - - - - True - - - - - True - _PrintScreen - True - - - - - - - - - - True - _Help - True - - - True - - - gtk-about - True - True - True - - - - - - - - - - False - 0 - - - - - - diff --git a/src/virt-viewer-about.xml b/src/virt-viewer-about.xml new file mode 100644 index 0000000..603d9c7 --- /dev/null +++ b/src/virt-viewer-about.xml @@ -0,0 +1,56 @@ + + + + + + 5 + About Glade + False + center-on-parent + dialog + Virtual Machine Viewer + Copyright 2007-2008 Daniel P. Berrange +Copyright 2007-2008 Red Hat, Inc. + A remote desktop client built with GTK-VNC and libvirt + http://virt-manager.org/ + virt-manager.org + 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 + + Daniel P. Berrange + The Fedora Translation Team + + + + + True + 2 + + + + + + True + end + + + False + end + 0 + + + + + + diff --git a/src/virt-viewer-auth.c b/src/virt-viewer-auth.c new file mode 100644 index 0000000..3d63dcd --- /dev/null +++ b/src/virt-viewer-auth.c @@ -0,0 +1,237 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007-2009 Red Hat, + * + * 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 + */ + +#include + +#include +#include +#include + +#include "virt-viewer-auth.h" + + +int +virt_viewer_auth_collect_credentials(const char *type, + const char *address, + char **username, + char **password) +{ + GtkWidget *dialog = NULL; + GtkBuilder *creds = virt_viewer_util_load_ui("virt-viewer-auth.xml"); + GtkWidget *credUsername; + GtkWidget *credPassword; + GtkWidget *promptUsername; + GtkWidget *promptPassword; + GtkWidget *labelMessage; + int response; + char *message; + + dialog = GTK_WIDGET(gtk_builder_get_object(creds, "auth")); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); + + labelMessage = GTK_WIDGET(gtk_builder_get_object(creds, "message")); + credUsername = GTK_WIDGET(gtk_builder_get_object(creds, "cred-username")); + promptUsername = GTK_WIDGET(gtk_builder_get_object(creds, "prompt-username")); + credPassword = GTK_WIDGET(gtk_builder_get_object(creds, "cred-password")); + promptPassword = GTK_WIDGET(gtk_builder_get_object(creds, "prompt-password")); + + gtk_widget_set_sensitive(credUsername, username != NULL); + gtk_widget_set_sensitive(promptUsername, username != NULL); + gtk_widget_set_sensitive(credPassword, password != NULL); + gtk_widget_set_sensitive(promptPassword, password != NULL); + + if (address) { + message = g_strdup_printf("Authentication is required for the %s connection to:\n\n" + "%s\n\n", + type, + address ? address : "[unknown]"); + } else { + message = g_strdup_printf("Authentication is required for the %s connection:\n", + type); + } + + gtk_label_set_markup(GTK_LABEL(labelMessage), message); + g_free(message); + + gtk_widget_show_all(dialog); + response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_hide(dialog); + + if (response == GTK_RESPONSE_OK) { + if (username) + *username = g_strdup(gtk_entry_get_text(GTK_ENTRY(credUsername))); + if (password) + *password = g_strdup(gtk_entry_get_text(GTK_ENTRY(credPassword))); + } + + gtk_widget_destroy(GTK_WIDGET(dialog)); + + return response == GTK_RESPONSE_OK ? 0 : -1; +} + +void +virt_viewer_auth_vnc_credentials(GtkWidget *vnc, + GValueArray *credList, + char **vncAddress) +{ + char *username = NULL, *password = NULL; + gboolean wantPassword = FALSE, wantUsername = FALSE; + int i; + + DEBUG_LOG("Got VNC credential request for %d credential(s)", credList->n_values); + + for (i = 0 ; i < credList->n_values ; i++) { + GValue *cred = g_value_array_get_nth(credList, i); + switch (g_value_get_enum(cred)) { + case VNC_DISPLAY_CREDENTIAL_USERNAME: + wantUsername = TRUE; + break; + case VNC_DISPLAY_CREDENTIAL_PASSWORD: + wantPassword = TRUE; + break; + case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: + break; + default: + DEBUG_LOG("Unsupported credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(vnc)); + goto cleanup; + } + } + + if (wantUsername || wantPassword) { + int ret = virt_viewer_auth_collect_credentials("VNC", vncAddress ? *vncAddress : NULL, + wantUsername ? &username : NULL, + wantPassword ? &password : NULL); + + if (ret < 0) { + vnc_display_close(VNC_DISPLAY(vnc)); + goto cleanup; + } + } + + for (i = 0 ; i < credList->n_values ; i++) { + GValue *cred = g_value_array_get_nth(credList, i); + switch (g_value_get_enum(cred)) { + case VNC_DISPLAY_CREDENTIAL_USERNAME: + if (!username || + vnc_display_set_credential(VNC_DISPLAY(vnc), + g_value_get_enum(cred), + username)) { + DEBUG_LOG("Failed to set credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(vnc)); + } + break; + case VNC_DISPLAY_CREDENTIAL_PASSWORD: + if (!password || + vnc_display_set_credential(VNC_DISPLAY(vnc), + g_value_get_enum(cred), + password)) { + DEBUG_LOG("Failed to set credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(vnc)); + } + break; + case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: + if (vnc_display_set_credential(VNC_DISPLAY(vnc), + g_value_get_enum(cred), + "libvirt")) { + DEBUG_LOG("Failed to set credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(vnc)); + } + break; + default: + DEBUG_LOG("Unsupported credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(vnc)); + } + } + + cleanup: + g_free(username); + g_free(password); +} + + + +int +virt_viewer_auth_libvirt_credentials(virConnectCredentialPtr cred, + unsigned int ncred, + void *cbdata) +{ + char **username = NULL, **password = NULL; + const char *uri = cbdata; + int i; + int ret = -1; + + DEBUG_LOG("Got libvirt credential request for %d credential(s)", ncred); + + for (i = 0 ; i < ncred ; i++) { + switch (cred[i].type) { + case VIR_CRED_USERNAME: + case VIR_CRED_AUTHNAME: + username = &cred[i].result; + break; + case VIR_CRED_PASSPHRASE: + password = &cred[i].result; + break; + default: + DEBUG_LOG("Unsupported libvirt credential %d", cred[i].type); + return -1; + } + } + + if (username || password) { + ret = virt_viewer_auth_collect_credentials("libvirt", uri, + username, password); + if (ret < 0) + goto cleanup; + } else { + ret = 0; + } + + for (i = 0 ; i < ncred ; i++) { + switch (cred[i].type) { + case VIR_CRED_AUTHNAME: + case VIR_CRED_USERNAME: + case VIR_CRED_PASSPHRASE: + if (cred[i].result) + cred[i].resultlen = strlen(cred[i].result); + else + cred[i].resultlen = 0; + DEBUG_LOG("Got '%s' %d %d", cred[i].result, cred[i].resultlen, cred[i].type); + break; + } + } + + cleanup: + DEBUG_LOG("Return %d", ret); + return ret; +} + + + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-auth.h b/src/virt-viewer-auth.h new file mode 100644 index 0000000..1cbf2b6 --- /dev/null +++ b/src/virt-viewer-auth.h @@ -0,0 +1,43 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007-2009 Red Hat, + * + * 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 + */ + +#ifndef VIRT_VIEWER_AUTH_H +#define VIRT_VIEWER_AUTH_H + +#include + +#include "virt-viewer-util.h" + +void virt_viewer_auth_vnc_credentials(GtkWidget *vnc, + GValueArray *credList, + char **message); + +int virt_viewer_auth_collect_credentials(const char *type, + const char *address, + char **username, + char **password); + +int virt_viewer_auth_libvirt_credentials(virConnectCredentialPtr cred, + unsigned int ncred, + void *cbdata); + +#endif diff --git a/src/virt-viewer-auth.xml b/src/virt-viewer-auth.xml new file mode 100644 index 0000000..f45143d --- /dev/null +++ b/src/virt-viewer-auth.xml @@ -0,0 +1,127 @@ + + + + + + 5 + Authentication required + center-on-parent + dialog + + + True + 2 + + + True + 0 + 0 + label + True + + + 1 + + + + + True + 2 + 2 + 6 + 6 + + + True + 1 + Password: + + + 1 + 2 + + + + + True + 1 + Username: + + + + + True + True + + + 1 + 2 + + + + + True + True + False + + + 1 + 2 + 1 + 2 + + + + + 2 + + + + + True + end + + + gtk-cancel + True + True + True + True + + + False + False + 0 + + + + + gtk-ok + True + True + True + True + True + True + + + False + False + 3 + + + + + False + end + 0 + + + + + + button-cancel + button-ok + + + diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c new file mode 100644 index 0000000..88d64d1 --- /dev/null +++ b/src/virt-viewer-display-spice.c @@ -0,0 +1,405 @@ +/* + * 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 + */ + +#include + +#include "virt-viewer-util.h" +#include "virt-viewer-display-spice.h" +#include "virt-viewer-auth.h" + +G_DEFINE_TYPE (VirtViewerDisplaySpice, virt_viewer_display_spice, VIRT_VIEWER_TYPE_DISPLAY) + + +static void virt_viewer_display_spice_close(VirtViewerDisplay *display); +static void virt_viewer_display_spice_send_keys(VirtViewerDisplay *display, const guint *keyvals, int nkeyvals); +static GdkPixbuf *virt_viewer_display_spice_get_pixbuf(VirtViewerDisplay *display); +static gboolean virt_viewer_display_spice_open_fd(VirtViewerDisplay *display, int fd); +static gboolean virt_viewer_display_spice_open_host(VirtViewerDisplay *display, char *host, char *port); +static gboolean virt_viewer_display_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 = virt_viewer_display_spice_close; + dclass->send_keys = virt_viewer_display_spice_send_keys; + dclass->get_pixbuf = virt_viewer_display_spice_get_pixbuf; + dclass->open_fd = virt_viewer_display_spice_open_fd; + dclass->open_host = virt_viewer_display_spice_open_host; + dclass->channel_open_fd = virt_viewer_display_spice_channel_open_fd; +} + +static void +virt_viewer_display_spice_init(VirtViewerDisplaySpice *self G_GNUC_UNUSED) +{ +} + +static void +virt_viewer_display_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 * +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_spice_channel_open_fd_request(SpiceChannel *channel, + gint tls G_GNUC_UNUSED, + VirtViewerDisplay *display) +{ + VirtViewerDisplaySpice *self = VIRT_VIEWER_DISPLAY_SPICE(display); + + g_return_if_fail(self != NULL); + + virt_viewer_channel_open_fd(display->viewer, (VirtViewerDisplayChannel *)channel); +} + +static void +virt_viewer_display_spice_main_channel_event(SpiceChannel *channel G_GNUC_UNUSED, + 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"); + virt_viewer_quit(display->viewer); + break; + case SPICE_CHANNEL_ERROR_CONNECT: + DEBUG_LOG("main channel: failed to connect"); + virt_viewer_disconnected(display->viewer); + break; + case SPICE_CHANNEL_ERROR_AUTH: + DEBUG_LOG("main channel: auth failure (wrong password?)"); + int ret = virt_viewer_auth_collect_credentials("SPICE", + display->viewer->pretty_address, + NULL, &password); + if (ret < 0) { + virt_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); + virt_viewer_disconnected(display->viewer); + break; + } + + g_free(password); +} + + +/* + * Triggers a resize of the main container to indirectly cause + * the display widget to be resized to fit the available space + */ +static void +virt_viewer_display_spice_resize_widget(VirtViewer *viewer) +{ + gtk_widget_queue_resize(viewer->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 +virt_viewer_display_spice_resize_desktop(SpiceChannel *channel G_GNUC_UNUSED, + gint format G_GNUC_UNUSED, + gint width, + gint height, + gint stride G_GNUC_UNUSED, + gint shmid G_GNUC_UNUSED, + gpointer imgdata G_GNUC_UNUSED, + VirtViewer *viewer) +{ + DEBUG_LOG("desktop resize %dx%d", width, height); + viewer->desktopWidth = width; + viewer->desktopHeight = height; + + if (viewer->autoResize && viewer->window && !viewer->fullscreen) { + virt_viewer_resize_main_window(viewer); + } else { + virt_viewer_display_spice_resize_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 +virt_viewer_display_spice_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; + } + + if (viewer->desktopWidth == 0 || viewer->desktopHeight == 0) + desktopAspect = 1; + else + 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; +} + +static void +virt_viewer_display_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(virt_viewer_display_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(virt_viewer_display_spice_main_channel_event), self); + } + + if (SPICE_IS_DISPLAY_CHANNEL(channel)) { + DEBUG_LOG("new display channel (#%d)", id); + if (display->widget != NULL) + return; + + g_signal_connect(channel, "display-primary-create", + G_CALLBACK(virt_viewer_display_spice_resize_desktop), display->viewer); + + self->display = spice_display_new(s, id); + display->widget = GTK_WIDGET(self->display); + g_object_set(self->display, + "grab-keyboard", TRUE, + "grab-mouse", TRUE, + "resize-guest", FALSE, + "scaling", TRUE, + "auto-clipboard", TRUE, + NULL); + virt_viewer_add_display_and_realize(display->viewer); + + g_signal_connect(display->viewer->align, "size-allocate", + G_CALLBACK(virt_viewer_display_spice_resize_align), display->viewer); + + virt_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 +virt_viewer_display_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(virt_viewer_display_spice_channel_new), self); + g_signal_connect(self->session, "channel-destroy", + G_CALLBACK(virt_viewer_display_spice_channel_destroy), self); + + return self; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-display-spice.h b/src/virt-viewer-display-spice.h new file mode 100644 index 0000000..c375822 --- /dev/null +++ b/src/virt-viewer-display-spice.h @@ -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 + */ +#ifndef _VIRT_VIEWER_DISPLAY_SPICE_H +#define _VIRT_VIEWER_DISPLAY_SPICE_H + +#include +#include +#include + +#include "virt-viewer-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 --git a/src/virt-viewer-display-vnc.c b/src/virt-viewer-display-vnc.c new file mode 100644 index 0000000..02f5636 --- /dev/null +++ b/src/virt-viewer-display-vnc.c @@ -0,0 +1,359 @@ +/* + * 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 + */ + +#include "virt-viewer-auth.h" +#include "virt-viewer-display-vnc.h" + +G_DEFINE_TYPE(VirtViewerDisplayVNC, virt_viewer_display_vnc, VIRT_VIEWER_TYPE_DISPLAY) + +static void virt_viewer_display_vnc_close(VirtViewerDisplay* display); +static void virt_viewer_display_vnc_send_keys(VirtViewerDisplay* display, const guint *keyvals, int nkeyvals); +static GdkPixbuf* virt_viewer_display_vnc_get_pixbuf(VirtViewerDisplay* display); +static gboolean virt_viewer_display_vnc_open_fd(VirtViewerDisplay* display, int fd); +static gboolean virt_viewer_display_vnc_open_host(VirtViewerDisplay* display, char *host, char *port); +static gboolean virt_viewer_display_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 = virt_viewer_display_vnc_close; + dclass->send_keys = virt_viewer_display_vnc_send_keys; + dclass->get_pixbuf = virt_viewer_display_vnc_get_pixbuf; + dclass->open_fd = virt_viewer_display_vnc_open_fd; + dclass->open_host = virt_viewer_display_vnc_open_host; + dclass->channel_open_fd = virt_viewer_display_vnc_channel_open_fd; +} + +static void +virt_viewer_display_vnc_init(VirtViewerDisplayVNC *self G_GNUC_UNUSED) +{ +} + +static void +virt_viewer_display_vnc_mouse_grab(GtkWidget *vnc G_GNUC_UNUSED, + VirtViewerDisplayVNC *self) +{ + virt_viewer_set_title(VIRT_VIEWER_DISPLAY(self)->viewer, TRUE); +} + +static void +virt_viewer_display_vnc_mouse_ungrab(GtkWidget *vnc G_GNUC_UNUSED, + VirtViewerDisplayVNC *self) +{ + virt_viewer_set_title(VIRT_VIEWER_DISPLAY(self)->viewer, FALSE); +} + +static void +virt_viewer_display_vnc_key_grab(GtkWidget *vnc G_GNUC_UNUSED, + VirtViewerDisplayVNC *self) +{ + virt_viewer_disable_modifiers(VIRT_VIEWER_DISPLAY(self)->viewer); +} + +static void +virt_viewer_display_vnc_key_ungrab(GtkWidget *vnc G_GNUC_UNUSED, + VirtViewerDisplayVNC *self) +{ + virt_viewer_enable_modifiers(VIRT_VIEWER_DISPLAY(self)->viewer); +} + +static void +virt_viewer_display_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* +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_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 +virt_viewer_display_vnc_bell(VirtViewer *viewer, + gpointer data G_GNUC_UNUSED) +{ + gdk_window_beep(GTK_WIDGET(viewer->window)->window); +} + +static void +virt_viewer_display_vnc_auth_unsupported(VirtViewer *viewer, + unsigned int authType, + gpointer data G_GNUC_UNUSED) +{ + virt_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 +virt_viewer_display_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 +virt_viewer_display_vnc_resize_widget(VirtViewer *viewer) +{ + gtk_widget_queue_resize(viewer->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 +virt_viewer_display_vnc_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) { + virt_viewer_resize_main_window(viewer); + } else { + virt_viewer_display_vnc_resize_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 +virt_viewer_display_vnc_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; + + 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(virt_viewer_connected), viewer); + g_signal_connect_swapped(self->vnc, "vnc-initialized", + G_CALLBACK(virt_viewer_initialized), viewer); + g_signal_connect_swapped(self->vnc, "vnc-disconnected", + G_CALLBACK(virt_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(virt_viewer_display_vnc_resize_desktop), viewer); + g_signal_connect_swapped(self->vnc, "vnc-bell", + G_CALLBACK(virt_viewer_display_vnc_bell), NULL); + g_signal_connect_swapped(self->vnc, "vnc-auth-failure", + G_CALLBACK(virt_viewer_display_vnc_auth_failure), viewer); + g_signal_connect_swapped(self->vnc, "vnc-auth-unsupported", + G_CALLBACK(virt_viewer_display_vnc_auth_unsupported), viewer); + g_signal_connect_swapped(self->vnc, "vnc-server-cut-text", + G_CALLBACK(virt_viewer_server_cut_text), viewer); + + g_signal_connect(self->vnc, "vnc-pointer-grab", + G_CALLBACK(virt_viewer_display_vnc_mouse_grab), self); + g_signal_connect(self->vnc, "vnc-pointer-ungrab", + G_CALLBACK(virt_viewer_display_vnc_mouse_ungrab), self); + g_signal_connect(self->vnc, "vnc-keyboard-grab", + G_CALLBACK(virt_viewer_display_vnc_key_grab), self); + g_signal_connect(self->vnc, "vnc-keyboard-ungrab", + G_CALLBACK(virt_viewer_display_vnc_key_ungrab), self); + + g_signal_connect(self->vnc, "vnc-auth-credential", + G_CALLBACK(virt_viewer_auth_vnc_credentials), &viewer->pretty_address); + + virt_viewer_add_display_and_realize(viewer); + + g_signal_connect(viewer->align, "size-allocate", + G_CALLBACK(virt_viewer_display_vnc_resize_align), viewer); + + return self; +} + + + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-display-vnc.h b/src/virt-viewer-display-vnc.h new file mode 100644 index 0000000..c0d776f --- /dev/null +++ b/src/virt-viewer-display-vnc.h @@ -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 + */ +#ifndef _VIRT_VIEWER_DISPLAY_VNC_H +#define _VIRT_VIEWER_DISPLAY_VNC_H + +#include +#include + +#include "virt-viewer-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 --git a/src/virt-viewer-display.c b/src/virt-viewer-display.c new file mode 100644 index 0000000..b2a1347 --- /dev/null +++ b/src/virt-viewer-display.c @@ -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 + */ +#include "virt-viewer-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 --git a/src/virt-viewer-display.h b/src/virt-viewer-display.h new file mode 100644 index 0000000..6e8057a --- /dev/null +++ b/src/virt-viewer-display.h @@ -0,0 +1,92 @@ +/* + * 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 + */ +#ifndef _VIRT_VIEWER_DISPLAY_H +#define _VIRT_VIEWER_DISPLAY_H + +#include + +#include "virt-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 --git a/src/virt-viewer-events.c b/src/virt-viewer-events.c new file mode 100644 index 0000000..d7d2c9b --- /dev/null +++ b/src/virt-viewer-events.c @@ -0,0 +1,317 @@ +/* + * events.c: event loop integration + * + * Copyright (C) 2008-2009 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + + +#include +#include +#include +#include +#include + +#include "virt-viewer-events.h" + +struct virt_viewer_events_handle +{ + int watch; + int fd; + int events; + int enabled; + GIOChannel *channel; + guint source; + virEventHandleCallback cb; + void *opaque; + virFreeCallback ff; +}; + +static int nextwatch = 1; +static unsigned int nhandles = 0; +static struct virt_viewer_events_handle **handles = NULL; + +static gboolean +virt_viewer_events_dispatch_handle(GIOChannel *source G_GNUC_UNUSED, + GIOCondition condition, + gpointer opaque) +{ + struct virt_viewer_events_handle *data = opaque; + int events = 0; + + if (condition & G_IO_IN) + events |= VIR_EVENT_HANDLE_READABLE; + if (condition & G_IO_OUT) + events |= VIR_EVENT_HANDLE_WRITABLE; + if (condition & G_IO_HUP) + events |= VIR_EVENT_HANDLE_HANGUP; + if (condition & G_IO_ERR) + events |= VIR_EVENT_HANDLE_ERROR; + + DEBUG_LOG("Dispatch handler %d %d %p\n", data->fd, events, data->opaque); + + (data->cb)(data->watch, data->fd, events, data->opaque); + + return TRUE; +} + + +static +int virt_viewer_events_add_handle(int fd, + int events, + virEventHandleCallback cb, + void *opaque, + virFreeCallback ff) +{ + struct virt_viewer_events_handle *data; + GIOCondition cond = 0; + + handles = g_realloc(handles, sizeof(*handles)*(nhandles+1)); + data = g_malloc(sizeof(*data)); + memset(data, 0, sizeof(*data)); + + if (events & VIR_EVENT_HANDLE_READABLE) + cond |= G_IO_IN; + if (events & VIR_EVENT_HANDLE_WRITABLE) + cond |= G_IO_OUT; + + data->watch = nextwatch++; + data->fd = fd; + data->events = events; + data->cb = cb; + data->opaque = opaque; + data->channel = g_io_channel_unix_new(fd); + data->ff = ff; + + DEBUG_LOG("Add handle %d %d %p\n", data->fd, events, data->opaque); + + data->source = g_io_add_watch(data->channel, + cond, + virt_viewer_events_dispatch_handle, + data); + + handles[nhandles++] = data; + + return data->watch; +} + +static struct virt_viewer_events_handle * +virt_viewer_events_find_handle(int watch) +{ + unsigned int i; + for (i = 0 ; i < nhandles ; i++) + if (handles[i]->watch == watch) + return handles[i]; + + return NULL; +} + +static void +virt_viewer_events_update_handle(int watch, + int events) +{ + struct virt_viewer_events_handle *data = virt_viewer_events_find_handle(watch); + + if (!data) { + DEBUG_LOG("Update for missing handle watch %d", watch); + return; + } + + if (events) { + GIOCondition cond = 0; + if (events == data->events) + return; + + if (data->source) + g_source_remove(data->source); + + cond |= G_IO_HUP; + if (events & VIR_EVENT_HANDLE_READABLE) + cond |= G_IO_IN; + if (events & VIR_EVENT_HANDLE_WRITABLE) + cond |= G_IO_OUT; + data->source = g_io_add_watch(data->channel, + cond, + virt_viewer_events_dispatch_handle, + data); + data->events = events; + } else { + if (!data->source) + return; + + g_source_remove(data->source); + data->source = 0; + data->events = 0; + } +} + +static int +virt_viewer_events_remove_handle(int watch) +{ + struct virt_viewer_events_handle *data = virt_viewer_events_find_handle(watch); + + if (!data) { + DEBUG_LOG("Remove of missing watch %d", watch); + return -1; + } + + DEBUG_LOG("Remove handle %d %d\n", watch, data->fd); + + g_source_remove(data->source); + data->source = 0; + data->events = 0; + if (data->ff) + (data->ff)(data->opaque); + free(data); + + return 0; +} + +struct virt_viewer_events_timeout +{ + int timer; + int interval; + guint source; + virEventTimeoutCallback cb; + void *opaque; + virFreeCallback ff; +}; + + +static int nexttimer = 1; +static unsigned int ntimeouts = 0; +static struct virt_viewer_events_timeout **timeouts = NULL; + +static gboolean +virt_viewer_events_dispatch_timeout(void *opaque) +{ + struct virt_viewer_events_timeout *data = opaque; + DEBUG_LOG("Dispatch timeout %p %p %d %p\n", data, data->cb, data->timer, data->opaque); + (data->cb)(data->timer, data->opaque); + + return TRUE; +} + +static int +virt_viewer_events_add_timeout(int interval, + virEventTimeoutCallback cb, + void *opaque, + virFreeCallback ff) +{ + struct virt_viewer_events_timeout *data; + + timeouts = g_realloc(timeouts, sizeof(*timeouts)*(ntimeouts+1)); + data = g_malloc(sizeof(*data)); + memset(data, 0, sizeof(*data)); + + data->timer = nexttimer++; + data->interval = interval; + data->cb = cb; + data->opaque = opaque; + data->ff = ff; + if (interval >= 0) + data->source = g_timeout_add(interval, + virt_viewer_events_dispatch_timeout, + data); + + timeouts[ntimeouts++] = data; + + DEBUG_LOG("Add timeout %p %d %p %p %d\n", data, interval, cb, opaque, data->timer); + + return data->timer; +} + + +static struct virt_viewer_events_timeout * +virt_viewer_events_find_timeout(int timer) +{ + unsigned int i; + for (i = 0 ; i < ntimeouts ; i++) + if (timeouts[i]->timer == timer) + return timeouts[i]; + + return NULL; +} + + +static void +virt_viewer_events_update_timeout(int timer, + int interval) +{ + struct virt_viewer_events_timeout *data = virt_viewer_events_find_timeout(timer); + + if (!data) { + DEBUG_LOG("Update of missing timer %d", timer); + return; + } + + DEBUG_LOG("Update timeout %p %d %d\n", data, timer, interval); + + if (interval >= 0) { + if (data->source) + return; + + data->interval = interval; + data->source = g_timeout_add(data->interval, + virt_viewer_events_dispatch_timeout, + data); + } else { + if (!data->source) + return; + + g_source_remove(data->source); + data->source = 0; + } +} + +static int +virt_viewer_events_remove_timeout(int timer) +{ + struct virt_viewer_events_timeout *data = virt_viewer_events_find_timeout(timer); + + if (!data) { + DEBUG_LOG("Remove of missing timer %d", timer); + return -1; + } + + DEBUG_LOG("Remove timeout %p %d\n", data, timer); + + if (!data->source) + return -1; + + g_source_remove(data->source); + data->source = 0; + + if (data->ff) + (data->ff)(data->opaque); + + free(data); + + return 0; +} + + +void virt_viewer_events_register(void) { + virEventRegisterImpl(virt_viewer_events_add_handle, + virt_viewer_events_update_handle, + virt_viewer_events_remove_handle, + virt_viewer_events_add_timeout, + virt_viewer_events_update_timeout, + virt_viewer_events_remove_timeout); +} + diff --git a/src/virt-viewer-events.h b/src/virt-viewer-events.h new file mode 100644 index 0000000..44ff8d7 --- /dev/null +++ b/src/virt-viewer-events.h @@ -0,0 +1,30 @@ +/* + * events.h: event loop integration + * + * Copyright (C) 2008-2009 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#ifndef VIRT_VIEWER_EVENT_H +#define VIRT_VIEWER_EVENT_H + +#include "virt-viewer-util.h" + +void virt_viewer_events_register(void); + +#endif diff --git a/src/virt-viewer-main.c b/src/virt-viewer-main.c new file mode 100644 index 0000000..b176022 --- /dev/null +++ b/src/virt-viewer-main.c @@ -0,0 +1,122 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007 Red Hat, + * + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include "virt-viewer.h" + +static void virt_viewer_version(void) +{ + g_print(_("%s version %s\n"), PACKAGE, VERSION); + + exit(0); +} + + +int main(int argc, char **argv) +{ + GOptionContext *context; + GError *error = NULL; + int ret; + char *uri = NULL; + int zoom = 100; + gchar **args = NULL; + gboolean verbose = FALSE; + gboolean debug = FALSE; + gboolean direct = FALSE; + gboolean waitvm = FALSE; + gboolean reconnect = FALSE; + const char *help_msg = N_("Run '" PACKAGE " --help' to see a full list of available command line options"); + const GOptionEntry options [] = { + { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, + virt_viewer_version, N_("display version information"), NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + N_("display verbose information"), NULL }, + { "direct", 'd', 0, G_OPTION_ARG_NONE, &direct, + N_("direct connection with no automatic tunnels"), NULL }, + { "connect", 'c', 0, G_OPTION_ARG_STRING, &uri, + N_("connect to hypervisor"), "URI"}, + { "wait", 'w', 0, G_OPTION_ARG_NONE, &waitvm, + N_("wait for domain to start"), NULL }, + { "reconnect", 'r', 0, G_OPTION_ARG_NONE, &reconnect, + N_("reconnect to domain upon restart"), NULL }, + { "zoom", 'z', 0, G_OPTION_ARG_INT, &zoom, + N_("Zoom level of window, in percentage"), "ZOOM" }, + { "debug", '\0', 0, G_OPTION_ARG_NONE, &debug, + N_("display debugging information"), NULL }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args, + NULL, "DOMAIN-NAME|ID|UUID" }, + { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } + }; + + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); + + /* Setup command line options */ + context = g_option_context_new (_("- Virtual machine graphical console")); + g_option_context_add_main_entries (context, options, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_add_group (context, vnc_display_get_option_group ()); + g_option_context_parse (context, &argc, &argv, &error); + if (error) { + g_printerr("%s\n%s\n", + error->message, + gettext(help_msg)); + g_error_free(error); + return 1; + } + + g_option_context_free(context); + + if (!args || (g_strv_length(args) != 1)) { + fprintf(stderr, _("\nUsage: %s [OPTIONS] DOMAIN-NAME|ID|UUID\n\n%s\n\n"), argv[0], help_msg); + return 1; + } + + if (zoom < 10 || zoom > 200) { + fprintf(stderr, "Zoom level must be within 10-200\n"); + return 1; + } + + ret = virt_viewer_start(uri, args[0], zoom, direct, waitvm, reconnect, verbose, debug, NULL); + if (ret != 0) + return ret; + + gtk_main(); + + return 0; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-priv.h b/src/virt-viewer-priv.h new file mode 100644 index 0000000..1cadda2 --- /dev/null +++ b/src/virt-viewer-priv.h @@ -0,0 +1,131 @@ +/* + * 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 + */ +#ifndef _VIRT_VIEWER_PRIV_H +# define _VIRT_VIEWER_PRIV_H + +#include +#include + +#include +#include +#include +#include + +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; + + GtkBuilder *builder; + GtkWidget *window; + GtkWidget *container; + + GtkWidget *notebook; + GtkWidget *align; + GtkWidget *status; + + GtkWidget *toolbar; + GtkWidget *layout; + + 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 *unixsock; + char *ghost; + char *gport; + char *host; + char *transport; + char *user; + int port; +}; + +struct _VirtViewerSize { + VirtViewer *viewer; + gint width, height; + gulong sig_id; +}; + +void virt_viewer_connected(VirtViewer *viewer); +void virt_viewer_initialized(VirtViewer *viewer); +void virt_viewer_disconnected(VirtViewer *viewer); +void virt_viewer_set_status(VirtViewer *viewer, const char *text); +void virt_viewer_set_title(VirtViewer *viewer, gboolean grabbed); +void virt_viewer_enable_modifiers(VirtViewer *viewer); +void virt_viewer_disable_modifiers(VirtViewer *viewer); +void virt_viewer_add_display_and_realize(VirtViewer *viewer); +void virt_viewer_server_cut_text(VirtViewer *viewer, const gchar *text); +void virt_viewer_resize_main_window(VirtViewer *viewer); +void virt_viewer_channel_open_fd(VirtViewer *viewer, VirtViewerDisplayChannel *channel); +void virt_viewer_quit(VirtViewer *viewer); + +void virt_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 --git a/src/virt-viewer-util.c b/src/virt-viewer-util.c new file mode 100644 index 0000000..bda80a4 --- /dev/null +++ b/src/virt-viewer-util.c @@ -0,0 +1,61 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007-2009 Red Hat, + * Copyright (C) 2009 Daniel P. Berrange + * + * 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 + */ + +#include + +#include +#include +#include + +#include "virt-viewer-util.h" + +GtkBuilder *virt_viewer_util_load_ui(const char *name) +{ + struct stat sb; + GtkBuilder *builder; + GError *error = NULL; + + builder = gtk_builder_new(); + if (stat(name, &sb) >= 0) { + gtk_builder_add_from_file(builder, name, &error); + } else { + gchar *path = g_strdup_printf("%s/%s", BUILDER_XML_DIR, name); + gtk_builder_add_from_file(builder, path, &error); + g_free(path); + } + + if (error) + g_error("Cannot load UI description %s: %s", name, + error->message); + + return builder; +} + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-util.h b/src/virt-viewer-util.h new file mode 100644 index 0000000..2c067ad --- /dev/null +++ b/src/virt-viewer-util.h @@ -0,0 +1,37 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007-2009 Red Hat, + * Copyright (C) 2009 Daniel P. Berrange + * + * 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 + */ + +#ifndef VIRT_VIEWER_UTIL_H +#define VIRT_VIEWER_UTIL_H + +#include + +extern gboolean doDebug; + +#define DEBUG_LOG(s, ...) do { if (doDebug) g_debug((s), ## __VA_ARGS__); } while (0) +#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array)) + + +GtkBuilder *virt_viewer_util_load_ui(const char *name); + +#endif diff --git a/src/virt-viewer.c b/src/virt-viewer.c new file mode 100644 index 0000000..a8f6a6f --- /dev/null +++ b/src/virt-viewer.c @@ -0,0 +1,1496 @@ +/* + * 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 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_SYS_UN_H +#include +#endif + +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "virt-viewer.h" +#include "virt-viewer-priv.h" +#include "virt-viewer-events.h" +#include "virt-viewer-auth.h" +#include "virt-viewer-display-vnc.h" + +#ifdef HAVE_SPICE_GTK +#include "virt-viewer-display-spice.h" +#endif + +#include "view/autoDrawer.h" + +#define SCALE(x) do { x = viewer->fullscreen ? x : x * viewer->zoomlevel / 100; } while (0); + +gboolean doDebug = FALSE; + +/* Signal handlers for main window */ +void virt_viewer_menu_view_zoom_out(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_menu_view_zoom_in(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_menu_view_zoom_reset(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_delete(GtkWidget *src, void *dummy, VirtViewer *viewer); +void virt_viewer_menu_file_quit(GtkWidget *src, VirtViewer *viewer); +void virt_viewer_menu_help_about(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_menu_view_fullscreen(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_menu_view_resize(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_menu_send(GtkWidget *menu, VirtViewer *viewer); +void virt_viewer_menu_file_screenshot(GtkWidget *menu, VirtViewer *viewer); + +/* Signal handlers for about dialog */ +void virt_viewer_about_close(GtkWidget *dialog, VirtViewer *viewer); +void virt_viewer_about_delete(GtkWidget *dialog, void *dummy, VirtViewer *viewer); + +static const char * const menuNames[LAST_MENU] = { + "menu-file", "menu-view", "menu-send", "menu-help" +}; + + +#define MAX_KEY_COMBO 3 +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"}, +}; + + +static gboolean virt_viewer_connect_timer(void *opaque); +static int virt_viewer_initial_connect(VirtViewer *viewer); + + +void +virt_viewer_simple_message_dialog(GtkWidget *window, + const char *fmt, ...) +{ + GtkWidget *dialog; + char *msg; + va_list vargs; + + va_start(vargs, fmt); + + msg = g_strdup_vprintf(fmt, vargs); + + va_end(vargs); + + dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", + msg); + + gtk_dialog_run(GTK_DIALOG(dialog)); + + gtk_widget_destroy(dialog); + + g_free(msg); +} + + +void +virt_viewer_add_display_and_realize(VirtViewer *viewer) +{ + g_return_if_fail(viewer != NULL); + g_return_if_fail(viewer->display != NULL); + g_return_if_fail(viewer->display->widget != NULL); + + gtk_container_add(GTK_CONTAINER(viewer->align), viewer->display->widget); + + if (!viewer->window) { + gtk_container_add(GTK_CONTAINER(viewer->container), GTK_WIDGET(viewer->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 + * allows us to set the fixed size, but then allow the user + * to later resize it smaller again + */ +static gboolean +virt_viewer_unset_widget_size_cb(gpointer data) +{ + GtkWidget *widget = data; + DEBUG_LOG("Unset requisition on widget=%p", widget); + + gtk_widget_queue_resize_no_redraw (widget); + + return FALSE; +} + +/* + * This sets the actual size of the widget, and then + * sets an idle callback to resize again, without constraints + * activated + */ +static gboolean +virt_viewer_set_widget_size_cb(GtkWidget *widget, + GtkRequisition *req, + gpointer data) +{ + VirtViewerSize *size = data; + DEBUG_LOG("Set requisition on widget=%p to %dx%d", widget, size->width, size->height); + + req->width = size->width; + req->height = size->height; + + g_signal_handler_disconnect(widget, size->sig_id); + g_free(size); + g_idle_add(virt_viewer_unset_widget_size_cb, widget); + + return FALSE; +} + + +/* + * Registers a callback used to set the widget size once + */ +static void +virt_viewer_set_widget_size(VirtViewer *viewer, + GtkWidget *widget, + int width, + int height) +{ + VirtViewerSize *size = g_new (VirtViewerSize, 1); + DEBUG_LOG("Queue resize widget=%p width=%d height=%d", widget, width, height); + size->viewer = viewer; + size->width = width; + size->height = height; + size->sig_id = g_signal_connect + (widget, "size-request", + G_CALLBACK (virt_viewer_set_widget_size_cb), + size); + + gtk_widget_queue_resize (widget); +} + + +/* + * This code attempts to resize the top level window to be large enough + * 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 + */ +void +virt_viewer_resize_main_window(VirtViewer *viewer) +{ + GdkRectangle fullscreen; + GdkScreen *screen; + int width, height; + double desktopAspect; + double screenAspect; + + DEBUG_LOG("Preparing main window resize"); + if (!viewer->active) { + DEBUG_LOG("Skipping inactive resize"); + return; + } + + gtk_window_resize(GTK_WINDOW (viewer->window), 1, 1); + + screen = gdk_drawable_get_screen(gtk_widget_get_window(viewer->window)); + gdk_screen_get_monitor_geometry(screen, + gdk_screen_get_monitor_at_window + (screen, gtk_widget_get_window(viewer->window)), + &fullscreen); + + desktopAspect = (double)viewer->desktopWidth / (double)viewer->desktopHeight; + screenAspect = (double)(fullscreen.width - 128) / (double)(fullscreen.height - 128); + + if ((viewer->desktopWidth > (fullscreen.width - 128)) || + (viewer->desktopHeight > (fullscreen.height - 128))) { + /* Doesn't fit native res, so go as large as possible + maintaining aspect ratio */ + if (screenAspect > desktopAspect) { + width = viewer->desktopHeight * desktopAspect; + height = viewer->desktopHeight; + } else { + width = viewer->desktopWidth; + height = viewer->desktopWidth / desktopAspect; + } + } else { + width = viewer->desktopWidth; + height = viewer->desktopHeight; + } + + SCALE(width); + SCALE(height); + + virt_viewer_set_widget_size(viewer, + viewer->align, + width, + height); +} + +void +virt_viewer_menu_view_zoom_out(GtkWidget *menu G_GNUC_UNUSED, + VirtViewer *viewer) +{ + viewer->zoomlevel -= 10; + if (viewer->zoomlevel < 10) + viewer->zoomlevel = 10; + + virt_viewer_resize_main_window(viewer); +} + +void +virt_viewer_menu_view_zoom_in(GtkWidget *menu G_GNUC_UNUSED, + VirtViewer *viewer) +{ + viewer->zoomlevel += 10; + if (viewer->zoomlevel > 200) + viewer->zoomlevel = 200; + + virt_viewer_resize_main_window(viewer); +} + +void +virt_viewer_menu_view_zoom_reset(GtkWidget *menu G_GNUC_UNUSED, + VirtViewer *viewer) +{ + viewer->zoomlevel = 100; + + virt_viewer_resize_main_window(viewer); +} + +void +virt_viewer_set_title(VirtViewer *viewer, + gboolean grabbed) +{ + char *title; + const char *subtitle; + + if (!viewer->window) + return; + + if (grabbed) + subtitle = "(Press Ctrl+Alt to release pointer) "; + else + subtitle = ""; + + title = g_strdup_printf("%s%s - Virt Viewer", + subtitle, viewer->domtitle); + + gtk_window_set_title(GTK_WINDOW(viewer->window), title); + + g_free(title); +} + +static gboolean +virt_viewer_ignore_accel(GtkWidget *menu G_GNUC_UNUSED, + VirtViewer *viewer G_GNUC_UNUSED) +{ + /* ignore accelerator */ + return TRUE; +} + + +void +virt_viewer_disable_modifiers(VirtViewer *viewer) +{ + GtkSettings *settings = gtk_settings_get_default(); + GValue empty; + GSList *accels; + int i; + + if (!viewer->window) + return; + + if (!viewer->accelEnabled) + return; + + /* This stops F10 activating menu bar */ + memset(&empty, 0, sizeof empty); + g_value_init(&empty, G_TYPE_STRING); + g_object_get_property(G_OBJECT(settings), "gtk-menu-bar-accel", &viewer->accelSetting); + g_object_set_property(G_OBJECT(settings), "gtk-menu-bar-accel", &empty); + + /* This stops global accelerators like Ctrl+Q == Quit */ + for (accels = viewer->accelList ; accels ; accels = accels->next) { + gtk_window_remove_accel_group(GTK_WINDOW(viewer->window), accels->data); + } + + /* This stops menu bar shortcuts like Alt+F == File */ + for (i = 0 ; i < LAST_MENU ; i++) { + GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, menuNames[i])); + viewer->accelMenuSig[i] = + g_signal_connect(menu, "mnemonic-activate", + G_CALLBACK(virt_viewer_ignore_accel), viewer); + } + + viewer->accelEnabled = FALSE; +} + + +void +virt_viewer_enable_modifiers(VirtViewer *viewer) +{ + GtkSettings *settings = gtk_settings_get_default(); + GSList *accels; + int i; + + if (!viewer->window) + return; + + if (viewer->accelEnabled) + return; + + /* This allows F10 activating menu bar */ + g_object_set_property(G_OBJECT(settings), "gtk-menu-bar-accel", &viewer->accelSetting); + + /* This allows global accelerators like Ctrl+Q == Quit */ + for (accels = viewer->accelList ; accels ; accels = accels->next) { + gtk_window_add_accel_group(GTK_WINDOW(viewer->window), accels->data); + } + + /* This allows menu bar shortcuts like Alt+F == File */ + for (i = 0 ; i < LAST_MENU ; i++) { + GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, menuNames[i])); + g_signal_handler_disconnect(menu, viewer->accelMenuSig[i]); + } + + viewer->accelEnabled = TRUE; +} + +void +virt_viewer_quit(VirtViewer *viewer) +{ + g_return_if_fail(viewer != NULL); + + if (viewer->display) + virt_viewer_display_close(viewer->display); + gtk_main_quit(); +} + +void +virt_viewer_delete(GtkWidget *src G_GNUC_UNUSED, + void *dummy G_GNUC_UNUSED, + VirtViewer *viewer) +{ + virt_viewer_quit(viewer); +} + +void +virt_viewer_menu_file_quit(GtkWidget *src G_GNUC_UNUSED, + VirtViewer *viewer) +{ + virt_viewer_quit(viewer); +} + + +static void +virt_viewer_leave_fullscreen(VirtViewer *viewer) +{ + GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "top-menu")); + if (!viewer->fullscreen) + return; + viewer->fullscreen = FALSE; + ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(viewer->layout), FALSE); + gtk_widget_show(menu); + gtk_widget_hide(viewer->toolbar); + gtk_window_unfullscreen(GTK_WINDOW(viewer->window)); + if (viewer->autoResize) + virt_viewer_resize_main_window(viewer); +} + +static void +virt_viewer_enter_fullscreen(VirtViewer *viewer) +{ + GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "top-menu")); + if (viewer->fullscreen) + return; + viewer->fullscreen = TRUE; + gtk_widget_hide(menu); + gtk_window_fullscreen(GTK_WINDOW(viewer->window)); + gtk_widget_show(viewer->toolbar); + ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(viewer->layout), TRUE); +} + + +static void +virt_viewer_toolbar_leave_fullscreen(GtkWidget *button G_GNUC_UNUSED, + VirtViewer *viewer) +{ + GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "menu-view-fullscreen")); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE); + virt_viewer_leave_fullscreen(viewer); +} + + +void +virt_viewer_menu_view_fullscreen(GtkWidget *menu, + VirtViewer *viewer) +{ + if (!viewer->window) + return; + + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu))) { + virt_viewer_enter_fullscreen(viewer); + } else { + virt_viewer_leave_fullscreen(viewer); + } +} + +void +virt_viewer_menu_view_resize(GtkWidget *menu, + VirtViewer *viewer) +{ + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu))) { + viewer->autoResize = TRUE; + if (!viewer->fullscreen) + virt_viewer_resize_main_window(viewer); + } else { + viewer->autoResize = FALSE; + } +} + +void +virt_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)); + + 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 +virt_viewer_save_screenshot(VirtViewer *viewer, + const char *file) +{ + 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); +} + + +void +virt_viewer_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED, + VirtViewer *viewer) +{ + GtkWidget *dialog; + + g_return_if_fail(viewer->display != NULL); + + dialog = gtk_file_chooser_dialog_new ("Save screenshot", + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + + //gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), default_folder_for_saving); + //gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "Screenshot"); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + virt_viewer_save_screenshot(viewer, filename); + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +void +virt_viewer_about_close(GtkWidget *dialog, + VirtViewer *viewer G_GNUC_UNUSED) +{ + gtk_widget_hide(dialog); + gtk_widget_destroy(dialog); +} + +void +virt_viewer_about_delete(GtkWidget *dialog, + void *dummy G_GNUC_UNUSED, + VirtViewer *viewer G_GNUC_UNUSED) +{ + gtk_widget_hide(dialog); + gtk_widget_destroy(dialog); +} + +void +virt_viewer_menu_help_about(GtkWidget *menu G_GNUC_UNUSED, + VirtViewer *viewer) +{ + GtkBuilder *about = virt_viewer_util_load_ui("virt-viewer-about.xml"); + + GtkWidget *dialog = GTK_WIDGET(gtk_builder_get_object(about, "about")); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION); + + gtk_builder_connect_signals(about, viewer); + + gtk_widget_show_all(dialog); + + g_object_unref(G_OBJECT(about)); +} + + +static int +virt_viewer_parse_uuid(const char *name, + unsigned char *uuid) +{ + int i; + + const char *cur = name; + for (i = 0;i < 16;) { + uuid[i] = 0; + if (*cur == 0) + return -1; + if ((*cur == '-') || (*cur == ' ')) { + cur++; + continue; + } + if ((*cur >= '0') && (*cur <= '9')) + uuid[i] = *cur - '0'; + else if ((*cur >= 'a') && (*cur <= 'f')) + uuid[i] = *cur - 'a' + 10; + else if ((*cur >= 'A') && (*cur <= 'F')) + uuid[i] = *cur - 'A' + 10; + else + return -1; + uuid[i] *= 16; + cur++; + if (*cur == 0) + return -1; + if ((*cur >= '0') && (*cur <= '9')) + uuid[i] += *cur - '0'; + else if ((*cur >= 'a') && (*cur <= 'f')) + uuid[i] += *cur - 'a' + 10; + else if ((*cur >= 'A') && (*cur <= 'F')) + uuid[i] += *cur - 'A' + 10; + else + return -1; + i++; + cur++; + } + + return 0; +} + + +static virDomainPtr +virt_viewer_lookup_domain(VirtViewer *viewer) +{ + char *end; + int id = strtol(viewer->domkey, &end, 10); + virDomainPtr dom = NULL; + unsigned char uuid[16]; + + if (id >= 0 && end && !*end) { + dom = virDomainLookupByID(viewer->conn, id); + } + if (!dom && virt_viewer_parse_uuid(viewer->domkey, uuid) == 0) { + dom = virDomainLookupByUUID(viewer->conn, uuid); + } + if (!dom) { + dom = virDomainLookupByName(viewer->conn, viewer->domkey); + } + return dom; +} + +static int +virt_viewer_matches_domain(VirtViewer *viewer, + virDomainPtr dom) +{ + char *end; + const char *name; + int id = strtol(viewer->domkey, &end, 10); + unsigned char wantuuid[16]; + unsigned char domuuid[16]; + + if (id >= 0 && end && !*end) { + if (virDomainGetID(dom) == id) + return 1; + } + if (virt_viewer_parse_uuid(viewer->domkey, wantuuid) == 0) { + virDomainGetUUID(dom, domuuid); + if (memcmp(wantuuid, domuuid, VIR_UUID_BUFLEN) == 0) + return 1; + } + + name = virDomainGetName(dom); + if (strcmp(name, viewer->domkey) == 0) + return 1; + + return 0; +} + +static char * +virt_viewer_extract_xpath_string(const gchar *xmldesc, + const gchar *xpath) +{ + xmlDocPtr xml = NULL; + xmlParserCtxtPtr pctxt = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + char *port = NULL; + + pctxt = xmlNewParserCtxt(); + if (!pctxt || !pctxt->sax) + goto error; + + xml = xmlCtxtReadDoc(pctxt, (const xmlChar *)xmldesc, "domain.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + if (!xml) + goto error; + + ctxt = xmlXPathNewContext(xml); + if (!ctxt) + goto error; + + obj = xmlXPathEval((const xmlChar *)xpath, ctxt); + if (!obj || obj->type != XPATH_STRING || !obj->stringval || !obj->stringval[0]) + goto error; + if (!strcmp((const char*)obj->stringval, "-1")) + goto error; + + port = g_strdup((const char*)obj->stringval); + xmlXPathFreeObject(obj); + obj = NULL; + + error: + if (obj) + xmlXPathFreeObject(obj); + if (ctxt) + xmlXPathFreeContext(ctxt); + if (xml) + xmlFreeDoc(xml); + if (pctxt) + xmlFreeParserCtxt(pctxt); + return port; +} + + +static int +virt_viewer_extract_host(const char *uristr, + char **host, + char **transport, + char **user, + int *port) +{ + xmlURIPtr uri; + char *offset; + + *host = NULL; + *transport = NULL; + *user = NULL; + + if (uristr == NULL || + !g_strcasecmp(uristr, "xen")) + uristr = "xen:///"; + + uri = xmlParseURI(uristr); + if (!uri || !uri->server) { + *host = g_strdup("localhost"); + } else { + *host = g_strdup(uri->server); + } + + if (uri->user) + *user = g_strdup(uri->user); + *port = uri->port; + + offset = strchr(uri->scheme, '+'); + if (offset) + *transport = g_strdup(offset+1); + + xmlFreeURI(uri); + return 0; +} + +#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) + +static int +virt_viewer_open_tunnel(const char **cmd) +{ + int fd[2]; + pid_t pid; + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) < 0) + return -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]); + return fd[0]; +} + + +static int +virt_viewer_open_tunnel_ssh(const char *sshhost, + int sshport, + const char *sshuser, + const char *host, + const char *port, + const char *unixsock) +{ + const char *cmd[10]; + char portstr[50]; + int n = 0; + + if (!sshport) + sshport = 22; + + sprintf(portstr, "%d", sshport); + + cmd[n++] = "ssh"; + cmd[n++] = "-p"; + cmd[n++] = portstr; + if (sshuser) { + cmd[n++] = "-l"; + cmd[n++] = sshuser; + } + cmd[n++] = sshhost; + cmd[n++] = "nc"; + if (port) { + cmd[n++] = host; + cmd[n++] = port; + } else { + cmd[n++] = "-U"; + cmd[n++] = unixsock; + } + cmd[n++] = NULL; + + return virt_viewer_open_tunnel(cmd); +} + +static int +virt_viewer_open_unix_sock(const char *unixsock) +{ + struct sockaddr_un addr; + int fd; + + memset(&addr, 0, sizeof addr); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, unixsock); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) { + close(fd); + return -1; + } + + return fd; +} + +#endif /* defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) */ + +static void +virt_viewer_trace(VirtViewer *viewer, + const char *fmt, ...) +{ + va_list ap; + + if (doDebug) { + va_start(ap, fmt); + g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fmt, ap); + va_end(ap); + } + + if (viewer->verbose) { + va_start(ap, fmt); + g_vprintf(fmt, ap); + va_end(ap); + } +} + + +void +virt_viewer_set_status(VirtViewer *viewer, + const char *text) +{ + gtk_notebook_set_current_page(GTK_NOTEBOOK(viewer->notebook), 0); + gtk_label_set_text(GTK_LABEL(viewer->status), text); +} + + +static void +virt_viewer_show_display(VirtViewer *viewer) +{ + g_return_if_fail(viewer != NULL); + g_return_if_fail(viewer->display != NULL); + g_return_if_fail(viewer->display->widget != NULL); + + gtk_widget_show(viewer->display->widget); + gtk_widget_grab_focus(viewer->display->widget); + gtk_notebook_set_current_page(GTK_NOTEBOOK(viewer->notebook), 1); +} + +static void +virt_viewer_connect_info_free(VirtViewer *viewer) +{ + free(viewer->host); + free(viewer->ghost); + free(viewer->gport); + free(viewer->transport); + free(viewer->user); + free(viewer->unixsock); + + viewer->host = NULL; + viewer->ghost = NULL; + viewer->gport = NULL; + viewer->transport = NULL; + viewer->user = NULL; + viewer->unixsock = NULL; + viewer->port = 0; +} + +static gboolean +virt_viewer_extract_connect_info(VirtViewer *viewer, + virDomainPtr dom) +{ + char *type = NULL; + char *xpath = NULL; + gboolean retval = FALSE; + char *xmldesc = virDomainGetXMLDesc(dom, 0); + + virt_viewer_connect_info_free(viewer); + + if ((type = virt_viewer_extract_xpath_string(xmldesc, "string(/domain/devices/graphics/@type)")) == NULL) { + virt_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) { + virt_viewer_trace(viewer, "Guest %s has a %s display\n", + viewer->domkey, type); + viewer->display = VIRT_VIEWER_DISPLAY(virt_viewer_display_vnc_new(viewer)); +#ifdef HAVE_SPICE_GTK + } else if (g_strcasecmp(type, "spice") == 0) { + virt_viewer_trace(viewer, "Guest %s has a %s display\n", + viewer->domkey, type); + viewer->display = VIRT_VIEWER_DISPLAY(virt_viewer_display_spice_new(viewer)); +#endif + } else { + virt_viewer_trace(viewer, "Guest %s has unsupported %s display type\n", + viewer->domkey, type); + virt_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 = virt_viewer_extract_xpath_string(xmldesc, xpath)) == NULL) { + free(xpath); + xpath = g_strdup_printf("string(/domain/devices/graphics[@type='%s']/@socket)", type); + if ((viewer->unixsock = virt_viewer_extract_xpath_string(xmldesc, xpath)) == NULL) { + virt_viewer_simple_message_dialog(viewer->window, _("Cannot determine the graphic address for the guest %s"), + viewer->domkey); + goto cleanup; + } + } else { + free(xpath); + xpath = g_strdup_printf("string(/domain/devices/graphics[@type='%s']/@listen)", type); + viewer->ghost = virt_viewer_extract_xpath_string(xmldesc, xpath); + if (viewer->ghost == NULL) + viewer->ghost = g_strdup("localhost"); + } + + if (viewer->gport) + DEBUG_LOG("Guest graphics address is %s:%s", viewer->ghost, viewer->gport); + else + DEBUG_LOG("Guest graphics address is %s", viewer->unixsock); + + if (virt_viewer_extract_host(viewer->uri, &viewer->host, &viewer->transport, &viewer->user, &viewer->port) < 0) { + virt_viewer_simple_message_dialog(viewer->window, _("Cannot determine the host for the guest %s"), + viewer->domkey); + goto cleanup; + } + + retval = TRUE; + +cleanup: + free(xpath); + free(xmldesc); + return retval; +} + +#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) +void +virt_viewer_channel_open_fd(VirtViewer *viewer, + VirtViewerDisplayChannel *channel) +{ + 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 = virt_viewer_open_tunnel_ssh(viewer->host, viewer->port, viewer->user, + viewer->ghost, viewer->gport, NULL)) < 0) + virt_viewer_simple_message_dialog(viewer->window, _("Connect to ssh failed.")); + } else + virt_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 +void +virt_viewer_channel_open_fd(VirtViewer *viewer G_GNUC_UNUSED, + VirtViewerDisplayChannel *channel G_GNUC_UNUSED) +{ + virt_viewer_simple_message_dialog(viewer->window, _("Connect to channel unsupported.")); +} +#endif + +static int +virt_viewer_activate(VirtViewer *viewer, + virDomainPtr dom) +{ + int fd = -1; + int ret = -1; + + if (viewer->active) + goto cleanup; + + virt_viewer_trace(viewer, "Guest %s is running, determining display\n", + viewer->domkey); + if (viewer->display == NULL) { + if (!virt_viewer_extract_connect_info(viewer, dom)) + goto cleanup; + + if (viewer->gport) + viewer->pretty_address = g_strdup_printf("%s:%s", viewer->ghost, viewer->gport); + else + viewer->pretty_address = g_strdup_printf("%s:%s", viewer->host, viewer->unixsock); + } + +#if defined(HAVE_SOCKETPAIR) && defined(HAVE_FORK) + if (viewer->transport && + g_strcasecmp(viewer->transport, "ssh") == 0 && + !viewer->direct) { + if (viewer->gport) { + virt_viewer_trace(viewer, "Opening indirect TCP connection to display at %s:%s\n", + viewer->ghost, viewer->gport); + } else { + virt_viewer_trace(viewer, "Opening indirect UNIX connection to display at %s\n", + viewer->unixsock); + } + virt_viewer_trace(viewer, "Setting up SSH tunnel via %s@%s:%d\n", + viewer->user, viewer->host, viewer->port ? viewer->port : 22); + + if ((fd = virt_viewer_open_tunnel_ssh(viewer->host, viewer->port, + viewer->user, viewer->ghost, + viewer->gport, viewer->unixsock)) < 0) + return -1; + } else if (viewer->unixsock) { + virt_viewer_trace(viewer, "Opening direct UNIX connection to display at %s", + viewer->unixsock); + if ((fd = virt_viewer_open_unix_sock(viewer->unixsock)) < 0) + return -1; + } +#endif + + if (fd >= 0) { + ret = virt_viewer_display_open_fd(viewer->display, fd); + } else { + virt_viewer_trace(viewer, "Opening direct TCP connection to display at %s:%s\n", + viewer->ghost, viewer->gport); + ret = virt_viewer_display_open_host(viewer->display, + viewer->ghost, viewer->gport); + } + + virt_viewer_set_status(viewer, "Connecting to graphic server"); + + free(viewer->domtitle); + viewer->domtitle = g_strdup(virDomainGetName(dom)); + + viewer->connected = FALSE; + viewer->active = TRUE; + virt_viewer_set_title(viewer, FALSE); + +cleanup: + return ret; +} + +/* text was actually requested */ +static void +virt_viewer_clipboard_copy(GtkClipboard *clipboard G_GNUC_UNUSED, + GtkSelectionData *data, + guint info G_GNUC_UNUSED, + VirtViewer *viewer) +{ + gtk_selection_data_set_text(data, viewer->clipboard, -1); +} + +void +virt_viewer_server_cut_text(VirtViewer *viewer, + const gchar *text) +{ + GtkClipboard *cb; + gsize a, b; + GtkTargetEntry targets[] = { + {g_strdup("UTF8_STRING"), 0, 0}, + {g_strdup("COMPOUND_TEXT"), 0, 0}, + {g_strdup("TEXT"), 0, 0}, + {g_strdup("STRING"), 0, 0}, + }; + + if (!text) + return; + + g_free (viewer->clipboard); + viewer->clipboard = g_convert (text, -1, "utf-8", "iso8859-1", &a, &b, NULL); + + if (viewer->clipboard) { + cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_set_with_owner (cb, + targets, + G_N_ELEMENTS(targets), + (GtkClipboardGetFunc)virt_viewer_clipboard_copy, + NULL, + G_OBJECT (viewer)); + } +} + +static gboolean +virt_viewer_retryauth(gpointer opaque) +{ + VirtViewer *viewer = opaque; + virt_viewer_initial_connect(viewer); + + return FALSE; +} + +static void +virt_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; + virt_viewer_set_title(viewer, FALSE); + + if (viewer->authretry) { + viewer->authretry = FALSE; + g_idle_add(virt_viewer_retryauth, viewer); + } else if (viewer->reconnect) { + if (!viewer->withEvents) { + DEBUG_LOG("No domain events, falling back to polling"); + g_timeout_add(500, + virt_viewer_connect_timer, + viewer); + } + + virt_viewer_set_status(viewer, "Waiting for guest domain to re-start"); + virt_viewer_trace(viewer, "Guest %s display has disconnected, waiting to reconnect", + viewer->domkey); + } else { + virt_viewer_set_status(viewer, "Guest domain has shutdown"); + virt_viewer_trace(viewer, "Guest %s display has disconnected, shutting down", + viewer->domkey); + gtk_main_quit(); + } +} + +void +virt_viewer_connected(VirtViewer *viewer) +{ + viewer->connected = TRUE; + virt_viewer_set_status(viewer, "Connected to graphic server"); +} + +void +virt_viewer_initialized(VirtViewer *viewer) +{ + virt_viewer_show_display(viewer); + virt_viewer_set_title(viewer, FALSE); +} + +void +virt_viewer_disconnected(VirtViewer *viewer) +{ + if (!viewer->connected) { + virt_viewer_simple_message_dialog(viewer->window, _("Unable to connect to the graphic server %s"), + viewer->pretty_address); + } + virt_viewer_deactivate(viewer); +} + + +static int +virt_viewer_domain_event(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + int event, + int detail G_GNUC_UNUSED, + void *opaque) +{ + VirtViewer *viewer = opaque; + + DEBUG_LOG("Got domain event %d %d", event, detail); + + if (!virt_viewer_matches_domain(viewer, dom)) + return 0; + + switch (event) { + case VIR_DOMAIN_EVENT_STOPPED: + virt_viewer_deactivate(viewer); + break; + + case VIR_DOMAIN_EVENT_STARTED: + virt_viewer_activate(viewer, dom); + break; + } + + return 0; +} + + +static int +virt_viewer_initial_connect(VirtViewer *viewer) +{ + virDomainPtr dom = NULL; + virDomainInfo info; + int ret = -1; + + virt_viewer_set_status(viewer, "Finding guest domain"); + dom = virt_viewer_lookup_domain(viewer); + if (!dom) { + if (viewer->waitvm) { + virt_viewer_set_status(viewer, "Waiting for guest domain to be created"); + virt_viewer_trace(viewer, "Guest %s does not yet exist, waiting for it to be created\n", + viewer->domkey); + goto done; + } else { + virt_viewer_simple_message_dialog(viewer->window, _("Cannot find guest domain %s"), + viewer->domkey); + DEBUG_LOG("Cannot find guest %s", viewer->domkey); + goto cleanup; + } + } + + virt_viewer_set_status(viewer, "Checking guest domain status"); + if (virDomainGetInfo(dom, &info) < 0) { + DEBUG_LOG("Cannot get guest state"); + goto cleanup; + } + + if (info.state == VIR_DOMAIN_SHUTOFF) { + virt_viewer_set_status(viewer, "Waiting for guest domain to start"); + } else { + ret = virt_viewer_activate(viewer, dom); + if (ret < 0) { + if (viewer->waitvm) { + virt_viewer_set_status(viewer, "Waiting for guest domain to start server"); + virt_viewer_trace(viewer, "Guest %s has not activated its display yet, waiting for it to start\n", + viewer->domkey); + } else { + DEBUG_LOG("Failed to activate viewer"); + goto cleanup; + } + } else if (ret == 0) { + DEBUG_LOG("Failed to activate viewer"); + ret = -1; + goto cleanup; + } + } + + done: + ret = 0; + cleanup: + if (dom) + virDomainFree(dom); + return ret; +} + +static gboolean +virt_viewer_connect_timer(void *opaque) +{ + VirtViewer *viewer = opaque; + + DEBUG_LOG("Connect timer fired"); + + if (!viewer->active && + virt_viewer_initial_connect(viewer) < 0) + gtk_main_quit(); + + if (viewer->active) + return FALSE; + + return TRUE; +} + +static void +virt_viewer_toolbar_setup(VirtViewer *viewer) +{ + GtkWidget *button; + + viewer->toolbar = gtk_toolbar_new(); + gtk_toolbar_set_show_arrow(GTK_TOOLBAR(viewer->toolbar), FALSE); + gtk_widget_set_no_show_all(viewer->toolbar, TRUE); + gtk_toolbar_set_style(GTK_TOOLBAR(viewer->toolbar), GTK_TOOLBAR_BOTH_HORIZ); + + /* Close connection */ + button = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_CLOSE)); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), _("Disconnect")); + gtk_widget_show(GTK_WIDGET(button)); + gtk_toolbar_insert(GTK_TOOLBAR(viewer->toolbar), GTK_TOOL_ITEM (button), 0); + g_signal_connect(button, "clicked", G_CALLBACK(gtk_main_quit), NULL); + + /* Leave fullscreen */ + button = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_LEAVE_FULLSCREEN)); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), _("Leave fullscreen")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), _("Leave fullscreen")); + gtk_tool_item_set_is_important(GTK_TOOL_ITEM(button), TRUE); + gtk_widget_show(GTK_WIDGET(button)); + gtk_toolbar_insert(GTK_TOOLBAR(viewer->toolbar), GTK_TOOL_ITEM(button), 0); + g_signal_connect(button, "clicked", G_CALLBACK(virt_viewer_toolbar_leave_fullscreen), viewer); + + viewer->layout = ViewAutoDrawer_New(); + + ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(viewer->layout), FALSE); + ViewOvBox_SetOver(VIEW_OV_BOX(viewer->layout), viewer->toolbar); + ViewOvBox_SetUnder(VIEW_OV_BOX(viewer->layout), viewer->notebook); + ViewAutoDrawer_SetOffset(VIEW_AUTODRAWER(viewer->layout), -1); + ViewAutoDrawer_SetFill(VIEW_AUTODRAWER(viewer->layout), FALSE); + ViewAutoDrawer_SetOverlapPixels(VIEW_AUTODRAWER(viewer->layout), 1); + ViewAutoDrawer_SetNoOverlapPixels(VIEW_AUTODRAWER(viewer->layout), 0); +} + + +static void +virt_viewer_error_func (void *data G_GNUC_UNUSED, + virErrorPtr error G_GNUC_UNUSED) +{ + /* nada */ +} + +int +virt_viewer_start(const char *uri, + const char *name, + gint zoom, + gboolean direct, + gboolean waitvm, + gboolean reconnect, + gboolean verbose, + gboolean debug, + GtkWidget *container) +{ + VirtViewer *viewer; + GtkWidget *menu; + int cred_types[] = + { VIR_CRED_AUTHNAME, VIR_CRED_PASSPHRASE }; + virConnectAuth auth_libvirt = { + .credtype = cred_types, + .ncredtype = ARRAY_CARDINALITY(cred_types), + .cb = virt_viewer_auth_libvirt_credentials, + .cbdata = (void *)uri, + }; + + doDebug = debug; + + viewer = g_new0(VirtViewer, 1); + + viewer->active = FALSE; + viewer->autoResize = TRUE; + viewer->direct = direct; + viewer->waitvm = waitvm; + viewer->reconnect = reconnect; + viewer->verbose = verbose; + viewer->domkey = g_strdup(name); + viewer->uri = g_strdup(uri); + viewer->zoomlevel = zoom; + + g_value_init(&viewer->accelSetting, G_TYPE_STRING); + + virt_viewer_events_register(); + + virSetErrorFunc(NULL, virt_viewer_error_func); + + virt_viewer_trace(viewer, "Opening connection to libvirt with URI %s\n", + uri ? uri : ""); + viewer->conn = virConnectOpenAuth(uri, + //virConnectAuthPtrDefault, + &auth_libvirt, + VIR_CONNECT_RO); + if (!viewer->conn) { + virt_viewer_simple_message_dialog(NULL, _("Unable to connect to libvirt with URI %s"), + uri ? uri : _("[none]")); + return -1; + } + + if (!container) { + viewer->builder = virt_viewer_util_load_ui("virt-viewer.xml"); + + menu = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "menu-view-resize")); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE); + + gtk_builder_connect_signals(viewer->builder, viewer); + } + + viewer->status = gtk_label_new(""); + viewer->align = gtk_alignment_new(0.5, 0.5, 0, 0); + + viewer->notebook = gtk_notebook_new(); + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(viewer->notebook), FALSE); + gtk_notebook_set_show_border(GTK_NOTEBOOK(viewer->notebook), FALSE); + + gtk_notebook_append_page(GTK_NOTEBOOK(viewer->notebook), viewer->status, NULL); + gtk_notebook_append_page(GTK_NOTEBOOK(viewer->notebook), viewer->align, NULL); + + if (container) { + viewer->container = container; + + gtk_box_pack_end(GTK_BOX(container), viewer->notebook, TRUE, TRUE, 0); + gtk_widget_show_all(GTK_WIDGET(container)); + } else { + GtkWidget *vbox = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "viewer-box")); + virt_viewer_toolbar_setup(viewer); + + //gtk_box_pack_end(GTK_BOX(vbox), viewer->toolbar, TRUE, TRUE, 0); + //gtk_box_pack_end(GTK_BOX(vbox), viewer->notebook, TRUE, TRUE, 0); + gtk_box_pack_end(GTK_BOX(vbox), viewer->layout, TRUE, TRUE, 0); + gtk_widget_show_all(GTK_WIDGET(vbox)); + + GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(viewer->builder, "viewer")); + GSList *accels; + viewer->container = window; + viewer->window = window; + gtk_window_set_resizable(GTK_WINDOW(window), TRUE); + viewer->accelEnabled = TRUE; + accels = gtk_accel_groups_from_object(G_OBJECT(window)); + for ( ; accels ; accels = accels->next) { + viewer->accelList = g_slist_append(viewer->accelList, accels->data); + g_object_ref(G_OBJECT(accels->data)); + } + gtk_widget_show_all(viewer->window); + } + + if (virt_viewer_initial_connect(viewer) < 0) + return -1; + + if (virConnectDomainEventRegister(viewer->conn, + virt_viewer_domain_event, + viewer, + NULL) < 0) + viewer->withEvents = FALSE; + else + viewer->withEvents = TRUE; + + if (!viewer->withEvents && + !viewer->active) { + DEBUG_LOG("No domain events, falling back to polling"); + g_timeout_add(500, + virt_viewer_connect_timer, + viewer); + } + + return 0; +} + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer.h b/src/virt-viewer.h new file mode 100644 index 0000000..39bda5a --- /dev/null +++ b/src/virt-viewer.h @@ -0,0 +1,38 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007 Red Hat, + * + * 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 + */ + +#ifndef VIRT_VIEWER_H +#define VIRT_VIEWER_H + +#include "virt-viewer-util.h" + +extern int virt_viewer_start(const char *uri, + const char *name, + gint zoom, + gboolean direct, + gboolean waitvm, + gboolean reconnect, + gboolean verbose, + gboolean debug, + GtkWidget *container); + +#endif /* VIRT_VIEWER_H */ diff --git a/src/virt-viewer.xml b/src/virt-viewer.xml new file mode 100644 index 0000000..8f2eb0b --- /dev/null +++ b/src/virt-viewer.xml @@ -0,0 +1,291 @@ + + + + + + 400 + 400 + + + + True + vertical + + + True + + + True + _File + True + + + True + + + True + Screenshot + True + + + + + + True + + + + + gtk-quit + True + True + True + + + + + + + + + + True + _View + True + + + True + + + True + Full screen + True + + + + + + True + _Zoom + True + + + True + + + True + gtk-zoom-in + + + + + + + True + gtk-zoom-out + + + + + + + True + + + + + True + gtk-zoom-100 + + + + + + + + + + + True + Automatically resize + True + + + + + + + + + + True + _Send key + True + + + True + + + True + Ctrl+Alt+_Del + True + + + + + + True + Ctrl+Alt+_Backspace + True + + + + + + True + + + + + True + Ctrl+Alt+F_1 + True + + + + + + True + Ctrl+Alt+F_2 + True + + + + + + True + Ctrl+Alt+F_3 + True + + + + + + True + Ctrl+Alt+F_4 + True + + + + + + True + Ctrl+Alt+F_5 + True + + + + + + True + Ctrl+Alt+F_6 + True + + + + + + True + Ctrl+Alt+F_7 + True + + + + + + True + Ctrl+Alt+F_8 + True + + + + + + True + Ctrl+Alt+F_9 + True + + + + + + True + Ctrl+Alt+F1_0 + True + + + + + + True + Ctrl+Alt+F11 + True + + + + + + True + Ctrl+Alt+F12 + True + + + + + + True + + + + + True + _PrintScreen + True + + + + + + + + + + True + _Help + True + + + True + + + gtk-about + True + True + True + + + + + + + + + + False + 0 + + + + + + diff --git a/virt-viewer.spec.in b/virt-viewer.spec.in index ec14bcf..f1aed0b 100644 --- a/virt-viewer.spec.in +++ b/virt-viewer.spec.in @@ -97,9 +97,9 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/%{name} %dir %{_datadir}/%{name} %dir %{_datadir}/%{name}/ui/ -%{_datadir}/%{name}/ui/auth.xml -%{_datadir}/%{name}/ui/about.xml -%{_datadir}/%{name}/ui/viewer.xml +%{_datadir}/%{name}/ui/virt-viewer.xml +%{_datadir}/%{name}/ui/virt-viewer-auth.xml +%{_datadir}/%{name}/ui/virt-viewer-about.xml %{_mandir}/man1/%{name}* %if %{_with_plugin} -- cgit