[glib/application-replace: 312/313] GApplication: Add a way to replace a unique instance
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/application-replace: 312/313] GApplication: Add a way to replace a unique instance
- Date: Tue, 30 Oct 2018 00:03:59 +0000 (UTC)
commit f83b9d81005705cbda3f9f86b8aec754b04c84eb
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Aug 18 15:35:33 2018 -0400
GApplication: Add a way to replace a unique instance
While uniqueness is great, sometimes you want to restart
a newer version of the same app. These two flags make that
possible.
We also add a ::name-lost signal, that is emitted when it
happens. The default handler for this signal just calls
g_application_quit(), but applications may want to connect
and do cleanup or state-saving here.
gio/gapplication.c | 46 ++++++++++++++++++++++++++++++++++
gio/gapplication.h | 3 ++-
gio/gapplicationimpl-dbus.c | 60 ++++++++++++++++++++++++++++++++++++++++++---
gio/gioenums.h | 9 ++++++-
4 files changed, 112 insertions(+), 6 deletions(-)
---
diff --git a/gio/gapplication.c b/gio/gapplication.c
index d4a0cd7ca..c822207eb 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -212,6 +212,7 @@
* @dbus_register vfunc. Since: 2.34
* @handle_local_options: invoked locally after the parsing of the commandline
* options has occurred. Since: 2.40
+ * @name_lost: invoked when another instance is taking over the name. Since: 2.58
*
* Virtual function table for #GApplication.
*
@@ -277,6 +278,7 @@ enum
SIGNAL_ACTION,
SIGNAL_COMMAND_LINE,
SIGNAL_HANDLE_LOCAL_OPTIONS,
+ SIGNAL_NAME_LOST,
NR_SIGNALS
};
@@ -476,6 +478,7 @@ g_application_parse_command_line (GApplication *application,
{
gboolean become_service = FALSE;
gchar *app_id = NULL;
+ gboolean replace = FALSE;
GVariantDict *dict = NULL;
GOptionContext *context;
GOptionGroup *gapplication_group;
@@ -557,6 +560,18 @@ g_application_parse_command_line (GApplication *application,
g_option_group_add_entries (gapplication_group, entries);
}
+ /* Allow replacing if the application allows it */
+ if (application->priv->flags & G_APPLICATION_ALLOW_REPLACEMENT)
+ {
+ GOptionEntry entries[] = {
+ { "gapplication-replace", '\0', 0, G_OPTION_ARG_NONE, &replace,
+ N_("Replace the running instance") },
+ { NULL }
+ };
+
+ g_option_group_add_entries (gapplication_group, entries);
+ }
+
/* Now we parse... */
if (!g_option_context_parse_strv (context, arguments, error))
goto out;
@@ -569,6 +584,10 @@ g_application_parse_command_line (GApplication *application,
if (app_id)
g_application_set_application_id (application, app_id);
+ /* Check for --gapplication-replace */
+ if (replace)
+ application->priv->flags |= G_APPLICATION_REPLACE;
+
dict = g_variant_dict_new (NULL);
if (application->priv->packed_options)
{
@@ -1177,6 +1196,13 @@ g_application_real_dbus_unregister (GApplication *application,
{
}
+static gboolean
+g_application_real_name_lost (GApplication *application)
+{
+ g_application_quit (application);
+ return TRUE;
+}
+
/* GObject implementation stuff {{{1 */
static void
g_application_set_property (GObject *object,
@@ -1434,6 +1460,7 @@ g_application_class_init (GApplicationClass *class)
class->add_platform_data = g_application_real_add_platform_data;
class->dbus_register = g_application_real_dbus_register;
class->dbus_unregister = g_application_real_dbus_unregister;
+ class->name_lost = g_application_real_name_lost;
g_object_class_install_property (object_class, PROP_APPLICATION_ID,
g_param_spec_string ("application-id",
@@ -1628,6 +1655,25 @@ g_application_class_init (GApplicationClass *class)
g_application_handle_local_options_accumulator, NULL, NULL,
G_TYPE_INT, 1, G_TYPE_VARIANT_DICT);
+ /**
+ * GApplication::name-lost:
+ * @application: the application
+ *
+ * The ::name-lost signal is emitted only on the registered primary instance
+ * when a new instance has taken over. This can only happen if the application
+ * is using the %G_APPLICATION_ALLOW_REPLACEMENT flag.
+ *
+ * The default handler for this signal calls g_application_quit().
+ *
+ * Returns: %TRUE if the signal has been handled
+ *
+ * Since: 2.60
+ */
+ g_application_signals[SIGNAL_NAME_LOST] =
+ g_signal_new (I_("name-lost"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GApplicationClass, name_lost),
+ g_signal_accumulator_true_handled, NULL, NULL,
+ G_TYPE_BOOLEAN, 0);
}
/* Application ID validity {{{1 */
diff --git a/gio/gapplication.h b/gio/gapplication.h
index cdb93655a..adc32ed44 100644
--- a/gio/gapplication.h
+++ b/gio/gapplication.h
@@ -112,9 +112,10 @@ struct _GApplicationClass
const gchar *object_path);
gint (* handle_local_options)(GApplication *application,
GVariantDict *options);
+ gboolean (* name_lost) (GApplication *application);
/*< private >*/
- gpointer padding[8];
+ gpointer padding[7];
};
GLIB_AVAILABLE_IN_ALL
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c
index f9e5e710d..46f16a7d4 100644
--- a/gio/gapplicationimpl-dbus.c
+++ b/gio/gapplicationimpl-dbus.c
@@ -111,6 +111,7 @@ struct _GApplicationImpl
GDBusConnection *session_bus;
GActionGroup *exported_actions;
const gchar *bus_name;
+ guint name_lost_signal;
gchar *object_path;
guint object_id;
@@ -327,6 +328,25 @@ application_path_from_appid (const gchar *appid)
return appid_path;
}
+static void g_application_impl_stop_primary (GApplicationImpl *impl);
+
+static void
+name_lost (GDBusConnection *bus,
+ const char *sender_name,
+ const char *object_path,
+ const char *interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GApplicationImpl *impl = user_data;
+ gboolean handled;
+
+ impl->primary = FALSE;
+ g_application_impl_stop_primary (impl);
+ g_signal_emit_by_name (impl->app, "name-lost", &handled);
+}
+
/* Attempt to become the primary instance.
*
* Returns %TRUE if everything went OK, regardless of if we became the
@@ -347,6 +367,8 @@ g_application_impl_attempt_primary (GApplicationImpl *impl,
NULL /* set_property */
};
GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
+ GBusNameOwnerFlags flags;
+ GApplicationFlags app_flags;
GVariant *reply;
guint32 rval;
@@ -426,12 +448,30 @@ g_application_impl_attempt_primary (GApplicationImpl *impl,
* the well-known name and fall back to remote mode (!is_primary)
* in the case that we can't do that.
*/
+ flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE;
+ app_flags = g_application_get_flags (impl->app);
+
+ if (app_flags & G_APPLICATION_ALLOW_REPLACEMENT)
+ {
+ impl->name_lost_signal = g_dbus_connection_signal_subscribe (impl->session_bus,
+ "org.freedesktop.DBus",
+ "org.freedesktop.DBus",
+ "NameLost",
+ "/org/freedesktop/DBus",
+ impl->bus_name,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ name_lost,
+ impl,
+ NULL);
+
+ flags |= G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
+ }
+ if (app_flags & G_APPLICATION_REPLACE)
+ flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
+
reply = g_dbus_connection_call_sync (impl->session_bus, "org.freedesktop.DBus", "/org/freedesktop/DBus",
"org.freedesktop.DBus", "RequestName",
- g_variant_new ("(su)",
- impl->bus_name,
- G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE),
- G_VARIANT_TYPE ("(u)"),
+ g_variant_new ("(su)", impl->bus_name, flags), G_VARIANT_TYPE ("(u)"),
0, -1, cancellable, error);
if (reply == NULL)
@@ -443,6 +483,12 @@ g_application_impl_attempt_primary (GApplicationImpl *impl,
/* DBUS_REQUEST_NAME_REPLY_EXISTS: 3 */
impl->primary = (rval != 3);
+ if (!impl->primary && impl->name_lost_signal)
+ {
+ g_dbus_connection_signal_unsubscribe (impl->session_bus, impl->name_lost_signal);
+ impl->name_lost_signal = 0;
+ }
+
return TRUE;
}
@@ -485,6 +531,12 @@ g_application_impl_stop_primary (GApplicationImpl *impl)
impl->actions_id = 0;
}
+ if (impl->name_lost_signal)
+ {
+ g_dbus_connection_signal_unsubscribe (impl->session_bus, impl->name_lost_signal);
+ impl->name_lost_signal = 0;
+ }
+
if (impl->primary && impl->bus_name)
{
g_dbus_connection_call (impl->session_bus, "org.freedesktop.DBus",
diff --git a/gio/gioenums.h b/gio/gioenums.h
index a83fa71f1..388441cb8 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1474,6 +1474,11 @@ typedef enum
* @G_APPLICATION_CAN_OVERRIDE_APP_ID: Allow users to override the
* application ID from the command line with `--gapplication-app-id`.
* Since: 2.48
+ * @G_APPLICATION_ALLOW_REPLACEMENT: Allow another instance to take over
+ * the bus name. Since: 2.60
+ * @G_APPLICATION_REPLACE: Take over from another instance. This flag is
+ * usually set by passing --gapplication-replace on the commandline.
+ * Since: 2.60
*
* Flags used to define the behaviour of a #GApplication.
*
@@ -1491,7 +1496,9 @@ typedef enum
G_APPLICATION_NON_UNIQUE = (1 << 5),
- G_APPLICATION_CAN_OVERRIDE_APP_ID = (1 << 6)
+ G_APPLICATION_CAN_OVERRIDE_APP_ID = (1 << 6),
+ G_APPLICATION_ALLOW_REPLACEMENT = (1 << 7),
+ G_APPLICATION_REPLACE = (1 << 8)
} GApplicationFlags;
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]