Commit f3782da2 authored by Lubomir Rintel's avatar Lubomir Rintel
Browse files

connection-editor: turn it into a GtkApplication

This simplifies things as we can replace the custom-made D-Bus interface
with a standard one.
parent b1b06f66
......@@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright 2004 - 2014 Red Hat, Inc.
* Copyright 2004 - 2018 Red Hat, Inc.
*/
#include "nm-default.h"
......@@ -35,20 +35,18 @@
gboolean nm_ce_keep_above;
static GMainLoop *loop = NULL;
#define ARG_TYPE "type"
#define ARG_CREATE "create"
#define ARG_SHOW "show"
#define ARG_UUID "uuid"
#define ARG_IMPORT "import"
#define NM_CE_DBUS_SERVICE "org.gnome.nm_connection_editor"
#define NM_CE_DBUS_INTERFACE "org.gnome.nm_connection_editor"
/*************************************************/
static GDBusNodeInfo *introspection_data = NULL;
static NMConnectionList *
_get_connection_list (GApplication *application)
{
GtkApplication *app = GTK_APPLICATION (application);
GList *windows = gtk_application_get_windows (app);
/*************************************************/
/* For now, assume we always have a single application window
* that is the connection list. */
return NM_CONNECTION_LIST (windows->data);
}
typedef struct {
gboolean create;
......@@ -84,7 +82,7 @@ idle_create_connection (gpointer user_data)
}
static gboolean
handle_arguments (NMConnectionList *list,
handle_arguments (GApplication *application,
const char *type,
gboolean create,
gboolean show,
......@@ -92,6 +90,7 @@ handle_arguments (NMConnectionList *list,
const char *import,
gboolean quit_after)
{
NMConnectionList *list = _get_connection_list (application);
gboolean show_list = TRUE;
GType ctype = 0;
gs_free char *type_tmp = NULL;
......@@ -147,201 +146,78 @@ handle_arguments (NMConnectionList *list,
}
/* If only editing a single connection, exit when done with that connection */
if (show_list == FALSE && quit_after == TRUE)
g_signal_connect_swapped (list, "editing-done", G_CALLBACK (g_main_loop_quit), loop);
if (show_list == FALSE && quit_after == TRUE) {
g_signal_connect_swapped (list, "editing-done",
G_CALLBACK (g_application_quit),
application);
}
return show_list;
}
static void
handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
static gboolean
signal_handler (gpointer user_data)
{
NMConnectionList *list = NM_CONNECTION_LIST (user_data);
char *type = NULL, *uuid = NULL, *import = NULL;
gboolean create = FALSE, show = FALSE;
GApplication *application = G_APPLICATION (user_data);
if (g_strcmp0 (method_name, "Start") == 0) {
if (g_variant_is_of_type (parameters, (const GVariantType *) "(a{sv})")) {
gs_unref_variant GVariant *dict = NULL;
g_variant_get (parameters, "(@a{sv})", &dict);
g_variant_lookup (dict, ARG_TYPE, "s", &type);
g_variant_lookup (dict, ARG_UUID, "s", &uuid);
g_variant_lookup (dict, ARG_CREATE, "b", &create);
g_variant_lookup (dict, ARG_SHOW, "b", &show);
g_variant_lookup (dict, ARG_IMPORT, "s", &import);
if (handle_arguments (list, type, create, show, uuid, import, FALSE))
nm_connection_list_present (list);
g_dbus_method_invocation_return_value (invocation, NULL);
} else {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"Invalid argument type (not a dict)");
}
}
}
g_message ("Caught signal shutting down...");
g_application_quit (application);
static const GDBusInterfaceVTable interface_vtable = {
handle_method_call, NULL, NULL
};
static guint
start_service (GDBusConnection *bus,
NMConnectionList *list,
guint *out_registration_id)
{
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.gnome.nm_connection_editor'>"
" <method name='Start'>"
" <arg type='a{sv}' name='args' direction='in'/>"
" </method>"
" </interface>"
"</node>";
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
g_assert (introspection_data != NULL);
*out_registration_id = g_dbus_connection_register_object (bus,
"/",
introspection_data->interfaces[0],
&interface_vtable,
list, /* user_data */
NULL, /* user_data_free_func */
NULL); /* GError** */
return g_bus_own_name_on_connection (bus,
NM_CE_DBUS_SERVICE,
G_BUS_NAME_OWNER_FLAGS_NONE,
NULL,
NULL,
NULL,
NULL);
return G_SOURCE_REMOVE;
}
static gboolean
try_existing_instance (GDBusConnection *bus,
const char *type,
gboolean create,
gboolean show,
const char *uuid,
const char *import)
static void
editor_startup (GApplication *application, gpointer user_data)
{
gs_free char *owner = NULL;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *reply = NULL;
GVariantBuilder builder;
g_assert (bus);
reply = g_dbus_connection_call_sync (bus,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetNameOwner",
g_variant_new ("(s)", NM_CE_DBUS_SERVICE),
G_VARIANT_TYPE ("(s)"),
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */
NULL,
&error);
if (!reply) {
if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
g_warning ("Failed to get editor name owner: %s", error->message);
return FALSE;
}
GtkApplication *app = GTK_APPLICATION (application);
NMConnectionList *list;
g_variant_get (reply, "(s)", &owner);
if (!owner)
return FALSE;
g_variant_unref (reply);
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
if (type)
g_variant_builder_add (&builder, "{sv}", ARG_TYPE, g_variant_new_string (type));
if (create)
g_variant_builder_add (&builder, "{sv}", ARG_CREATE, g_variant_new_boolean (TRUE));
if (show)
g_variant_builder_add (&builder, "{sv}", ARG_SHOW, g_variant_new_boolean (TRUE));
if (uuid)
g_variant_builder_add (&builder, "{sv}", ARG_UUID, g_variant_new_string (uuid));
if (import)
g_variant_builder_add (&builder, "{sv}", ARG_IMPORT, g_variant_new_string (import));
reply = g_dbus_connection_call_sync (bus,
NM_CE_DBUS_SERVICE,
"/",
NM_CE_DBUS_INTERFACE,
"Start",
g_variant_new ("(@a{sv})", g_variant_builder_end (&builder)),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */
NULL,
&error);
if (!reply) {
g_warning ("Failed to send arguments to existing editor instance: %s", error->message);
return FALSE;
list = nm_connection_list_new ();
if (!list) {
g_warning ("Failed to initialize the UI, exiting...");
g_application_quit (application);
return;
}
return TRUE;
gtk_application_add_window (app, GTK_WINDOW (list));
}
static gboolean
signal_handler (gpointer user_data)
static void
editor_activate (GApplication *application, gpointer user_data)
{
int signo = GPOINTER_TO_INT (user_data);
g_message ("Caught signal %d, shutting down...", signo);
g_main_loop_quit (loop);
NMConnectionList *list = _get_connection_list (application);
return G_SOURCE_REMOVE;
nm_connection_list_present (list);
}
int
main (int argc, char *argv[])
static gint
editor_command_line (GApplication *application,
GApplicationCommandLine *command_line,
gpointer user_data)
{
gchar **argv;
gint argc;
GOptionContext *opt_ctx = NULL;
GError *error = NULL;
NMConnectionList *list = NULL;
guint owner_id = 0, registration_id = 0;
GDBusConnection *bus = NULL;
gs_free char *type = NULL, *uuid = NULL, *import = NULL;
gboolean create = FALSE, show = FALSE;
int ret = 1;
GOptionEntry entries[] = {
{ ARG_TYPE, 't', 0, G_OPTION_ARG_STRING, &type, "Type of connection to show or create", NM_SETTING_WIRED_SETTING_NAME },
{ ARG_CREATE, 'c', 0, G_OPTION_ARG_NONE, &create, "Create a new connection", NULL },
{ ARG_SHOW, 's', 0, G_OPTION_ARG_NONE, &show, "Show a given connection type page", NULL },
{ "edit", 'e', 0, G_OPTION_ARG_STRING, &uuid, "Edit an existing connection with a given UUID", "UUID" },
{ ARG_IMPORT, 'i', 0, G_OPTION_ARG_STRING, &import, "Import a VPN connection from given file", NULL },
/* This is not passed over D-Bus. */
{ "keep-above", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &nm_ce_keep_above, NULL, NULL },
{ "type", 't', 0, G_OPTION_ARG_STRING, &type, "Type of connection to show or create", NM_SETTING_WIRED_SETTING_NAME },
{ "create", 'c', 0, G_OPTION_ARG_NONE, &create, "Create a new connection", NULL },
{ "show", 's', 0, G_OPTION_ARG_NONE, &show, "Show a given connection type page", NULL },
{ "edit", 'e', 0, G_OPTION_ARG_STRING, &uuid, "Edit an existing connection with a given UUID", "UUID" },
{ "import", 'i', 0, G_OPTION_ARG_STRING, &import, "Import a VPN connection from given file", NULL },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, NMALOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
gtk_init (&argc, &argv);
textdomain (GETTEXT_PACKAGE);
argv = g_application_command_line_get_arguments (command_line, &argc);
opt_ctx = g_option_context_new (NULL);
g_option_context_set_summary (opt_ctx, "Allows users to view and edit network connection settings");
g_option_context_add_main_entries (opt_ctx, entries, NULL);
if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
g_printerr ("Failed to parse options: %s\n", error->message);
g_application_command_line_printerr (command_line, "Failed to parse options: %s\n", error->message);
g_error_free (error);
goto out;
}
......@@ -351,52 +227,45 @@ main (int argc, char *argv[])
type = g_strdup (NM_SETTING_GSM_SETTING_NAME);
}
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
if (bus) {
/* Check for an existing instance on the bus, and if there
* is one, send the arguments to it and exit instead of opening
* a second instance of the connection editor.
*/
if (try_existing_instance (bus, type, create, show, uuid, import)) {
/* success */
ret = 0;
goto out;
}
}
if (handle_arguments (application, type, create, show, uuid, import, FALSE))
g_application_activate (application);
loop = g_main_loop_new (NULL, FALSE);
ret = 0;
list = nm_connection_list_new ();
if (!list) {
g_warning ("Failed to initialize the UI, exiting...");
goto out;
}
g_signal_connect_swapped (list, "done", G_CALLBACK (g_main_loop_quit), loop);
out:
g_option_context_free (opt_ctx);
return ret;
}
if (bus)
owner_id = start_service (bus, list, &registration_id);
int
main (int argc, char *argv[])
{
gs_unref_object GtkApplication *app = NULL;
GOptionContext *opt_ctx;
GOptionEntry entries[] = {
/* This is not passed over D-Bus. */
{ "keep-above", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &nm_ce_keep_above, NULL, NULL },
{ NULL }
};
/* Figure out what page or editor window we'll show initially */
if (handle_arguments (list, type, create, show, uuid, import, (create || show || uuid || import)))
nm_connection_list_present (list);
bindtextdomain (GETTEXT_PACKAGE, NMALOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
app = gtk_application_new ("org.gnome.nm_connection_editor",
G_APPLICATION_HANDLES_COMMAND_LINE);
g_main_loop_run (loop);
ret = 0;
opt_ctx = g_option_context_new (NULL);
g_option_context_add_main_entries (opt_ctx, entries, NULL);
g_option_context_parse (opt_ctx, &argc, &argv, NULL);
g_option_context_free (opt_ctx);
out:
if (owner_id)
g_bus_unown_name (owner_id);
if (registration_id)
g_dbus_connection_unregister_object (bus, registration_id);
if (introspection_data)
g_dbus_node_info_unref (introspection_data);
g_clear_error (&error);
if (opt_ctx)
g_option_context_free (opt_ctx);
g_clear_object (&bus);
return ret;
}
g_signal_connect (app, "startup", G_CALLBACK (editor_startup), NULL);
g_signal_connect (app, "activate", G_CALLBACK (editor_activate), NULL);
g_signal_connect (app, "command-line", G_CALLBACK (editor_command_line), NULL);
g_unix_signal_add (SIGTERM, signal_handler, app);
g_unix_signal_add (SIGINT, signal_handler, app);
return g_application_run (G_APPLICATION (app), argc, argv);
}
......@@ -66,7 +66,7 @@ struct _NMConnectionListPrivate {
NM_TYPE_CONNECTION_LIST, \
NMConnectionListPrivate))
G_DEFINE_TYPE_WITH_CODE (NMConnectionList, nm_connection_list, GTK_TYPE_WINDOW,
G_DEFINE_TYPE_WITH_CODE (NMConnectionList, nm_connection_list, GTK_TYPE_APPLICATION_WINDOW,
G_ADD_PRIVATE (NMConnectionList))
#define COL_ID 0
......
......@@ -37,11 +37,11 @@
typedef struct _NMConnectionListPrivate NMConnectionListPrivate;
typedef struct {
GtkWindow parent;
GtkApplicationWindow parent;
} NMConnectionList;
typedef struct {
GtkWindowClass parent_class;
GtkApplicationWindowClass parent_class;
/* Signals */
void (*done) (NMConnectionList *list, gint result);
......
......@@ -2,7 +2,7 @@
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<template class="NMConnectionList" parent="GtkWindow">
<template class="NMConnectionList" parent="GtkApplicationWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Network Connections</property>
<property name="window_position">center</property>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment