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

Eduardo Lima (Etrunko) etrunko at redhat.com
Fri Dec 11 16:40:32 UTC 2015


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:

- Update glib requirements to 2.40.0 and adds gio as build dependency.

- 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 three, the
  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             |   4 +-
 src/remote-viewer-main.c | 122 +-------------------------
 src/remote-viewer.c      | 152 +++++++++++++++++++++++++-------
 src/remote-viewer.h      |   3 +-
 src/virt-viewer-app.c    | 223 +++++++++++++++++++++++++++--------------------
 src/virt-viewer-app.h    |  10 +--
 src/virt-viewer-main.c   | 102 +---------------------
 src/virt-viewer.c        | 117 ++++++++++++++++++++-----
 src/virt-viewer.h        |   8 +-
 src/virt-viewer.xml      |   2 +-
 10 files changed, 355 insertions(+), 388 deletions(-)

diff --git a/configure.ac b/configure.ac
index 250a7fe..bd9524e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@ 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.40.0"
 LIBXML2_REQUIRED="2.6.0"
 LIBVIRT_REQUIRED="0.10.0"
 GTK3_REQUIRED="3.0"
@@ -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 6ac2523..0329d16 100644
--- a/src/remote-viewer-main.c
+++ b/src/remote-viewer-main.c
@@ -30,32 +30,11 @@
 #include <io.h>
 #endif
 
-#ifdef HAVE_GTK_VNC
-#include <vncdisplay.h>
-#endif
-#ifdef HAVE_SPICE_GTK
-#include <spice-client.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;
@@ -87,118 +66,23 @@ static void connected(VirtViewerSession *session,
 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;
+    ret = g_application_run(G_APPLICATION(viewer), argc, argv);
 
  cleanup:
-    g_free(uri);
-    if (viewer)
-        g_object_unref(viewer);
-    g_strfreev(args);
-    g_clear_error(&error);
+    g_object_unref(viewer);
 
     return ret;
 }
diff --git a/src/remote-viewer.c b/src/remote-viewer.c
index e712d61..036ee06 100644
--- a/src/remote-viewer.c
+++ b/src/remote-viewer.c
@@ -82,12 +82,44 @@ static OvirtVm * choose_vm(GtkWindow *main_window,
 #endif
 
 static gboolean remote_viewer_start(VirtViewerApp *self, GError **error);
+
+/* VirtViewerApp overrides */
+static gint remote_viewer_handle_local_options(GApplication *app, GVariantDict *options);
+
 #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 *win);
 static void spice_foreign_menu_updated(RemoteViewer *self);
 #endif
 
+static const char OPT_VERSION[] = "version";
+static const char OPT_TITLE[] = "title";
+static const char OPT_CONTROLLER[] = "spice-controller";
+
+static void
+remote_viewer_constructed(GObject *object)
+{
+    GApplication *app = G_APPLICATION(object);
+    const GOptionEntry options[] = {
+        { OPT_TITLE, 't', 0, G_OPTION_ARG_STRING, NULL,
+          N_("Set window title"), NULL },
+#ifdef HAVE_SPICE_GTK
+        { OPT_CONTROLLER, '\0', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Open connection using Spice controller communication"), NULL },
+#endif
+        { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, NULL,
+          NULL, "URI|VV-FILE" },
+        { NULL },
+    };
+
+   G_OBJECT_CLASS(remote_viewer_parent_class)->constructed(object);
+   g_application_add_main_option_entries(app, options);
+
+#ifdef HAVE_OVIRT
+    g_application_add_option_group(app, ovirt_get_option_group ());
+#endif
+}
+
 static void
 remote_viewer_dispose (GObject *object)
 {
@@ -188,18 +220,24 @@ remote_viewer_class_init (RemoteViewerClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
     VirtViewerAppClass *app_class = VIRT_VIEWER_APP_CLASS (klass);
+    GApplicationClass *g_app_class = G_APPLICATION_CLASS(klass);
+    GtkApplicationClass *gtk_app_class = GTK_APPLICATION_CLASS(klass);
 
     g_type_class_add_private (klass, sizeof (RemoteViewerPrivate));
 
     object_class->get_property = remote_viewer_get_property;
     object_class->set_property = remote_viewer_set_property;
+    object_class->constructed = remote_viewer_constructed;
     object_class->dispose = remote_viewer_dispose;
 
     app_class->start = remote_viewer_start;
     app_class->deactivated = remote_viewer_deactivated;
+
+    g_app_class->handle_local_options = remote_viewer_handle_local_options;
+
 #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 +246,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 +254,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 +265,6 @@ remote_viewer_class_init (RemoteViewerClass *klass)
                                                          "Open recent dialog",
                                                          FALSE,
                                                          G_PARAM_READWRITE |
-                                                         G_PARAM_CONSTRUCT_ONLY |
                                                          G_PARAM_STATIC_STRINGS));
 }
 
@@ -238,11 +275,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.fedorahosted.remote-viewer",
+                        "flags", G_APPLICATION_NON_UNIQUE,
                         NULL);
 }
 
