[virt-tools-list] [PATCH v4 3/5] Port to GtkApplication API's

Eduardo Lima (Etrunko) etrunko at redhat.com
Mon Feb 15 14:31:26 UTC 2016


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 at redhat.com>
---
 configure.ac             |   6 +-
 src/remote-viewer-main.c | 167 ++------------------------------------
 src/remote-viewer.c      | 207 +++++++++++++++++++++++++++++++++++++++--------
 src/remote-viewer.h      |   4 +-
 src/virt-viewer-app.c    | 145 ++++++++++++++++++++-------------
 src/virt-viewer-app.h    |  11 +--
 src/virt-viewer-main.c   | 108 ++-----------------------
 src/virt-viewer-util.h   |   1 +
 src/virt-viewer-window.c |   4 +-
 src/virt-viewer.c        | 137 +++++++++++++++++++++++++------
 src/virt-viewer.h        |   9 +--
 src/virt-viewer.xml      |   2 +-
 12 files changed, 399 insertions(+), 402 deletions(-)

diff --git a/configure.ac b/configure.ac
index 250a7fe..e09d0cb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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"
-GTK3_REQUIRED="3.0"
+GTK3_REQUIRED="3.10"
 GTK_VNC2_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],
diff --git a/src/remote-viewer-main.c b/src/remote-viewer-main.c
index 81cf736..b05f27b 100644
--- a/src/remote-viewer-main.c
+++ b/src/remote-viewer-main.c
@@ -22,184 +22,29 @@
 
 #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;
 
     virt_viewer_util_init(_("Remote Viewer"));
 
-    /* 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
+    viewer = remote_viewer_new();
     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;
+        goto end;
 
- cleanup:
-    g_free(uri);
-    if (viewer)
-        g_object_unref(viewer);
-    g_strfreev(args);
-    g_clear_error(&error);
+    ret = g_application_run(G_APPLICATION(viewer), argc, argv);
+    g_object_unref(viewer);
 
+end:
     return ret;
 }
 
diff --git a/src/remote-viewer.c b/src/remote-viewer.c
index e712d61..2703a24 100644
--- a/src/remote-viewer.c
+++ b/src/remote-viewer.c
@@ -23,6 +23,7 @@
  */
 
 #include <config.h>
+#include <gio/gio.h>
 #include <gtk/gtk.h>
 #include <glib/gprintf.h>
 #include <glib/gi18n.h>
@@ -30,6 +31,7 @@
 
 #ifdef HAVE_OVIRT
 #include <govirt/govirt.h>
+#include <govirt/ovirt-options.h>
 #include "ovirt-foreign-menu.h"
 #include "virt-viewer-vm-connection.h"
 #endif
@@ -84,8 +86,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 +186,128 @@ 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 gboolean
+remote_viewer_version (G_GNUC_UNUSED const gchar *option_name,
+                       G_GNUC_UNUSED const gchar *value,
+                       G_GNUC_UNUSED gpointer data,
+                       GError **error)
+{
+
+    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");
+    g_set_error(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_VERSION,
+                _("%s version %s"), g_get_prgname(), VERSION BUILDID);
+    return FALSE;
+}
+
+static void
+remote_viewer_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group)
+{
+    static 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, &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)
+{
+#define GOTO_END \
+    do { \
+        ret = TRUE; \
+        *status = 1; \
+        goto end; \
+       } while (FALSE)
+
+    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"));
+            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"));
+            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);
+
+#undef GOTO_END
+
+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 +315,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 +332,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 +340,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 +351,6 @@ remote_viewer_class_init (RemoteViewerClass *klass)
                                                          "Open recent dialog",
                                                          FALSE,
                                                          G_PARAM_READWRITE |
-                                                         G_PARAM_CONSTRUCT_ONLY |
                                                          G_PARAM_STATIC_STRINGS));
 }
 
@@ -238,11 +361,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 +388,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 +737,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 +847,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 +883,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 +1167,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 +1280,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) {
diff --git a/src/remote-viewer.h b/src/remote-viewer.h
index 6d445ca..c03a271 100644
--- a/src/remote-viewer.h
+++ b/src/remote-viewer.h
@@ -47,9 +47,7 @@ typedef struct {
 } RemoteViewerClass;
 
 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
 
diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c
index 60157e9..8120272 100644
--- a/src/virt-viewer-app.c
+++ b/src/virt-viewer-app.c
@@ -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>
 
@@ -103,6 +104,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 {
@@ -155,7 +157,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))
 
@@ -174,14 +176,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)
 {
@@ -298,7 +292,7 @@ virt_viewer_app_quit(VirtViewerApp *self)
         }
     }
 
-    gtk_main_quit();
+    g_application_quit(G_APPLICATION(self));
 }
 
 static gint
@@ -949,12 +943,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);
@@ -1069,8 +1064,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);
 }
 
@@ -1424,7 +1417,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
@@ -1502,7 +1495,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,
@@ -1788,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();
@@ -1805,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);
@@ -1871,9 +1855,18 @@ virt_viewer_update_smartcard_accels(VirtViewerApp *self)
 }
 
 static void
-virt_viewer_app_constructed(GObject *object)
+virt_viewer_app_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));
@@ -1881,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_F8, GDK_SHIFT_MASK);
@@ -1891,25 +1890,82 @@ virt_viewer_app_constructed(GObject *object)
     gtk_accel_map_add_entry("<virt-viewer>/view/zoom-out", GDK_minus, GDK_CONTROL_MASK);
     gtk_accel_map_add_entry("<virt-viewer>/view/zoom-in", GDK_plus, GDK_CONTROL_MASK);
     gtk_accel_map_add_entry("<virt-viewer>/send/secure-attention", GDK_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);
+    }
+
+    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, NULL, 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 && !g_error_matches(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_VERSION)) {
+            g_printerr(_("%s\n"), error->message);
+            *status = 1;
+        }
+
+        g_error_free(error);
+        ret = TRUE;
+    }
+
+    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_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,
@@ -2015,28 +2071,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
@@ -2576,8 +2610,10 @@ 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 [] = {
         { "zoom", 'z', 0, G_OPTION_ARG_INT, &opt_zoom,
@@ -2596,11 +2632,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)
diff --git a/src/virt-viewer-app.h b/src/virt-viewer-app.h
index bbbc9b4..7f6c401 100644
--- a/src/virt-viewer-app.h
+++ b/src/virt-viewer-app.h
@@ -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);
diff --git a/src/virt-viewer-main.c b/src/virt-viewer-main.c
index 505b472..ffa2474 100644
--- a/src/virt-viewer-main.c
+++ b/src/virt-viewer-main.c
@@ -22,122 +22,28 @@
 
 #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);
-}
 
+#include "virt-viewer.h"
 
 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;
 
     virt_viewer_util_init(_("Virt Viewer"));
 
-    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);
+    viewer = virt_viewer_new();
     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;
+        goto end;
 
- 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(G_APPLICATION(viewer), argc, argv);
+    g_object_unref(viewer);
 
+end:
     return ret;
 }
 
diff --git a/src/virt-viewer-util.h b/src/virt-viewer-util.h
index f1cb08b..a9496a4 100644
--- a/src/virt-viewer-util.h
+++ b/src/virt-viewer-util.h
@@ -31,6 +31,7 @@ extern gboolean doDebug;
 enum {
     VIRT_VIEWER_ERROR_FAILED,
     VIRT_VIEWER_ERROR_CANCELLED,
+    VIRT_VIEWER_VERSION,
 };
 
 #define VIRT_VIEWER_ERROR virt_viewer_error_quark ()
diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c
index 3a958f0..14549fd 100644
--- a/src/virt-viewer-window.c
+++ b/src/virt-viewer-window.c
@@ -346,8 +346,7 @@ virt_viewer_window_init (VirtViewerWindow *self)
     gtk_window_set_has_resize_grip(GTK_WINDOW(priv->window), FALSE);
     priv->accel_enabled = TRUE;
 
-    accels = gtk_accel_groups_from_object(G_OBJECT(priv->window));
-    for ( ; accels ; accels = accels->next) {
+    for (accels = gtk_accel_groups_from_object(G_OBJECT(priv->window)); accels; accels = accels->next) {
         priv->accel_list = g_slist_append(priv->accel_list, accels->data);
         g_object_ref(G_OBJECT(accels->data));
     }
@@ -1428,7 +1427,6 @@ virt_viewer_window_get_menu_displays(VirtViewerWindow *self)
 
     return GTK_MENU_ITEM(gtk_builder_get_object(self->priv->builder, "menu-displays"));
 }
-
 GtkBuilder*
 virt_viewer_window_get_builder(VirtViewerWindow *self)
 {
diff --git a/src/virt-viewer.c b/src/virt-viewer.c
index 10f624d..f74d0c5 100644
--- a/src/virt-viewer.c
+++ b/src/virt-viewer.c
@@ -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,113 @@ 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 gboolean
+virt_viewer_version (G_GNUC_UNUSED const gchar *option_name,
+                     G_GNUC_UNUSED const gchar *value,
+                     G_GNUC_UNUSED gpointer data,
+                     GError **error)
+{
+
+    g_print(_("%s version %s\n"), g_get_prgname(), VERSION BUILDID);
+    g_set_error(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_VERSION,
+                _("%s version %s"), g_get_prgname(), VERSION BUILDID);
+    return FALSE;
+}
+
+static void
+virt_viewer_add_option_entries(VirtViewerApp *self, GOptionContext *context, GOptionGroup *group)
+{
+    static 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, &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)
+{
+#define GOTO_END \
+    do { \
+        ret = TRUE; \
+        *status = 1; \
+        goto end; \
+       } while (FALSE)
+
+    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);
+            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"));
+            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);
+
+#undef GOTO_END
+
+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 +190,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 +212,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 +1082,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;
 }
 
 /*
diff --git a/src/virt-viewer.h b/src/virt-viewer.h
index c962615..373836a 100644
--- a/src/virt-viewer.h
+++ b/src/virt-viewer.h
@@ -47,14 +47,7 @@ typedef struct {
 } VirtViewerClass;
 
 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
 
diff --git a/src/virt-viewer.xml b/src/virt-viewer.xml
index 07948bd..03f2f84 100644
--- a/src/virt-viewer.xml
+++ b/src/virt-viewer.xml
@@ -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>
-- 
2.5.0




More information about the virt-tools-list mailing list