[network-manager-applet] start fixing fast-user-switching
- From: Dan Williams <dcbw src gnome org>
- To: svn-commits-list gnome org
- Subject: [network-manager-applet] start fixing fast-user-switching
- Date: Fri, 8 May 2009 11:15:52 -0400 (EDT)
commit add51d01ff9a0520f17788c095ad762d0932ffd9
Author: Dan Williams <dcbw redhat com>
Date: Fri May 8 11:13:22 2009 -0400
start fixing fast-user-switching
Applet now claims a service on the session bus to enforce one-applet-per-session.
Further patches will actually relax the system bus service semantics to actually
fix fast-user-switching, so that only the applet with the active seat claims
the service on the system bus.
---
src/applet-dbus-manager.c | 423 ++++++++++++++++++++++++++++++---------------
src/applet-dbus-manager.h | 35 ++--
src/applet.c | 13 ++-
3 files changed, 315 insertions(+), 156 deletions(-)
diff --git a/src/applet-dbus-manager.c b/src/applet-dbus-manager.c
index b7822f9..68cce7f 100644
--- a/src/applet-dbus-manager.c
+++ b/src/applet-dbus-manager.c
@@ -30,8 +30,9 @@
#include "applet-dbus-manager.h"
enum {
- DBUS_CONNECTION_CHANGED = 0,
+ CONNECTION_CHANGED = 0,
NAME_OWNER_CHANGED,
+ EXIT_NOW,
NUM_SIGNALS
};
static guint signals[NUM_SIGNALS];
@@ -44,81 +45,142 @@ G_DEFINE_TYPE(AppletDBusManager, applet_dbus_manager, G_TYPE_OBJECT)
AppletDBusManagerPrivate))
typedef struct {
+ /* system bus */
DBusConnection * connection;
DBusGConnection *g_connection;
DBusGProxy * proxy;
gboolean started;
+
+ /* session bus */
+ DBusGConnection *session_g_connection;
+ DBusGProxy * session_proxy;
+
+ gulong recon_id;
} AppletDBusManagerPrivate;
-static gboolean applet_dbus_manager_init_bus (AppletDBusManager *self);
-static void applet_dbus_manager_cleanup (AppletDBusManager *self);
+static gboolean system_bus_init (AppletDBusManager *self);
+static void system_bus_cleanup (AppletDBusManager *self);
+
+static void session_bus_cleanup (AppletDBusManager *self);
+
static void start_reconnection_timeout (AppletDBusManager *self);
-static void destroy_cb (DBusGProxy *proxy, gpointer user_data);
-AppletDBusManager *
-applet_dbus_manager_get (void)
+/*
+ * The applet claims two services:
+ * a) system bus service - to provide settings to NetworkManager and other
+ * programs that want information about network connections
+ * b) session bus service - to enforce single-applet-per-session; this service
+ * *must* be claimed, otherwise the applet quits becuase there is already
+ * an applet running in the session.
+ */
+
+
+DBusConnection *
+applet_dbus_manager_get_dbus_connection (AppletDBusManager *self)
{
- static AppletDBusManager *singleton = NULL;
+ AppletDBusManagerPrivate *priv;
- if (!singleton) {
- singleton = APPLET_DBUS_MANAGER (g_object_new (APPLET_TYPE_DBUS_MANAGER, NULL));
- if (!applet_dbus_manager_init_bus (singleton))
- start_reconnection_timeout (singleton);
- } else {
- g_object_ref (singleton);
- }
+ g_return_val_if_fail (APPLET_IS_DBUS_MANAGER (self), NULL);
- g_assert (singleton);
- return singleton;
+ priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
+ return priv->g_connection ? dbus_g_connection_get_connection (priv->g_connection) : NULL;
}
-static void
-applet_dbus_manager_init (AppletDBusManager *self)
+DBusGConnection *
+applet_dbus_manager_get_connection (AppletDBusManager *self)
{
+ g_return_val_if_fail (APPLET_IS_DBUS_MANAGER (self), NULL);
+
+ return APPLET_DBUS_MANAGER_GET_PRIVATE (self)->g_connection;
}
-static void
-applet_dbus_manager_finalize (GObject *object)
+static DBusGConnection *
+bus_init (DBusBusType bus_type,
+ DBusGProxy **proxy,
+ GCallback destroy_cb,
+ gpointer user_data,
+ const char *detail)
{
- AppletDBusManager *self = APPLET_DBUS_MANAGER (object);
+ DBusGConnection *gc;
+ DBusConnection *connection;
+ GError *error = NULL;
- applet_dbus_manager_cleanup (self);
+ dbus_connection_set_change_sigpipe (TRUE);
- G_OBJECT_CLASS (applet_dbus_manager_parent_class)->finalize (object);
+ gc = dbus_g_bus_get (bus_type, &error);
+ if (!gc) {
+ nm_warning ("Could not get the %s bus. Make sure the message "
+ "bus daemon is running! Message: %s",
+ detail, error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ connection = dbus_g_connection_get_connection (gc);
+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+ *proxy = dbus_g_proxy_new_for_name (gc,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus");
+ if (!*proxy) {
+ nm_warning ("Could not get the DBus object!");
+ dbus_g_connection_unref (gc);
+ gc = NULL;
+ } else
+ g_signal_connect (*proxy, "destroy", destroy_cb, user_data);
+
+ return gc;
}
-static void
-applet_dbus_manager_class_init (AppletDBusManagerClass *klass)
+static gboolean
+request_name (DBusGProxy *proxy, int flags, const char *detail)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = applet_dbus_manager_finalize;
+ int request_name_result;
+ GError *error;
- signals[DBUS_CONNECTION_CHANGED] =
- g_signal_new ("dbus-connection-changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppletDBusManagerClass, dbus_connection_changed),
- NULL, NULL, nma_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
+ if (!dbus_g_proxy_call (proxy, "RequestName", &error,
+ G_TYPE_STRING, NM_DBUS_SERVICE_USER_SETTINGS,
+ G_TYPE_UINT, flags,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &request_name_result,
+ G_TYPE_INVALID)) {
+ nm_warning ("Could not acquire the %s service.\n"
+ " Message: '%s'", detail, error->message);
+ g_error_free (error);
+ return FALSE;
+ }
- signals[NAME_OWNER_CHANGED] =
- g_signal_new ("name-owner-changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppletDBusManagerClass, name_owner_changed),
- NULL, NULL, nma_marshal_VOID__STRING_STRING_STRING,
- G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ nm_warning ("Could not acquire the %s service as it is already "
+ "taken. Return: %d",
+ detail, request_name_result);
+ return FALSE;
+ }
- g_type_class_add_private (klass, sizeof (AppletDBusManagerPrivate));
+ return TRUE;
}
+static void
+system_bus_destroy_cb (DBusGProxy *proxy, gpointer user_data)
+{
+ AppletDBusManager *self = APPLET_DBUS_MANAGER (user_data);
+
+ /* Clean up existing connection */
+ nm_info ("disconnected by the system bus.");
+ system_bus_cleanup (self);
+
+ g_signal_emit (G_OBJECT (self),
+ signals[CONNECTION_CHANGED],
+ 0, NULL);
+
+ start_reconnection_timeout (self);
+}
-/* Only cleanup a specific dbus connection, not all our private data */
static void
-applet_dbus_manager_cleanup (AppletDBusManager *self)
+system_bus_cleanup (AppletDBusManager *self)
{
AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
@@ -129,7 +191,7 @@ applet_dbus_manager_cleanup (AppletDBusManager *self)
}
if (priv->proxy) {
- g_signal_handlers_disconnect_by_func (priv->proxy, destroy_cb, self);
+ g_signal_handlers_disconnect_by_func (priv->proxy, system_bus_destroy_cb, self);
g_object_unref (priv->proxy);
priv->proxy = NULL;
}
@@ -137,33 +199,114 @@ applet_dbus_manager_cleanup (AppletDBusManager *self)
priv->started = FALSE;
}
+static void
+session_bus_destroy_cb (DBusGProxy *proxy, gpointer user_data)
+{
+ AppletDBusManager *self = APPLET_DBUS_MANAGER (user_data);
+
+ nm_info ("disconnected by the session bus.");
+ session_bus_cleanup (self);
+ start_reconnection_timeout (self);
+}
+
+static void
+session_bus_cleanup (AppletDBusManager *self)
+{
+ AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
+
+ if (priv->session_g_connection) {
+ dbus_g_connection_unref (priv->session_g_connection);
+ priv->session_g_connection = NULL;
+ }
+
+ if (priv->session_proxy) {
+ g_signal_handlers_disconnect_by_func (priv->session_proxy, session_bus_destroy_cb, self);
+ g_object_unref (priv->session_proxy);
+ priv->session_proxy = NULL;
+ }
+}
+
+static gboolean
+start_session_bus_service (AppletDBusManager *self)
+{
+ return request_name (APPLET_DBUS_MANAGER_GET_PRIVATE (self)->session_proxy,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ "session");
+}
+
static gboolean
-applet_dbus_manager_reconnect (gpointer user_data)
+session_bus_init (AppletDBusManager *self)
+{
+ AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
+
+ if (priv->session_g_connection) {
+ nm_warning ("session connection already exists");
+ return FALSE;
+ }
+
+ priv->session_g_connection = bus_init (DBUS_BUS_SESSION, &(priv->session_proxy),
+ G_CALLBACK (session_bus_destroy_cb), self,
+ "session");
+ if (!priv->session_g_connection) {
+ session_bus_cleanup (self);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+reconnect_cb (gpointer user_data)
{
AppletDBusManager *self = APPLET_DBUS_MANAGER (user_data);
+ AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
+ guint32 i = 0;
g_assert (self != NULL);
- if (applet_dbus_manager_init_bus (self)) {
- if (applet_dbus_manager_start_service (self)) {
- nm_info ("reconnected to the system bus.");
- g_signal_emit (self,
- signals[DBUS_CONNECTION_CHANGED],
- 0,
- APPLET_DBUS_MANAGER_GET_PRIVATE (self)->connection);
- return TRUE;
+ /* System bus connection */
+ if (priv->g_connection)
+ i++;
+ else {
+ if (system_bus_init (self)) {
+ if (applet_dbus_manager_start_service (self)) {
+ nm_info ("reconnected to the system bus.");
+ g_signal_emit (self, signals[CONNECTION_CHANGED],
+ 0, priv->connection);
+ i++;
+ } else
+ system_bus_cleanup (self);
+ }
+ }
+
+ if (priv->session_g_connection)
+ i++;
+ else {
+ if (session_bus_init (self)) {
+ nm_info ("reconnected to the session bus.");
+ if (start_session_bus_service (self))
+ i++;
+ else {
+ session_bus_cleanup (self);
+ g_signal_emit (self, signals[EXIT_NOW], 0);
+ }
}
}
- applet_dbus_manager_cleanup (self);
- return FALSE;
+ /* Keep the reconnect timeout active if at least one of the system or
+ * session bus connections still needs to be reconnected.
+ */
+ return i < 2 ? FALSE : TRUE;
}
static void
start_reconnection_timeout (AppletDBusManager *self)
{
+ AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
+
/* Schedule timeout for reconnection attempts */
- g_timeout_add (3000, applet_dbus_manager_reconnect, self);
+ if (!priv->recon_id)
+ priv->recon_id = g_timeout_add (3000, reconnect_cb, self);
}
char *
@@ -227,58 +370,24 @@ proxy_name_owner_changed (DBusGProxy *proxy,
name, old_owner, new_owner);
}
-static void
-destroy_cb (DBusGProxy *proxy, gpointer user_data)
-{
- AppletDBusManager *self = APPLET_DBUS_MANAGER (user_data);
-
- /* Clean up existing connection */
- nm_info ("disconnected by the system bus.");
- applet_dbus_manager_cleanup (self);
-
- g_signal_emit (G_OBJECT (self),
- signals[DBUS_CONNECTION_CHANGED],
- 0, NULL);
-
- start_reconnection_timeout (self);
-}
-
static gboolean
-applet_dbus_manager_init_bus (AppletDBusManager *self)
+system_bus_init (AppletDBusManager *self)
{
AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
- GError *err = NULL;
if (priv->connection) {
nm_warning ("DBus Manager already has a valid connection.");
return FALSE;
}
- dbus_connection_set_change_sigpipe (TRUE);
-
- priv->g_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
+ priv->g_connection = bus_init (DBUS_BUS_SYSTEM, &(priv->proxy),
+ G_CALLBACK (system_bus_destroy_cb), self,
+ "system");
if (!priv->g_connection) {
- nm_warning ("Could not get the system bus. Make sure "
- "the message bus daemon is running! Message: %s",
- err->message);
- g_error_free (err);
- goto error;
- }
-
- priv->connection = dbus_g_connection_get_connection (priv->g_connection);
- dbus_connection_set_exit_on_disconnect (priv->connection, FALSE);
-
- priv->proxy = dbus_g_proxy_new_for_name (priv->g_connection,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus");
- if (!priv->proxy) {
- nm_warning ("Could not get the DBus object!");
- goto error;
+ system_bus_cleanup (self);
+ return FALSE;
}
- g_signal_connect (priv->proxy, "destroy", G_CALLBACK (destroy_cb), self);
-
dbus_g_proxy_add_signal (priv->proxy, "NameOwnerChanged",
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INVALID);
@@ -287,10 +396,6 @@ applet_dbus_manager_init_bus (AppletDBusManager *self)
G_CALLBACK (proxy_name_owner_changed),
self, NULL);
return TRUE;
-
-error:
- applet_dbus_manager_cleanup (self);
- return FALSE;
}
/* Register our service on the bus; shouldn't be called until
@@ -301,59 +406,101 @@ gboolean
applet_dbus_manager_start_service (AppletDBusManager *self)
{
AppletDBusManagerPrivate *priv;
- int flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
- int request_name_result;
- GError *err = NULL;
g_return_val_if_fail (APPLET_IS_DBUS_MANAGER (self), FALSE);
priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
- if (priv->started) {
- nm_warning ("Service has already started.");
- return FALSE;
+ if (!priv->started) {
+ priv->started = request_name (priv->proxy,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ "NetworkManagerUserSettings");
+ if (!priv->started)
+ system_bus_cleanup (self);
}
- if (!dbus_g_proxy_call (priv->proxy, "RequestName", &err,
- G_TYPE_STRING, NM_DBUS_SERVICE_USER_SETTINGS,
- G_TYPE_UINT, flags,
- G_TYPE_INVALID,
- G_TYPE_UINT, &request_name_result,
- G_TYPE_INVALID)) {
- nm_warning ("Could not acquire the NetworkManagerUserSettings service.\n"
- " Message: '%s'", err->message);
- g_error_free (err);
- goto out;
- }
+ return priv->started;
+}
- if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- nm_warning ("Could not acquire the NetworkManagerUserSettings service "
- "as it is already taken. Return: %d",
- request_name_result);
- goto out;
- }
+AppletDBusManager *
+applet_dbus_manager_get (void)
+{
+ static AppletDBusManager *singleton = NULL;
- priv->started = TRUE;
+ if (!singleton) {
+ singleton = APPLET_DBUS_MANAGER (g_object_new (APPLET_TYPE_DBUS_MANAGER, NULL));
-out:
- if (!priv->started)
- applet_dbus_manager_cleanup (self);
+ /* If there's another applet on the session bus, have to quit */
+ if (session_bus_init (singleton)) {
+ if (!start_session_bus_service (singleton)) {
+ g_object_unref (singleton);
+ singleton = NULL;
+ return NULL;
+ }
+ } else
+ start_reconnection_timeout (singleton);
- return priv->started;
+ if (!system_bus_init (singleton))
+ start_reconnection_timeout (singleton);
+ } else {
+ g_object_ref (singleton);
+ }
+
+ g_assert (singleton);
+ return singleton;
}
-DBusConnection *
-applet_dbus_manager_get_dbus_connection (AppletDBusManager *self)
+static void
+applet_dbus_manager_init (AppletDBusManager *self)
{
- g_return_val_if_fail (APPLET_IS_DBUS_MANAGER (self), NULL);
+}
- return APPLET_DBUS_MANAGER_GET_PRIVATE (self)->connection;
+static void
+applet_dbus_manager_finalize (GObject *object)
+{
+ AppletDBusManager *self = APPLET_DBUS_MANAGER (object);
+ AppletDBusManagerPrivate *priv = APPLET_DBUS_MANAGER_GET_PRIVATE (self);
+
+ system_bus_cleanup (self);
+ session_bus_cleanup (self);
+
+ if (priv->recon_id)
+ g_source_remove (priv->recon_id);
+
+ G_OBJECT_CLASS (applet_dbus_manager_parent_class)->finalize (object);
}
-DBusGConnection *
-applet_dbus_manager_get_connection (AppletDBusManager *self)
+static void
+applet_dbus_manager_class_init (AppletDBusManagerClass *klass)
{
- g_return_val_if_fail (APPLET_IS_DBUS_MANAGER (self), NULL);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- return APPLET_DBUS_MANAGER_GET_PRIVATE (self)->g_connection;
+ object_class->finalize = applet_dbus_manager_finalize;
+
+ signals[CONNECTION_CHANGED] =
+ g_signal_new ("dbus-connection-changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (AppletDBusManagerClass, connection_changed),
+ NULL, NULL, nma_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ signals[NAME_OWNER_CHANGED] =
+ g_signal_new ("name-owner-changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (AppletDBusManagerClass, name_owner_changed),
+ NULL, NULL, nma_marshal_VOID__STRING_STRING_STRING,
+ G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+ signals[EXIT_NOW] =
+ g_signal_new ("exit-now",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (AppletDBusManagerClass, exit_now),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (klass, sizeof (AppletDBusManagerPrivate));
}
+
diff --git a/src/applet-dbus-manager.h b/src/applet-dbus-manager.h
index d9f86fa..f125620 100644
--- a/src/applet-dbus-manager.h
+++ b/src/applet-dbus-manager.h
@@ -47,31 +47,34 @@ typedef struct {
GObjectClass parent;
/* Signals */
- void (*dbus_connection_changed) (AppletDBusManager *mgr,
- DBusConnection *connection);
-
- void (*name_owner_changed) (AppletDBusManager *mgr,
- DBusConnection *connection,
- const char *name,
- const char *old_owner,
- const char *new_owner);
+ void (*connection_changed) (AppletDBusManager *mgr,
+ DBusConnection *connection);
+
+ void (*name_owner_changed) (AppletDBusManager *mgr,
+ DBusConnection *connection,
+ const char *name,
+ const char *old_owner,
+ const char *new_owner);
+
+ void (*exit_now) (AppletDBusManager *mgr);
} AppletDBusManagerClass;
GType applet_dbus_manager_get_type (void);
-AppletDBusManager * applet_dbus_manager_get (void);
+AppletDBusManager *applet_dbus_manager_get (void);
-char * applet_dbus_manager_get_name_owner (AppletDBusManager *self,
- const char *name);
+char *applet_dbus_manager_get_name_owner (AppletDBusManager *self,
+ const char *name);
-gboolean applet_dbus_manager_start_service (AppletDBusManager *self);
+gboolean applet_dbus_manager_start_service (AppletDBusManager *self);
-gboolean applet_dbus_manager_name_has_owner (AppletDBusManager *self,
- const char *name);
+gboolean applet_dbus_manager_name_has_owner (AppletDBusManager *self,
+ const char *name);
-DBusConnection * applet_dbus_manager_get_dbus_connection (AppletDBusManager *self);
-DBusGConnection * applet_dbus_manager_get_connection (AppletDBusManager *self);
+DBusConnection *applet_dbus_manager_get_dbus_connection (AppletDBusManager *self);
+DBusGConnection *applet_dbus_manager_get_connection (AppletDBusManager *self);
G_END_DECLS
#endif /* __APPLET_DBUS_MANAGER_H__ */
+
diff --git a/src/applet.c b/src/applet.c
index c189c1f..1cec7f7 100644
--- a/src/applet.c
+++ b/src/applet.c
@@ -2471,6 +2471,14 @@ applet_pre_keyring_callback (gpointer user_data)
}
}
+static void
+exit_cb (GObject *ignored, gpointer user_data)
+{
+ NMApplet *applet = user_data;
+
+ g_main_loop_quit (applet->loop);
+}
+
static GObject *
constructor (GType type,
guint n_props,
@@ -2525,6 +2533,7 @@ constructor (GType type,
g_object_unref (applet);
return NULL;
}
+ g_signal_connect (G_OBJECT (dbus_mgr), "exit-now", G_CALLBACK (exit_cb), applet);
applet->dbus_settings = (NMDBusSettings *) nm_dbus_settings_system_new (applet_dbus_manager_get_connection (dbus_mgr));
@@ -2539,8 +2548,8 @@ constructor (GType type,
/* Start our DBus service */
if (!applet_dbus_manager_start_service (dbus_mgr)) {
- g_object_unref (applet);
- return NULL;
+ g_object_unref (applet);
+ return NULL;
}
/* Initialize device classes */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]