@@ -265,26 +302,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,11 +651,12 @@ remote_viewer_activate(VirtViewerApp *app, GError **error)
 }
 
 static void
-remote_viewer_window_added(VirtViewerApp *app,
-                           VirtViewerWindow *win)
+remote_viewer_window_added(GtkApplication *app,
+                           G_GNUC_UNUSED GtkWindow *win)
 {
-    spice_menu_update(REMOTE_VIEWER(app), win);
-    spice_foreign_menu_update(REMOTE_VIEWER(app), win);
+    VirtViewerWindow *window = virt_viewer_app_get_main_window(VIRT_VIEWER_APP(app));
+    spice_menu_update(REMOTE_VIEWER(app), window);
+    spice_foreign_menu_update(REMOTE_VIEWER(app), window);
 }
 #endif
 
@@ -1185,6 +1203,76 @@ cleanup:
     return ret;
 }
 
+static gint
+remote_viewer_handle_local_options(GApplication *gapp, GVariantDict *options)
+{
+    VirtViewerApp *app = VIRT_VIEWER_APP(gapp);
+    gint ret = -1;
+    gchar *title = NULL;
+    gchar **args = NULL;
+    gboolean controller = FALSE;
+
+    if (g_variant_dict_contains(options, 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");
+        return 0;
+    }
+
+    if (g_variant_dict_lookup(options, G_OPTION_REMAINING, "^as", &args)) {
+        if (args && (g_strv_length(args) != 1)) {
+            g_printerr(_("Error: can't handle multiple URIs\n"));
+            ret = 1;
+            goto end;
+        }
+
+        g_object_set(app, "guri", args[0], NULL);
+    }
+
+    g_variant_dict_lookup(options, OPT_TITLE, "s", &title);
+
+#ifdef HAVE_SPICE_GTK
+    if (g_variant_dict_lookup(options, OPT_CONTROLLER, "b", &controller)) {
+        if (args) {
+            g_printerr(_("Error: extra arguments given while using Spice controller\n\n"));
+            ret = 1;
+            goto end;
+        } else {
+            RemoteViewer *self = REMOTE_VIEWER(app);
+            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 (title && !controller)
+        g_object_set(app, "title", title, NULL);
+
+    ret = G_APPLICATION_CLASS(remote_viewer_parent_class)->handle_local_options(gapp, options);
+
+end:
+    if (ret == 1)
+        g_printerr(_("Run '%s --help' to see a full list of available command line options\n\n"),
+                   g_get_prgname());
+
+    g_strfreev(args);
+    return ret;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 4
diff --git a/src/remote-viewer.h b/src/remote-viewer.h
index 6d445ca..e200fc1 100644
--- a/src/remote-viewer.h
+++ b/src/remote-viewer.h
@@ -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
 
diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c
index 653b30c..67cac77 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>
 
@@ -63,6 +64,7 @@
 #endif
 
 gboolean doDebug = FALSE;
+static int opt_zoom = NORMAL_ZOOM_LEVEL;
 
 /* Signal handlers for about dialog */
 void virt_viewer_app_about_close(GtkWidget *dialog, VirtViewerApp *self);
@@ -104,6 +106,12 @@ static void virt_viewer_app_set_fullscreen(VirtViewerApp *self, gboolean fullscr
 static void virt_viewer_app_update_menu_displays(VirtViewerApp *self);
 static void virt_viewer_update_smartcard_accels(VirtViewerApp *self);
 
+/* From GApplication */
+static gint virt_viewer_app_handle_local_options(GApplication *app,
+                                                 GVariantDict *options);
+static void virt_viewer_app_startup_cb(GApplication *app, gpointer data);
+static void virt_viewer_app_activate_cb(GApplication *app, gpointer data);
+
 
 struct _VirtViewerAppPrivate {
     VirtViewerWindow *main_window;
@@ -155,7 +163,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 +182,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 +298,7 @@ virt_viewer_app_quit(VirtViewerApp *self)
         }
     }
 
-    gtk_main_quit();
+    g_application_quit(G_APPLICATION(self));
 }
 
 static gint
@@ -926,12 +926,11 @@ virt_viewer_app_window_new(VirtViewerApp *self, gint nth)
                     virt_viewer_session_get_has_usbredir(self->priv->session));
     }
 
-    g_signal_emit(self, signals[SIGNAL_WINDOW_ADDED], 0, window);
-
     if (self->priv->fullscreen)
         app_window_try_fullscreen(self, window, nth);
 
     w = virt_viewer_window_get_window(window);
+    gtk_application_add_window(GTK_APPLICATION(self), w);
     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);
