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.
This commit is contained in:
Matthias Clasen
2018-08-18 15:35:33 -04:00
parent 051c9ada8e
commit 3a4b18f903
4 changed files with 117 additions and 7 deletions

View File

@@ -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 name_owner_flags;
GApplicationFlags app_flags;
GVariant *reply;
guint32 rval;
@@ -426,11 +448,33 @@ 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.
*/
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),
name_owner_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);
name_owner_flags |= G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
}
if (app_flags & G_APPLICATION_REPLACE)
name_owner_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, name_owner_flags),
G_VARIANT_TYPE ("(u)"),
0, -1, cancellable, error);
@@ -443,6 +487,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 +535,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",