Port to GtkApplication API's

Most of this patch consists in code being shuffled around to fit the
expected flow while using the new APIs. I tried my best to make this
patch the less intrusive as possible. Main changes are:

- Updated build requirements
   * glib version 2.38
   * gtk+ version 3.10
   * gio

- VirtViewerApp is now a subclass of GtkApplication.
  Some mainloop calls were replaced:
   * gtk_main() -> g_application_run()
   * gtk_quit() -> g_application_quit()

- Unified command line option handling.
  The logic has moved from the main functions and split in common
  options, and specific ones for each application. With this, the main
  functions were highly simplified, and now basically responsible for
  instantiating the App object and running the main loop.

- All Window objects must be associated with the Application.
  With this, there is no need to emit our own 'window-added'/'window-
  removed' signals, as those will be emited by GtkApplication whenever
  gtk_application_add_window() and gtk_application_remove_window() are
  called. Also, 'window-removed' was not being used anywhere.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
This commit is contained in:
Eduardo Lima (Etrunko) 2015-12-09 18:11:37 -02:00 committed by Fabiano Fidêncio
parent 7a54b96dbe
commit a9ce19f848
11 changed files with 364 additions and 405 deletions

View File

@ -12,10 +12,10 @@ AC_CANONICAL_HOST
m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])
AM_SILENT_RULES([yes])
GLIB2_REQUIRED=2.22.0
GLIB2_REQUIRED="2.38.0"
LIBXML2_REQUIRED="2.6.0"
LIBVIRT_REQUIRED="0.10.0"
GTK_REQUIRED="3.0"
GTK_REQUIRED="3.10"
GTK_VNC_REQUIRED="0.4.0"
SPICE_GTK_REQUIRED="0.30"
SPICE_PROTOCOL_REQUIRED="0.12.7"
@ -93,7 +93,7 @@ PKG_PROG_PKG_CONFIG
GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
AC_SUBST(GLIB_MKENUMS)
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= $GLIB2_REQUIRED gthread-2.0 gmodule-export-2.0)
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= $GLIB2_REQUIRED gio-2.0 gthread-2.0 gmodule-export-2.0)
PKG_CHECK_MODULES(LIBXML2, libxml-2.0 >= $LIBXML2_REQUIRED)
AC_ARG_WITH([libvirt],

View File

@ -22,184 +22,24 @@
#include <config.h>
#include <locale.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <stdlib.h>
#ifdef G_OS_WIN32
#include <windows.h>
#include <io.h>
#endif
#ifdef HAVE_GTK_VNC
#include <vncdisplay.h>
#endif
#ifdef HAVE_SPICE_GTK
#include <spice-option.h>
#endif
#ifdef HAVE_OVIRT
#include <govirt/ovirt-options.h>
#endif
#include "remote-viewer.h"
#include "virt-viewer-app.h"
#include "virt-viewer-session.h"
static void
remote_viewer_version(void)
{
g_print(_("remote-viewer version %s"), VERSION BUILDID);
#ifdef REMOTE_VIEWER_OS_ID
g_print(" (OS ID: %s)", REMOTE_VIEWER_OS_ID);
#endif
g_print("\n");
exit(EXIT_SUCCESS);
}
static void
recent_add(gchar *uri, const gchar *mime_type)
{
GtkRecentManager *recent;
GtkRecentData meta = {
.app_name = (char*)"remote-viewer",
.app_exec = (char*)"remote-viewer %u",
.mime_type = (char*)mime_type,
};
if (uri == NULL)
return;
recent = gtk_recent_manager_get_default();
meta.display_name = uri;
if (!gtk_recent_manager_add_full(recent, uri, &meta))
g_warning("Recent item couldn't be added");
}
static void connected(VirtViewerSession *session,
VirtViewerApp *self G_GNUC_UNUSED)
{
gchar *uri = virt_viewer_session_get_uri(session);
const gchar *mime = virt_viewer_session_mime_type(session);
recent_add(uri, mime);
g_free(uri);
}
int
main(int argc, char **argv)
{
GOptionContext *context;
GError *error = NULL;
int ret = 1;
gchar **args = NULL;
gchar *uri = NULL;
char *title = NULL;
RemoteViewer *viewer = NULL;
#ifdef HAVE_SPICE_GTK
gboolean controller = FALSE;
#endif
VirtViewerApp *app;
const GOptionEntry options [] = {
{ "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
remote_viewer_version, N_("Display version information"), NULL },
{ "title", 't', 0, G_OPTION_ARG_STRING, &title,
N_("Set window title"), NULL },
#ifdef HAVE_SPICE_GTK
{ "spice-controller", '\0', 0, G_OPTION_ARG_NONE, &controller,
N_("Open connection using Spice controller communication"), NULL },
#endif
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args,
NULL, "URI|VV-FILE" },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
GOptionGroup *app_options = NULL;
GApplication *app = NULL;
virt_viewer_util_init(_("Remote Viewer"));
app = G_APPLICATION(remote_viewer_new());
/* Setup command line options */
context = g_option_context_new (NULL);
g_option_context_set_summary(context, _("Remote viewer client"));
app_options = virt_viewer_app_get_option_group();
g_option_group_add_entries (app_options, options);
g_option_context_set_main_group (context, app_options);
g_option_context_add_group (context, gtk_get_option_group (TRUE));
#ifdef HAVE_GTK_VNC
g_option_context_add_group (context, vnc_display_get_option_group ());
#endif
#ifdef HAVE_SPICE_GTK
g_option_context_add_group (context, spice_get_option_group ());
#endif
#ifdef HAVE_OVIRT
g_option_context_add_group (context, ovirt_get_option_group ());
#endif
g_option_context_parse (context, &argc, &argv, &error);
if (error) {
char *base_name;
base_name = g_path_get_basename(argv[0]);
g_printerr(_("%s\nRun '%s --help' to see a full list of available command line options\n"),
error->message, base_name);
g_free(base_name);
goto cleanup;
}
g_option_context_free(context);
#ifdef HAVE_SPICE_GTK
if (controller) {
if (args) {
g_printerr(_("Error: extra arguments given while using Spice controller\n"));
goto cleanup;
}
} else
#endif
if (args) {
if (g_strv_length(args) > 1) {
g_printerr(_("Error: can't handle multiple URIs\n"));
goto cleanup;
} else if (g_strv_length(args) == 1) {
uri = g_strdup(args[0]);
}
}
#ifdef HAVE_SPICE_GTK
if (controller) {
viewer = remote_viewer_new_with_controller();
g_object_set(viewer, "guest-name", "defined by Spice controller", NULL);
} else {
#endif
viewer = remote_viewer_new(uri);
if (title)
g_object_set(viewer, "title", title, NULL);
#ifdef HAVE_SPICE_GTK
}
#endif
if (viewer == NULL)
goto cleanup;
app = VIRT_VIEWER_APP(viewer);
if (!virt_viewer_app_start(app, &error)) {
if (g_error_matches(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_CANCELLED))
ret = 0;
else if (error) {
virt_viewer_app_simple_message_dialog(app, error->message);
}
goto cleanup;
}
g_signal_connect(virt_viewer_app_get_session(app), "session-connected",
G_CALLBACK(connected), app);
gtk_main();
ret = 0;
cleanup:
g_free(uri);
if (viewer)
g_object_unref(viewer);
g_strfreev(args);
g_clear_error(&error);
ret = g_application_run(app, argc, argv);
g_object_unref(app);
return ret;
}

View File

@ -23,6 +23,7 @@
*/
#include <config.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <glib/gi18n.h>
@ -84,8 +85,9 @@ static OvirtVm * choose_vm(GtkWindow *main_window,
static gboolean remote_viewer_start(VirtViewerApp *self, GError **error);
#ifdef HAVE_SPICE_GTK
static gboolean remote_viewer_activate(VirtViewerApp *self, GError **error);
static void remote_viewer_window_added(VirtViewerApp *self, VirtViewerWindow *win);
static void remote_viewer_window_added(GtkApplication *app, GtkWindow *w);
static void spice_foreign_menu_updated(RemoteViewer *self);
static void foreign_menu_title_changed(SpiceCtrlForeignMenu *menu, GParamSpec *pspec, RemoteViewer *self);
#endif
static void
@ -183,11 +185,104 @@ remote_viewer_deactivated(VirtViewerApp *app, gboolean connect_error)
VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->deactivated(app, connect_error);
}
static gchar **opt_args = NULL;
static char *opt_title = NULL;
static gboolean opt_controller = FALSE;
static void
remote_viewer_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group)
{
static const GOptionEntry options[] = {
{ "title", 't', 0, G_OPTION_ARG_STRING, &opt_title,
N_("Set window title"), NULL },
#ifdef HAVE_SPICE_GTK
{ "spice-controller", '\0', 0, G_OPTION_ARG_NONE, &opt_controller,
N_("Open connection using Spice controller communication"), NULL },
#endif
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &opt_args,
NULL, "URI|VV-FILE" },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
VIRT_VIEWER_APP_CLASS(remote_viewer_parent_class)->add_option_entries(self, context, group);
g_option_context_set_summary(context, _("Remote viewer client"));
g_option_group_add_entries(group, options);
#ifdef HAVE_OVIRT
g_option_context_add_group (context, ovirt_get_option_group ());
#endif
}
static gboolean
remote_viewer_local_command_line (GApplication *gapp,
gchar ***args,
int *status)
{
gboolean ret = FALSE;
VirtViewerApp *app = VIRT_VIEWER_APP(gapp);
RemoteViewer *self = REMOTE_VIEWER(app);
ret = G_APPLICATION_CLASS(remote_viewer_parent_class)->local_command_line(gapp, args, status);
if (ret)
goto end;
if (!opt_args) {
self->priv->open_recent_dialog = TRUE;
} else {
if (g_strv_length(opt_args) > 1) {
g_printerr(_("\nError: can't handle multiple URIs\n\n"));
ret = TRUE;
*status = 1;
goto end;
}
g_object_set(app, "guri", opt_args[0], NULL);
}
#ifdef HAVE_SPICE_GTK
if (opt_controller) {
if (opt_args) {
g_printerr(_("\nError: extra arguments given while using Spice controller\n\n"));
ret = TRUE;
*status = 1;
goto end;
}
SpiceCtrlController *ctrl = spice_ctrl_controller_new();
SpiceCtrlForeignMenu *menu = spice_ctrl_foreign_menu_new();
g_object_set(self, "guest-name", "defined by Spice controller",
"controller", ctrl,
"foreign-menu", menu,
NULL);
g_signal_connect(menu, "notify::title",
G_CALLBACK(foreign_menu_title_changed),
self);
g_object_unref(ctrl);
g_object_unref(menu);
}
#endif
if (opt_title && !opt_controller)
g_object_set(app, "title", opt_title, NULL);
end:
if (ret && *status)
g_printerr(_("Run '%s --help' to see a full list of available command line options\n"), g_get_prgname());
g_strfreev(opt_args);
return ret;
}
static void
remote_viewer_class_init (RemoteViewerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkApplicationClass *gtk_app_class = GTK_APPLICATION_CLASS(klass);
VirtViewerAppClass *app_class = VIRT_VIEWER_APP_CLASS (klass);
GApplicationClass *g_app_class = G_APPLICATION_CLASS(klass);
g_type_class_add_private (klass, sizeof (RemoteViewerPrivate));
@ -195,11 +290,15 @@ remote_viewer_class_init (RemoteViewerClass *klass)
object_class->set_property = remote_viewer_set_property;
object_class->dispose = remote_viewer_dispose;
g_app_class->local_command_line = remote_viewer_local_command_line;
app_class->start = remote_viewer_start;
app_class->deactivated = remote_viewer_deactivated;
app_class->add_option_entries = remote_viewer_add_option_entries;
#ifdef HAVE_SPICE_GTK
app_class->activate = remote_viewer_activate;
app_class->window_added = remote_viewer_window_added;
gtk_app_class->window_added = remote_viewer_window_added;
g_object_class_install_property(object_class,
PROP_CONTROLLER,
@ -208,7 +307,6 @@ remote_viewer_class_init (RemoteViewerClass *klass)
"Spice controller",
SPICE_CTRL_TYPE_CONTROLLER,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property(object_class,
PROP_CTRL_FOREIGN_MENU,
@ -217,8 +315,9 @@ remote_viewer_class_init (RemoteViewerClass *klass)
"Spice foreign menu",
SPICE_CTRL_TYPE_FOREIGN_MENU,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
#else
(void) gtk_app_class;
#endif
g_object_class_install_property(object_class,
PROP_OPEN_RECENT_DIALOG,
@ -227,7 +326,6 @@ remote_viewer_class_init (RemoteViewerClass *klass)
"Open recent dialog",
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
@ -238,11 +336,11 @@ remote_viewer_init(RemoteViewer *self)
}
RemoteViewer *
remote_viewer_new(const gchar *uri)
remote_viewer_new(void)
{
return g_object_new(REMOTE_VIEWER_TYPE,
"guri", uri,
"open-recent-dialog", uri == NULL,
"application-id", "org.virt-manager.remote-viewer",
"flags", G_APPLICATION_NON_UNIQUE,
NULL);
}
@ -265,26 +363,6 @@ foreign_menu_title_changed(SpiceCtrlForeignMenu *menu G_GNUC_UNUSED,
spice_foreign_menu_updated(self);
}
RemoteViewer *
remote_viewer_new_with_controller(void)
{
RemoteViewer *self;
SpiceCtrlController *ctrl = spice_ctrl_controller_new();
SpiceCtrlForeignMenu *menu = spice_ctrl_foreign_menu_new();
self = g_object_new(REMOTE_VIEWER_TYPE,
"controller", ctrl,
"foreign-menu", menu,
NULL);
g_signal_connect(menu, "notify::title",
G_CALLBACK(foreign_menu_title_changed),
self);
g_object_unref(ctrl);
g_object_unref(menu);
return self;
}
static void
spice_ctrl_do_connect(SpiceCtrlController *ctrl G_GNUC_UNUSED,
VirtViewerApp *self)
@ -634,9 +712,11 @@ remote_viewer_activate(VirtViewerApp *app, GError **error)
}
static void
remote_viewer_window_added(VirtViewerApp *app,
VirtViewerWindow *win)
remote_viewer_window_added(GtkApplication *app,
GtkWindow *w)
{
VirtViewerWindow *win = VIRT_VIEWER_WINDOW(
g_object_get_data(G_OBJECT(w), "virt-viewer-window"));
spice_menu_update(REMOTE_VIEWER(app), win);
spice_foreign_menu_update(REMOTE_VIEWER(app), win);
}
@ -742,8 +822,10 @@ authenticate_cb(RestProxy *proxy, G_GNUC_UNUSED RestProxyAuth *auth,
}
static void
ovirt_foreign_menu_update(RemoteViewer *app, VirtViewerWindow *win)
ovirt_foreign_menu_update(GtkApplication *gtkapp, GtkWindow *gtkwin, G_GNUC_UNUSED gpointer data)
{
RemoteViewer *app = REMOTE_VIEWER(gtkapp);
VirtViewerWindow *win = g_object_get_data(G_OBJECT(gtkwin), "virt-viewer-window");
GtkWidget *menu = g_object_get_data(G_OBJECT(win), "foreign-menu");
GtkWidget *submenu;
GtkMenuShell *shell = GTK_MENU_SHELL(gtk_builder_get_object(virt_viewer_window_get_builder(win), "top-menu"));
@ -776,8 +858,9 @@ static void
ovirt_foreign_menu_update_each(gpointer value,
gpointer user_data)
{
ovirt_foreign_menu_update(REMOTE_VIEWER(user_data),
VIRT_VIEWER_WINDOW(value));
ovirt_foreign_menu_update(GTK_APPLICATION(user_data),
virt_viewer_window_get_window(VIRT_VIEWER_WINDOW(value)),
NULL);
}
static void
@ -1059,6 +1142,36 @@ choose_vm(GtkWindow *main_window,
}
#endif
static void
remote_viewer_recent_add(gchar *uri, const gchar *mime_type)
{
GtkRecentManager *recent;
GtkRecentData meta = {
.app_name = (char*)"remote-viewer",
.app_exec = (char*)"remote-viewer %u",
.mime_type = (char*)mime_type,
};
if (uri == NULL)
return;
recent = gtk_recent_manager_get_default();
meta.display_name = uri;
if (!gtk_recent_manager_add_full(recent, uri, &meta))
g_warning("Recent item couldn't be added");
}
static void
remote_viewer_session_connected(VirtViewerSession *session,
VirtViewerApp *self G_GNUC_UNUSED)
{
gchar *uri = virt_viewer_session_get_uri(session);
const gchar *mime = virt_viewer_session_mime_type(session);
remote_viewer_recent_add(uri, mime);
g_free(uri);
}
static gboolean
remote_viewer_start(VirtViewerApp *app, GError **err)
{
@ -1142,6 +1255,9 @@ retry_dialog:
goto cleanup;
}
g_signal_connect(virt_viewer_app_get_session(app), "session-connected",
G_CALLBACK(remote_viewer_session_connected), app);
virt_viewer_session_set_file(virt_viewer_app_get_session(app), vvfile);
#ifdef HAVE_OVIRT
if (vvfile != NULL) {

View File

@ -48,8 +48,7 @@ typedef struct {
GType remote_viewer_get_type (void);
RemoteViewer* remote_viewer_new(const gchar *uri);
RemoteViewer* remote_viewer_new_with_controller(void);
RemoteViewer *remote_viewer_new (void);
G_END_DECLS

View File

@ -32,6 +32,7 @@
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <gio/gio.h>
#include <glib/gprintf.h>
#include <glib/gi18n.h>
@ -102,6 +103,7 @@ static void virt_viewer_app_update_pretty_address(VirtViewerApp *self);
static void virt_viewer_app_set_fullscreen(VirtViewerApp *self, gboolean fullscreen);
static void virt_viewer_app_update_menu_displays(VirtViewerApp *self);
static void virt_viewer_update_smartcard_accels(VirtViewerApp *self);
static void virt_viewer_app_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group);
struct _VirtViewerAppPrivate {
@ -154,7 +156,7 @@ struct _VirtViewerAppPrivate {
};
G_DEFINE_ABSTRACT_TYPE(VirtViewerApp, virt_viewer_app, G_TYPE_OBJECT)
G_DEFINE_ABSTRACT_TYPE(VirtViewerApp, virt_viewer_app, GTK_TYPE_APPLICATION)
#define GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), VIRT_VIEWER_TYPE_APP, VirtViewerAppPrivate))
@ -173,14 +175,6 @@ enum {
PROP_UUID,
};
enum {
SIGNAL_WINDOW_ADDED,
SIGNAL_WINDOW_REMOVED,
SIGNAL_LAST,
};
static guint signals[SIGNAL_LAST];
void
virt_viewer_app_set_debug(gboolean debug)
{
@ -297,7 +291,7 @@ virt_viewer_app_quit(VirtViewerApp *self)
}
}
gtk_main_quit();
g_application_quit(G_APPLICATION(self));
}
static gint
@ -948,12 +942,13 @@ virt_viewer_app_window_new(VirtViewerApp *self, gint nth)
virt_viewer_app_update_menu_displays(self);
virt_viewer_window_set_usb_options_sensitive(window, virt_viewer_app_has_usbredir(self));
g_signal_emit(self, signals[SIGNAL_WINDOW_ADDED], 0, window);
w = virt_viewer_window_get_window(window);
g_object_set_data(G_OBJECT(w), "virt-viewer-window", window);
gtk_application_add_window(GTK_APPLICATION(self), w);
if (self->priv->fullscreen)
app_window_try_fullscreen(self, window, nth);
w = virt_viewer_window_get_window(window);
g_signal_connect(w, "hide", G_CALLBACK(viewer_window_visible_cb), self);
g_signal_connect(w, "show", G_CALLBACK(viewer_window_visible_cb), self);
g_signal_connect(w, "focus-in-event", G_CALLBACK(viewer_window_focus_in_cb), self);
@ -1068,8 +1063,6 @@ static void virt_viewer_app_remove_nth_window(VirtViewerApp *self,
g_debug("Remove window %d %p", nth, win);
self->priv->windows = g_list_remove(self->priv->windows, win);
g_signal_emit(self, signals[SIGNAL_WINDOW_REMOVED], 0, win);
g_object_unref(win);
}
@ -1423,7 +1416,7 @@ virt_viewer_app_default_deactivated(VirtViewerApp *self, gboolean connect_error)
}
if (self->priv->quit_on_disconnect)
gtk_main_quit();
g_application_quit(G_APPLICATION(self));
}
static void
@ -1501,7 +1494,7 @@ virt_viewer_app_disconnected(VirtViewerSession *session G_GNUC_UNUSED, const gch
virt_viewer_app_hide_all_windows(self);
if (priv->quitting)
gtk_main_quit();
g_application_quit(G_APPLICATION(self));
if (connect_error) {
GtkWidget *dialog = virt_viewer_app_make_message_dialog(self,
@ -1768,6 +1761,7 @@ gboolean virt_viewer_app_start(VirtViewerApp *self, GError **error)
static int opt_zoom = NORMAL_ZOOM_LEVEL;
static gchar *opt_hotkeys = NULL;
static gboolean opt_version = FALSE;
static gboolean opt_verbose = FALSE;
static gboolean opt_debug = FALSE;
static gboolean opt_fullscreen = FALSE;
@ -1787,8 +1781,6 @@ virt_viewer_app_init(VirtViewerApp *self)
self->priv = GET_PRIVATE(self);
gtk_window_set_default_icon_name("virt-viewer");
virt_viewer_app_set_debug(opt_debug);
virt_viewer_app_set_fullscreen(self, opt_fullscreen);
self->priv->displays = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
self->priv->config = g_key_file_new();
@ -1804,14 +1796,7 @@ virt_viewer_app_init(VirtViewerApp *self)
g_clear_error(&error);
if (opt_zoom < MIN_ZOOM_LEVEL || opt_zoom > MAX_ZOOM_LEVEL) {
g_printerr(_("Zoom level must be within %d-%d\n"), MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
opt_zoom = NORMAL_ZOOM_LEVEL;
}
self->priv->initial_display_map = virt_viewer_app_get_monitor_mapping_for_section(self, "fallback");
self->priv->verbose = opt_verbose;
self->priv->quit_on_disconnect = opt_kiosk ? opt_kiosk_quit : TRUE;
g_signal_connect(self, "notify::guest-name", G_CALLBACK(title_maybe_changed), NULL);
g_signal_connect(self, "notify::title", G_CALLBACK(title_maybe_changed), NULL);
g_signal_connect(self, "notify::guri", G_CALLBACK(title_maybe_changed), NULL);
@ -1870,9 +1855,18 @@ virt_viewer_update_smartcard_accels(VirtViewerApp *self)
}
static void
virt_viewer_app_constructed(GObject *object)
virt_viewer_app_on_application_startup(GApplication *app)
{
VirtViewerApp *self = VIRT_VIEWER_APP(object);
VirtViewerApp *self = VIRT_VIEWER_APP(app);
GError *error = NULL;
G_APPLICATION_CLASS(virt_viewer_app_parent_class)->startup(app);
virt_viewer_app_set_debug(opt_debug);
virt_viewer_app_set_fullscreen(self, opt_fullscreen);
self->priv->verbose = opt_verbose;
self->priv->quit_on_disconnect = opt_kiosk ? opt_kiosk_quit : TRUE;
self->priv->main_window = virt_viewer_app_window_new(self,
virt_viewer_app_get_first_monitor(self));
@ -1880,6 +1874,12 @@ virt_viewer_app_constructed(GObject *object)
virt_viewer_app_set_kiosk(self, opt_kiosk);
virt_viewer_app_set_hotkeys(self, opt_hotkeys);
if (opt_zoom < MIN_ZOOM_LEVEL || opt_zoom > MAX_ZOOM_LEVEL) {
g_printerr(_("Zoom level must be within %d-%d\n"), MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
opt_zoom = NORMAL_ZOOM_LEVEL;
}
virt_viewer_window_set_zoom_level(self->priv->main_window, opt_zoom);
virt_viewer_set_insert_smartcard_accel(self, GDK_KEY_F8, GDK_SHIFT_MASK);
@ -1890,25 +1890,92 @@ virt_viewer_app_constructed(GObject *object)
gtk_accel_map_add_entry("<virt-viewer>/view/zoom-out", GDK_KEY_minus, GDK_CONTROL_MASK);
gtk_accel_map_add_entry("<virt-viewer>/view/zoom-in", GDK_KEY_plus, GDK_CONTROL_MASK);
gtk_accel_map_add_entry("<virt-viewer>/send/secure-attention", GDK_KEY_End, GDK_CONTROL_MASK | GDK_MOD1_MASK);
if (!virt_viewer_app_start(self, &error)) {
if (error && !g_error_matches(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_CANCELLED))
virt_viewer_app_simple_message_dialog(self, error->message);
g_clear_error(&error);
g_application_quit(app);
return;
}
g_application_hold(app);
}
static gboolean
virt_viewer_app_local_command_line (GApplication *gapp,
gchar ***args,
int *status)
{
VirtViewerApp *self = VIRT_VIEWER_APP(gapp);
gboolean ret = FALSE;
gint argc = g_strv_length(*args);
GError *error = NULL;
GOptionContext *context = g_option_context_new(NULL);
GOptionGroup *group = g_option_group_new("virt-viewer", NULL, NULL, gapp, NULL);
*status = 0;
g_option_context_set_main_group(context, group);
VIRT_VIEWER_APP_GET_CLASS(self)->add_option_entries(self, context, group);
g_option_context_add_group(context, gtk_get_option_group(TRUE));
#ifdef HAVE_GTK_VNC
g_option_context_add_group(context, vnc_display_get_option_group());
#endif
#ifdef HAVE_SPICE_GTK
g_option_context_add_group(context, spice_get_option_group());
#endif
if (!g_option_context_parse(context, &argc, args, &error)) {
if (error != NULL) {
g_printerr(_("%s\n"), error->message);
g_error_free(error);
}
*status = 1;
ret = TRUE;
goto end;
}
if (opt_version) {
g_print(_("%s version %s"), g_get_prgname(), VERSION BUILDID);
#ifdef REMOTE_VIEWER_OS_ID
g_print(" (OS ID: %s)", REMOTE_VIEWER_OS_ID);
#endif
g_print("\n");
ret = TRUE;
}
end:
g_option_context_free(context);
return ret;
}
static void
virt_viewer_app_class_init (VirtViewerAppClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GApplicationClass *g_app_class = G_APPLICATION_CLASS(klass);
g_type_class_add_private (klass, sizeof (VirtViewerAppPrivate));
object_class->constructed = virt_viewer_app_constructed;
object_class->get_property = virt_viewer_app_get_property;
object_class->set_property = virt_viewer_app_set_property;
object_class->dispose = virt_viewer_app_dispose;
g_app_class->local_command_line = virt_viewer_app_local_command_line;
g_app_class->startup = virt_viewer_app_on_application_startup;
g_app_class->command_line = NULL; /* inhibit GApplication default handler */
klass->start = virt_viewer_app_default_start;
klass->initial_connect = virt_viewer_app_default_initial_connect;
klass->activate = virt_viewer_app_default_activate;
klass->deactivated = virt_viewer_app_default_deactivated;
klass->open_connection = virt_viewer_app_default_open_connection;
klass->add_option_entries = virt_viewer_app_add_option_entries;
g_object_class_install_property(object_class,
PROP_VERBOSE,
@ -2014,28 +2081,6 @@ virt_viewer_app_class_init (VirtViewerAppClass *klass)
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_STATIC_STRINGS));
signals[SIGNAL_WINDOW_ADDED] =
g_signal_new("window-added",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(VirtViewerAppClass, window_added),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
G_TYPE_OBJECT);
signals[SIGNAL_WINDOW_REMOVED] =
g_signal_new("window-removed",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(VirtViewerAppClass, window_removed),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
G_TYPE_OBJECT);
}
void
@ -2575,10 +2620,14 @@ option_kiosk_quit(G_GNUC_UNUSED const gchar *option_name,
return FALSE;
}
GOptionGroup*
virt_viewer_app_get_option_group(void)
static void
virt_viewer_app_add_option_entries(G_GNUC_UNUSED VirtViewerApp *self,
G_GNUC_UNUSED GOptionContext *context,
GOptionGroup *group)
{
static const GOptionEntry options [] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &opt_version,
N_("Display version information"), NULL },
{ "zoom", 'z', 0, G_OPTION_ARG_INT, &opt_zoom,
N_("Zoom level of window, in percentage"), "ZOOM" },
{ "full-screen", 'f', 0, G_OPTION_ARG_NONE, &opt_fullscreen,
@ -2595,11 +2644,8 @@ virt_viewer_app_get_option_group(void)
N_("Display debugging information"), NULL },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
GOptionGroup *group;
group = g_option_group_new("virt-viewer", NULL, NULL, NULL, NULL);
g_option_group_add_entries(group, options);
return group;
g_option_group_add_entries(group, options);
}
gboolean virt_viewer_app_get_session_cancelled(VirtViewerApp *self)

View File

@ -24,6 +24,7 @@
#define VIRT_VIEWER_APP_H
#include <glib-object.h>
#include <gtk/gtk.h>
#include "virt-viewer-util.h"
#include "virt-viewer-window.h"
@ -39,16 +40,12 @@ G_BEGIN_DECLS
typedef struct _VirtViewerAppPrivate VirtViewerAppPrivate;
typedef struct {
GObject parent;
GtkApplication parent;
VirtViewerAppPrivate *priv;
} VirtViewerApp;
typedef struct {
GObjectClass parent_class;
/* signals */
void (*window_added) (VirtViewerApp *self, VirtViewerWindow *window);
void (*window_removed) (VirtViewerApp *self, VirtViewerWindow *window);
GtkApplicationClass parent_class;
/*< private >*/
gboolean (*start) (VirtViewerApp *self, GError **error);
@ -56,6 +53,7 @@ typedef struct {
gboolean (*activate) (VirtViewerApp *self, GError **error);
void (*deactivated) (VirtViewerApp *self, gboolean connect_error);
gboolean (*open_connection)(VirtViewerApp *self, int *fd);
void (*add_option_entries)(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group);
} VirtViewerAppClass;
GType virt_viewer_app_get_type (void);
@ -95,7 +93,6 @@ GList* virt_viewer_app_get_windows(VirtViewerApp *self);
gboolean virt_viewer_app_get_enable_accel(VirtViewerApp *self);
VirtViewerSession* virt_viewer_app_get_session(VirtViewerApp *self);
gboolean virt_viewer_app_get_fullscreen(VirtViewerApp *app);
GOptionGroup* virt_viewer_app_get_option_group(void);
void virt_viewer_app_clear_hotkeys(VirtViewerApp *app);
GList* virt_viewer_app_get_initial_displays(VirtViewerApp* self);
gint virt_viewer_app_get_initial_monitor_for_display(VirtViewerApp* self, gint display);

View File

@ -22,121 +22,23 @@
#include <config.h>
#include <locale.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <stdlib.h>
#ifdef HAVE_GTK_VNC
#include <vncdisplay.h>
#endif
#ifdef HAVE_SPICE_GTK
#include <spice-option.h>
#endif
#include "virt-viewer.h"
static void virt_viewer_version(void)
{
g_print(_("%s version %s\n"), PACKAGE, VERSION BUILDID);
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
GOptionContext *context;
GError *error = NULL;
int ret = 1;
char *uri = NULL;
gchar **args = NULL;
gboolean direct = FALSE;
gboolean attach = FALSE;
gboolean waitvm = FALSE;
gboolean reconnect = FALSE;
VirtViewer *viewer = NULL;
char *base_name;
char *help_msg = NULL;
const GOptionEntry options [] = {
{ "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
virt_viewer_version, N_("Display version information"), NULL },
{ "direct", 'd', 0, G_OPTION_ARG_NONE, &direct,
N_("Direct connection with no automatic tunnels"), NULL },
{ "attach", 'a', 0, G_OPTION_ARG_NONE, &attach,
N_("Attach to the local display using libvirt"), 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 },
{ 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 }
};
GOptionGroup* app_options = NULL;
GApplication *app= NULL;
virt_viewer_util_init(_("Virt Viewer"));
app = G_APPLICATION(virt_viewer_new());
base_name = g_path_get_basename(argv[0]);
help_msg = g_strdup_printf(_("Run '%s --help' to see a full list of available command line options"),
base_name);
g_free(base_name);
/* Setup command line options */
context = g_option_context_new (NULL);
g_option_context_set_summary (context, _("Virtual machine graphical console"));
app_options = virt_viewer_app_get_option_group();
g_option_group_add_entries (app_options, options);
g_option_context_set_main_group (context, app_options);
g_option_context_add_group (context, gtk_get_option_group (TRUE));
#ifdef HAVE_GTK_VNC
g_option_context_add_group (context, vnc_display_get_option_group ());
#endif
#ifdef HAVE_SPICE_GTK
g_option_context_add_group (context, spice_get_option_group ());
#endif
g_option_context_parse (context, &argc, &argv, &error);
if (error) {
g_printerr("%s\n%s\n",
error->message, help_msg);
goto cleanup;
}
g_option_context_free(context);
if (args && (g_strv_length(args) != 1)) {
g_printerr(_("\nUsage: %s [OPTIONS] [DOMAIN-NAME|ID|UUID]\n\n%s\n\n"), argv[0], help_msg);
goto cleanup;
}
if (args == NULL && waitvm) {
g_printerr(_("\nNo DOMAIN-NAME|ID|UUID was specified for '--wait'\n\n"));
goto cleanup;
}
viewer = virt_viewer_new(uri, (args) ? args[0] : NULL, direct, attach, waitvm, reconnect);
if (viewer == NULL)
goto cleanup;
if (!virt_viewer_app_start(VIRT_VIEWER_APP(viewer), &error)) {
if (g_error_matches(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_CANCELLED))
ret = 0;
else if (error) {
virt_viewer_app_simple_message_dialog(VIRT_VIEWER_APP(viewer), error->message);
}
goto cleanup;
}
gtk_main();
ret = 0;
cleanup:
if (viewer)
g_object_unref(viewer);
g_free(uri);
g_strfreev(args);
g_free(help_msg);
g_clear_error(&error);
ret = g_application_run(app, argc, argv);
g_object_unref(app);
return ret;
}

View File

@ -30,7 +30,7 @@ extern gboolean doDebug;
enum {
VIRT_VIEWER_ERROR_FAILED,
VIRT_VIEWER_ERROR_CANCELLED,
VIRT_VIEWER_ERROR_CANCELLED
};
#define VIRT_VIEWER_ERROR virt_viewer_error_quark ()

View File

@ -32,6 +32,7 @@
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <gio/gio.h>
#include <glib/gprintf.h>
#include <glib/gi18n.h>
@ -73,11 +74,93 @@ static gboolean virt_viewer_start(VirtViewerApp *self, GError **error);
static void virt_viewer_dispose (GObject *object);
static int virt_viewer_connect(VirtViewerApp *app, GError **error);
static gchar **opt_args = NULL;
static gchar *opt_uri = NULL;
static gboolean opt_direct = FALSE;
static gboolean opt_attach = FALSE;
static gboolean opt_waitvm = FALSE;
static gboolean opt_reconnect = FALSE;
static void
virt_viewer_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group)
{
static const GOptionEntry options[] = {
{ "direct", 'd', 0, G_OPTION_ARG_NONE, &opt_direct,
N_("Direct connection with no automatic tunnels"), NULL },
{ "attach", 'a', 0, G_OPTION_ARG_NONE, &opt_attach,
N_("Attach to the local display using libvirt"), NULL },
{ "connect", 'c', 0, G_OPTION_ARG_STRING, &opt_uri,
N_("Connect to hypervisor"), "URI"},
{ "wait", 'w', 0, G_OPTION_ARG_NONE, &opt_waitvm,
N_("Wait for domain to start"), NULL },
{ "reconnect", 'r', 0, G_OPTION_ARG_NONE, &opt_reconnect,
N_("Reconnect to domain upon restart"), NULL },
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &opt_args,
NULL, "-- DOMAIN-NAME|ID|UUID" },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
VIRT_VIEWER_APP_CLASS(virt_viewer_parent_class)->add_option_entries(self, context, group);
g_option_context_set_summary(context, _("Virtual machine graphical console"));
g_option_group_add_entries(group, options);
}
static gboolean
virt_viewer_local_command_line (GApplication *gapp,
gchar ***args,
int *status)
{
gboolean ret = FALSE;
VirtViewer *self = VIRT_VIEWER(gapp);
VirtViewerApp *app = VIRT_VIEWER_APP(gapp);
ret = G_APPLICATION_CLASS(virt_viewer_parent_class)->local_command_line(gapp, args, status);
if (ret)
goto end;
if (opt_args) {
if (g_strv_length(opt_args) != 1) {
g_printerr(_("\nUsage: %s [OPTIONS] [DOMAIN-NAME|ID|UUID]\n\n"), PACKAGE);
ret = TRUE;
*status = 1;
goto end;
}
self->priv->domkey = g_strdup(opt_args[0]);
}
if (opt_waitvm) {
if (!self->priv->domkey) {
g_printerr(_("\nNo DOMAIN-NAME|ID|UUID was specified for '--wait'\n\n"));
ret = TRUE;
*status = 1;
goto end;
}
self->priv->waitvm = TRUE;
}
virt_viewer_app_set_direct(app, opt_direct);
virt_viewer_app_set_attach(app, opt_attach);
self->priv->reconnect = opt_reconnect;
self->priv->uri = g_strdup(opt_uri);
end:
if (ret && *status)
g_printerr(_("Run '%s --help' to see a full list of available command line options\n"), g_get_prgname());
g_strfreev(opt_args);
g_free(opt_uri);
return ret;
}
static void
virt_viewer_class_init (VirtViewerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
VirtViewerAppClass *app_class = VIRT_VIEWER_APP_CLASS (klass);
GApplicationClass *g_app_class = G_APPLICATION_CLASS(klass);
g_type_class_add_private (klass, sizeof (VirtViewerPrivate));
@ -87,6 +170,9 @@ virt_viewer_class_init (VirtViewerClass *klass)
app_class->deactivated = virt_viewer_deactivated;
app_class->open_connection = virt_viewer_open_connection;
app_class->start = virt_viewer_start;
app_class->add_option_entries = virt_viewer_add_option_entries;
g_app_class->local_command_line = virt_viewer_local_command_line;
}
static void
@ -106,7 +192,7 @@ virt_viewer_connect_timer(void *opaque)
if (!virt_viewer_app_is_active(app) &&
!virt_viewer_app_initial_connect(app, NULL))
gtk_main_quit();
g_application_quit(G_APPLICATION(app));
if (virt_viewer_app_is_active(app)) {
self->priv->reconnect_poll = 0;
@ -976,33 +1062,12 @@ virt_viewer_start(VirtViewerApp *app, GError **error)
}
VirtViewer *
virt_viewer_new(const char *uri,
const char *name,
gboolean direct,
gboolean attach,
gboolean waitvm,
gboolean reconnect)
virt_viewer_new(void)
{
VirtViewer *self;
VirtViewerApp *app;
VirtViewerPrivate *priv;
self = g_object_new(VIRT_VIEWER_TYPE,
"guest-name", name,
return g_object_new(VIRT_VIEWER_TYPE,
"application-id", "org.virt-manager.virt-viewer",
"flags", G_APPLICATION_NON_UNIQUE,
NULL);
app = VIRT_VIEWER_APP(self);
priv = self->priv;
virt_viewer_app_set_direct(app, direct);
virt_viewer_app_set_attach(app, attach);
/* should probably be properties instead */
priv->uri = g_strdup(uri);
priv->domkey = g_strdup(name);
priv->waitvm = waitvm;
priv->reconnect = reconnect;
return self;
}
/*

View File

@ -48,13 +48,7 @@ typedef struct {
GType virt_viewer_get_type (void);
VirtViewer *
virt_viewer_new(const char *uri,
const char *name,
gboolean direct,
gboolean attach,
gboolean waitvm,
gboolean reconnect);
VirtViewer *virt_viewer_new (void);
G_END_DECLS

View File

@ -2,7 +2,7 @@
<interface>
<!-- interface-requires gtk+ 2.6 -->
<object class="GtkAccelGroup" id="accelgroup"/>
<object class="GtkWindow" id="viewer">
<object class="GtkApplicationWindow" id="viewer">
<property name="can_focus">False</property>
<property name="default_width">1024</property>
<property name="default_height">768</property>