@@ -1046,8 +1045,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);
 }
 
@@ -1401,7 +1398,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
@@ -1479,7 +1476,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,
@@ -1744,13 +1741,6 @@ gboolean virt_viewer_app_start(VirtViewerApp *self, GError **error)
     return self->priv->started;
 }
 
-static int opt_zoom = NORMAL_ZOOM_LEVEL;
-static gchar *opt_hotkeys = NULL;
-static gboolean opt_verbose = FALSE;
-static gboolean opt_debug = FALSE;
-static gboolean opt_fullscreen = FALSE;
-static gboolean opt_kiosk = FALSE;
-static gboolean opt_kiosk_quit = FALSE;
 
 static void
 title_maybe_changed(VirtViewerApp *self, GParamSpec* pspec G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED)
@@ -1765,8 +1755,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();
@@ -1782,17 +1770,14 @@ 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);
+
+    /* From GApplication */
+    g_signal_connect(self, "startup", G_CALLBACK(virt_viewer_app_startup_cb), NULL);
+    g_signal_connect(self, "activate", G_CALLBACK(virt_viewer_app_activate_cb), NULL);
 }
 
 static void
@@ -1847,17 +1832,75 @@ virt_viewer_update_smartcard_accels(VirtViewerApp *self)
     }
 }
 
+static gboolean
+virt_viewer_app_option_kiosk_quit(VirtViewerApp *self, const gchar *value)
+{
+    if (g_strcmp0(value, "never") == 0) {
+        self->priv->quit_on_disconnect = FALSE;
+        return TRUE;
+    }
+    if (g_strcmp0(value, "on-disconnect") == 0) {
+        self->priv->quit_on_disconnect = TRUE;
+        return TRUE;
+    }
+
+    g_printerr(_("Invalid kiosk-quit argument: %s\n\n"), value);
+
+    return FALSE;
+}
+
+static const char OPT_VERSION[] = "version";
+static const char OPT_ZOOM[] = "zoom";
+static const char OPT_FULLSCREEN[] = "full-screen";
+static const char OPT_HOTKEYS[] = "hotkeys";
+static const char OPT_KIOSK[] = "kiosk";
+static const char OPT_KIOSK_QUIT[] = "kiosk-quit";
+static const char OPT_VERBOSE[] = "verbose";
+static const char OPT_DEBUG[] = "debug";
+
 static void
 virt_viewer_app_constructed(GObject *object)
 {
-    VirtViewerApp *self = VIRT_VIEWER_APP(object);
+    GApplication *app = G_APPLICATION(object);
+
+    static const GOptionEntry virt_viewer_app_options[] = {
+        { OPT_VERSION, 'V', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Display version information"), NULL },
+        { OPT_ZOOM, 'z', 0, G_OPTION_ARG_INT, NULL,
+          N_("Zoom level of window, in percentage"), "ZOOM" },
+        { OPT_FULLSCREEN, 'f', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Open in full screen mode (adjusts guest resolution to fit the client)"), NULL },
+        { OPT_HOTKEYS, 'H', 0, G_OPTION_ARG_STRING, NULL,
+          N_("Customise hotkeys"), NULL },
+        { OPT_KIOSK, 'k', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Enable kiosk mode"), NULL },
+        { OPT_KIOSK_QUIT, '\0', 0, G_OPTION_ARG_STRING, NULL,
+          N_("Quit on given condition in kiosk mode"), N_("<never|on-disconnect>") },
+        { OPT_VERBOSE, 'v', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Display verbose information"), NULL },
+        { OPT_DEBUG, '\0', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Display debugging information"), NULL },
+        { NULL },
+    };
+
+    g_application_add_main_option_entries(app, virt_viewer_app_options);
+
+#ifdef HAVE_GTK_VNC
+    g_application_add_option_group(app, vnc_display_get_option_group());
+#endif
+#ifdef HAVE_SPICE_GTK
+    g_application_add_option_group(app, spice_get_option_group());
+#endif
+}
+
+static void
+virt_viewer_app_startup_cb(GApplication *app, G_GNUC_UNUSED gpointer data)
+{
+    VirtViewerApp *self = VIRT_VIEWER_APP(app);
 
     self->priv->main_window = virt_viewer_app_window_new(self,
                                                          virt_viewer_app_get_first_monitor(self));
     self->priv->main_notebook = GTK_WIDGET(virt_viewer_window_get_notebook(self->priv->main_window));
-
-    virt_viewer_app_set_kiosk(self, opt_kiosk);
-    virt_viewer_app_set_hotkeys(self, opt_hotkeys);
     virt_viewer_window_set_zoom_level(self->priv->main_window, opt_zoom);
 
     virt_viewer_set_insert_smartcard_accel(self, GDK_F8, GDK_SHIFT_MASK);
@@ -1871,9 +1914,26 @@ virt_viewer_app_constructed(GObject *object)
 }
 
 static void
+virt_viewer_app_activate_cb(GApplication *app, G_GNUC_UNUSED gpointer data)
+{
+    GError *error = NULL;
+    VirtViewerApp *self = VIRT_VIEWER_APP(app);
+
+    if (!virt_viewer_app_start(VIRT_VIEWER_APP(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);
+    }
+}
+
+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));
 
@@ -1882,6 +1942,8 @@ virt_viewer_app_class_init (VirtViewerAppClass *klass)
     object_class->set_property = virt_viewer_app_set_property;
     object_class->dispose = virt_viewer_app_dispose;
 
+    g_app_class->handle_local_options = virt_viewer_app_handle_local_options;
+
     klass->start = virt_viewer_app_default_start;
     klass->initial_connect = virt_viewer_app_default_initial_connect;
     klass->activate = virt_viewer_app_default_activate;
@@ -1992,28 +2054,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
@@ -2535,49 +2575,40 @@ virt_viewer_app_show_preferences(VirtViewerApp *self, GtkWidget *parent)
     gtk_window_present(GTK_WINDOW(preferences));
 }
 
-static gboolean
-option_kiosk_quit(G_GNUC_UNUSED const gchar *option_name,
-                  const gchar *value,
-                  G_GNUC_UNUSED gpointer data, GError **error)
+static gint
+virt_viewer_app_handle_local_options(GApplication *app,
+                                     GVariantDict *options)
 {
-    if (g_str_equal(value, "never")) {
-        opt_kiosk_quit = FALSE;
-        return TRUE;
-    }
-    if (g_str_equal(value, "on-disconnect")) {
-        opt_kiosk_quit = TRUE;
-        return TRUE;
+    VirtViewerApp *self = VIRT_VIEWER_APP(app);
+    gchar *opt_hotkeys = NULL;
+
+    virt_viewer_app_set_fullscreen(self, g_variant_dict_contains(options, OPT_FULLSCREEN));
+    virt_viewer_app_set_debug(g_variant_dict_contains(options, OPT_DEBUG));
+    self->priv->verbose = g_variant_dict_contains(options, OPT_VERBOSE);
+
+    if (g_variant_dict_contains(options, OPT_KIOSK)) {
+        gchar *opt_kiosk_quit = NULL;
+
+        virt_viewer_app_set_kiosk(self, TRUE);
+        self->priv->quit_on_disconnect = TRUE;
+
+        if (g_variant_dict_lookup(options, OPT_KIOSK_QUIT, "s", &opt_kiosk_quit) &&
+            !virt_viewer_app_option_kiosk_quit(self, opt_kiosk_quit)) {
+            return 1;
+        }
     }
 
-    g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, _("Invalid kiosk-quit argument: %s"), value);
-    return FALSE;
-}
+    if (g_variant_dict_lookup(options, OPT_ZOOM, "i", &opt_zoom)) {
+        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;
+        }
+    }
 
-GOptionGroup*
-virt_viewer_app_get_option_group(void)
-{
-    static const GOptionEntry options [] = {
-        { "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,
-          N_("Open in full screen mode (adjusts guest resolution to fit the client)"), NULL },
-        { "hotkeys", 'H', 0, G_OPTION_ARG_STRING, &opt_hotkeys,
-          N_("Customise hotkeys"), NULL },
-        { "kiosk", 'k', 0, G_OPTION_ARG_NONE, &opt_kiosk,
-          N_("Enable kiosk mode"), NULL },
-        { "kiosk-quit", '\0', 0, G_OPTION_ARG_CALLBACK, option_kiosk_quit,
-          N_("Quit on given condition in kiosk mode"), N_("<never|on-disconnect>") },
-        { "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose,
-          N_("Display verbose information"), NULL },
-        { "debug", '\0', 0, G_OPTION_ARG_NONE, &opt_debug,
-          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);
+    if (g_variant_dict_lookup(options, OPT_HOTKEYS, "s", &opt_hotkeys))
+        virt_viewer_app_set_hotkeys(self, opt_hotkeys);
 
-    return group;
+    return -1;
 }
 
 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..7bb22fb 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);
@@ -95,7 +92,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 9b9807a..dd51dcb 100644
--- a/src/virt-viewer-main.c
+++ b/src/virt-viewer-main.c
@@ -25,118 +25,24 @@
 #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-client.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;
+    ret = g_application_run(G_APPLICATION(viewer), argc, argv);
 
  cleanup:
-    if (viewer)
-        g_object_unref(viewer);
-    g_free(uri);
-    g_strfreev(args);
-    g_free(help_msg);
-    g_clear_error(&error);
+    g_object_unref(viewer);
 
     return ret;
 }
diff --git a/src/virt-viewer.c b/src/virt-viewer.c
index 10f624d..0f870de 100644
--- a/src/virt-viewer.c
+++ b/src/virt-viewer.c
@@ -73,20 +73,58 @@ 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);
 
+/* VirtViewerApp overrides */
+static gint virt_viewer_handle_local_options(GApplication *app, GVariantDict *options);
+
+static const char OPT_VERSION[] = "version";
+static const char OPT_DIRECT[] = "direct";
+static const char OPT_ATTACH[] = "attach";
+static const char OPT_CONNECT[] = "connect";
+static const char OPT_WAIT[] = "wait";
+static const char OPT_RECONNECT[] = "reconnect";
+
+static void
+virt_viewer_constructed(GObject *object)
+{
+    GApplication *app = G_APPLICATION(object);
+    const GOptionEntry options[] = {
+        { OPT_DIRECT, 'd', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Direct connection with no automatic tunnels"), NULL },
+        { OPT_ATTACH, 'a', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Attach to the local display using libvirt"), NULL },
+        { OPT_CONNECT, 'c', 0, G_OPTION_ARG_STRING, NULL,
+          N_("Connect to hypervisor"), "URI"},
+        { OPT_WAIT, 'w', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Wait for domain to start"), NULL },
+        { OPT_RECONNECT, 'r', 0, G_OPTION_ARG_NONE, NULL,
+          N_("Reconnect to domain upon restart"), NULL },
+        { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, NULL,
+          NULL, "-- DOMAIN-NAME|ID|UUID" },
+        { NULL },
+    };
+
+    G_OBJECT_CLASS(virt_viewer_parent_class)->constructed(object);
+    g_application_add_main_option_entries(app, options);
+}
+
 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));
 
     object_class->dispose = virt_viewer_dispose;
+    object_class->constructed = virt_viewer_constructed;
 
     app_class->initial_connect = virt_viewer_initial_connect;
     app_class->deactivated = virt_viewer_deactivated;
     app_class->open_connection = virt_viewer_open_connection;
     app_class->start = virt_viewer_start;
+
+    g_app_class->handle_local_options = virt_viewer_handle_local_options;
 }
 
 static void
@@ -106,7 +144,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(self));
 
     if (virt_viewer_app_is_active(app)) {
         self->priv->reconnect_poll = 0;
@@ -975,34 +1013,65 @@ virt_viewer_start(VirtViewerApp *app, GError **error)
     return VIRT_VIEWER_APP_CLASS(virt_viewer_parent_class)->start(app, error);
 }
 
-VirtViewer *
-virt_viewer_new(const char *uri,
-                const char *name,
-                gboolean direct,
-                gboolean attach,
-                gboolean waitvm,
-                gboolean reconnect)
+static gint
+virt_viewer_handle_local_options(GApplication *gapp, GVariantDict *options)
 {
-    VirtViewer *self;
-    VirtViewerApp *app;
-    VirtViewerPrivate *priv;
+    VirtViewer *self = VIRT_VIEWER(gapp);
+    VirtViewerApp *app = VIRT_VIEWER_APP(gapp);
+    gint ret = -1;
+    gchar *uri = NULL;
+    gchar **args = NULL;
 
-    self = g_object_new(VIRT_VIEWER_TYPE,
-                        "guest-name", name,
-                        NULL);
-    app = VIRT_VIEWER_APP(self);
-    priv = self->priv;
+    if (g_variant_dict_contains(options, OPT_VERSION)) {
+        g_print(_("%s version %s\n"), g_get_prgname(), VERSION BUILDID);
+        return 0;
+    }
+
+    if (g_variant_dict_lookup(options, G_OPTION_REMAINING, "^as", &args)) {
+        if (args && (g_strv_length(args) != 1)) {
+            g_printerr(_("\nUsage: %s [OPTIONS] [DOMAIN-NAME|ID|UUID]\n\n"), PACKAGE);
+            ret = 1;
+            goto end;
+        }
+
+        self->priv->domkey = g_strdup(args[0]);
+    }
+
+    if (g_variant_dict_contains(options, OPT_WAIT)) {
+        if (!self->priv->domkey) {
+            g_printerr(_("\nNo DOMAIN-NAME|ID|UUID was specified for '--wait'\n\n"));
+            ret = 1;
+            goto end;
+        }
+
+        self->priv->waitvm = TRUE;
+    }
+
+    virt_viewer_app_set_direct(app, g_variant_dict_contains(options, OPT_DIRECT));
+    virt_viewer_app_set_attach(app, g_variant_dict_contains(options, OPT_ATTACH));
+    self->priv->reconnect = g_variant_dict_contains(options, OPT_RECONNECT);
 
-    virt_viewer_app_set_direct(app, direct);
-    virt_viewer_app_set_attach(app, attach);
+    if (g_variant_dict_lookup(options, OPT_CONNECT, "s", &uri))
+        self->priv->uri = g_strdup(uri);
 
-    /* should probably be properties instead */
-    priv->uri = g_strdup(uri);
-    priv->domkey = g_strdup(name);
-    priv->waitvm = waitvm;
-    priv->reconnect = reconnect;
+    ret = G_APPLICATION_CLASS(virt_viewer_parent_class)->handle_local_options(gapp, options);
 
-    return self;
+end:
+    if (ret == 1)
+        g_printerr(_("Run '%s --help' to see a full list of available command line options\n\n"),
+                   g_get_prgname());
+
+    g_strfreev(args);
+    return ret;
+}
+
+VirtViewer *
+virt_viewer_new(void)
+{
+    return g_object_new(VIRT_VIEWER_TYPE,
+                        "application-id", "org.fedorahosted.virt-viewer",
+                        "flags", G_APPLICATION_NON_UNIQUE,
+                        NULL);
 }
 
 /*
diff --git a/src/virt-viewer.h b/src/virt-viewer.h
index c962615..5aeacb0 100644
--- a/src/virt-viewer.h
+++ b/src/virt-viewer.h
@@ -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
 
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