From ae39f7001e5603010afc02de29787ade6d48ef14 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 22 Mar 2013 16:34:34 -0500 Subject: port indicator-session to GMenu/cmake. Code coverage increased from 0% to 95.4%. --- src/backend-dbus/users.c | 810 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 810 insertions(+) create mode 100644 src/backend-dbus/users.c (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c new file mode 100644 index 0000000..4798d33 --- /dev/null +++ b/src/backend-dbus/users.c @@ -0,0 +1,810 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-consolekit-manager.h" +#include "dbus-user.h" + +#include "users.h" + +struct _IndicatorSessionUsersDbusPriv +{ + char * active_session_id; + + Accounts * accounts; + + DisplayManagerSeat * dm_seat; + + ConsoleKitSeat * seat_proxy; + + /* user's dbus object path -> AccountsUser* */ + GHashTable * path_to_user; + + /* uint32 user-id --> user's dbus object path */ + GHashTable * uid_to_user_path; + + /* uint32 user-id --> hashset of ssid strings */ + GHashTable * uid_to_sessions; + + /* ssid string --> uint32 user-id */ + GHashTable * session_to_uid; + + GCancellable * cancellable; +}; + +typedef IndicatorSessionUsersDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionUsersDbus, + indicator_session_users_dbus, + INDICATOR_TYPE_SESSION_USERS) + +/*** +**** +***/ + +static void create_user_proxy_for_path (IndicatorSessionUsersDbus * self, + const char * path); + +static void create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, + const char * ssid); + +static void +emit_user_changed_for_path (IndicatorSessionUsersDbus * self, const char * path) +{ + AccountsUser * user = g_hash_table_lookup (self->priv->path_to_user, path); + + if (user && !accounts_user_get_system_account (user)) + indicator_session_users_changed (INDICATOR_SESSION_USERS(self), path); +} + +static void +emit_user_changed_for_uid (IndicatorSessionUsersDbus * self, guint uid) +{ + const char * path; + + if ((path = g_hash_table_lookup (self->priv->uid_to_user_path, GUINT_TO_POINTER(uid)))) + emit_user_changed_for_path (self, path); +} + +/*** +**** ACCOUNT MANAGER / USER TRACKING +***/ + +/* called when a user proxy gets the 'Changed' signal */ +static void +on_user_changed (AccountsUser * user, gpointer gself) +{ + /* Accounts.User doesn't update properties in the standard way, + * so create a new proxy to pull in the new properties. + * The older proxy is freed when it's removed from our path_to_user hash */ + const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); + create_user_proxy_for_path (gself, path); +} + +static void +track_user (IndicatorSessionUsersDbus * self, + AccountsUser * user) +{ + priv_t * p; + const char * path; + gboolean already_had_user; + + p = self->priv; + + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); + already_had_user = g_hash_table_contains (p->path_to_user, path); + + g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); + g_hash_table_insert (p->path_to_user, g_strdup(path), user); + + if (already_had_user) + { + emit_user_changed_for_path (self, path); + } + else + { + const guint uid = (guint) accounts_user_get_uid (user); + + g_hash_table_insert (p->uid_to_user_path, + GUINT_TO_POINTER(uid), + g_strdup(path)); + + if (!accounts_user_get_system_account (user)) + indicator_session_users_added (INDICATOR_SESSION_USERS(self), path); + } +} + +static void +untrack_user (IndicatorSessionUsersDbus * self, + const gchar * path) +{ + g_hash_table_remove (self->priv->path_to_user, path); + + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), path); +} + + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer self) +{ + GError * err; + AccountsUser * user; + + err = NULL; + user = accounts_user_proxy_new_for_bus_finish (res, &err); + if (err != NULL) + { + g_warning ("%s: %s", G_STRFUNC, err->message); + g_error_free (err); + } + else + { + track_user (self, user); + } +} + +static void +create_user_proxy_for_path (IndicatorSessionUsersDbus * self, + const char * path) +{ + const char * name = "org.freedesktop.Accounts"; + const GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_user_proxy_ready, self); +} + +static void +on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** paths; + + err = NULL; + paths = NULL; + accounts_call_list_cached_users_finish (ACCOUNTS(o), &paths, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; paths && paths[i]; ++i) + create_user_proxy_for_path (gself, paths[i]); + + g_strfreev (paths); + } +} + +static void +set_account_manager (IndicatorSessionUsersDbus * self, Accounts * a) +{ + priv_t * p = self->priv; + + if (p->accounts != NULL) + { + g_signal_handlers_disconnect_by_data (p->accounts, self); + g_clear_object (&p->accounts); + } + + if (a != NULL) + { + p->accounts = g_object_ref (a); + + accounts_call_list_cached_users (a, + self->priv->cancellable, + on_user_list_ready, + self); + + g_signal_connect_swapped (a, "user-added", + G_CALLBACK(create_user_proxy_for_path), self); + + g_signal_connect_swapped (a, "user-deleted", + G_CALLBACK(untrack_user), self); + } +} + +#if 0 +static void +create_accounts_proxy (IndicatorSessionUsersDbus * self) +{ + const char * name = "org.freedesktop.Accounts"; + const char * path = "/org/freedesktop/Accounts"; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_accounts_proxy_ready, self); +} +#endif + +/** + * SEAT / SESSION TRACKING + * + * There are two simple goals here: + * + * 1. Keep track of how many GUI sessions each user has + * so that we can set the 'is_logged_in' flag correctly + * + * 2. Also track which is the current session, + * so that we can compare it to those GUI sessions to + * set the 'is_current_session' flag correctly. + * + * Now that you know the goals, these steps may make more sense: + * + * 1. create a ConsoleKitManager proxy + * 2. ask it for the current session + * 3. create a corresponding Session proxy + * 4. ask that Session proxy for its seat + * 5. create a corresponding Seat proxy + * 6. connect to that seat's session-added / session-removed signals + * 7. ask the seat for a list of its current sessions + * 8. create corresponding Session proxies + * 9. of them, look for the GUI sessions by checking their X11 properties + * 10. for each GUI session, get the corresponding uid + * 11. use the information to update our uid <--> GUI sessions tables + */ + +static void +track_session (IndicatorSessionUsersDbus * self, + const char * ssid, + guint uid) +{ + gpointer uid_key; + GHashTable * sessions; + + uid_key = GUINT_TO_POINTER (uid); + sessions = g_hash_table_lookup (self->priv->uid_to_sessions, uid_key); + if (sessions == NULL) + { + sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (self->priv->uid_to_sessions, uid_key, sessions); + } + + g_hash_table_add (sessions, g_strdup (ssid)); + g_hash_table_insert (self->priv->session_to_uid, g_strdup(ssid), uid_key); + + g_debug ("%s %s now tracking ssid:%s uid:%u. uid has %u tracked ssids.", + G_STRLOC, G_STRFUNC, ssid, uid, g_hash_table_size (sessions)); + + emit_user_changed_for_uid (self, uid); +} + +static void +untrack_session (IndicatorSessionUsersDbus * self, + const char * ssid) +{ + gpointer uidptr; + priv_t * p = self->priv; + + if (g_hash_table_lookup_extended (p->session_to_uid, ssid, NULL, &uidptr)) + { + const guint uid = GPOINTER_TO_UINT (uidptr); + GHashTable * sessions = g_hash_table_lookup (p->uid_to_sessions, uidptr); + + g_hash_table_remove (p->session_to_uid, ssid); + g_hash_table_remove (sessions, ssid); + g_debug ("%s %s not tracking ssid:%s uid:%u. uid has %u tracked ssids.", + G_STRLOC, G_STRFUNC, ssid, uid, + sessions ? g_hash_table_size (sessions) : 0); + + emit_user_changed_for_uid (self, uid); + } +} + +static void +on_session_proxy_uid_ready (GObject * o, + GAsyncResult * res, + gpointer gself) +{ + guint uid; + GError * err; + ConsoleKitSession * session = CONSOLE_KIT_SESSION (o); + + uid = 0; + err = NULL; + console_kit_session_call_get_unix_user_finish (session, &uid, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (uid) + { + const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(session)); + track_session (gself, path, uid); + } + + g_object_unref (o); +} + +static void +on_session_x11_display_ready (GObject * o, + GAsyncResult * res, + gpointer gself) +{ + priv_t * p; + GError * err; + gchar * gui; + ConsoleKitSession * session; + + p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + + err = NULL; + gui = NULL; + session = CONSOLE_KIT_SESSION (o); + console_kit_session_call_get_x11_display_finish (session, &gui, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + gboolean is_gui_session; + + is_gui_session = gui && *gui; + + if (!is_gui_session) + g_clear_object (&session); + else + console_kit_session_call_get_unix_user (session, + p->cancellable, + on_session_proxy_uid_ready, + gself); + + g_free (gui); + } +} + +static void +on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + ConsoleKitSession * session; + + err = NULL; + session = console_kit_session_proxy_new_finish (res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (session != NULL) + { + priv_t * p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + + console_kit_session_call_get_x11_display (session, + p->cancellable, + on_session_x11_display_ready, + gself); + } +} + +static void +create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, + const char * ssid) +{ + const char * name = "org.freedesktop.ConsoleKit"; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, ssid, + self->priv->cancellable, + on_session_proxy_ready, self); +} + +static void +on_session_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** sessions; + + err = NULL; + sessions = NULL; + console_kit_seat_call_get_sessions_finish (CONSOLE_KIT_SEAT(o), + &sessions, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; sessions && sessions[i]; i++) + create_session_proxy_for_ssid (gself, sessions[i]); + + g_strfreev (sessions); + } +} + +static inline guint +get_uid_for_session (IndicatorSessionUsersDbus * self, const char * ssid) +{ + guint uid = 0; + gpointer value; + + if (ssid != NULL) + if ((value = g_hash_table_lookup (self->priv->session_to_uid, ssid))) + uid = GPOINTER_TO_UINT (value); + + return uid; +} + +/* it's a live session if username is 'ubuntu' and uid is 999 */ +static gboolean +is_live_ssid (IndicatorSessionUsersDbus * self, const char * ssid) +{ + priv_t * p; + guint uid; + + p = INDICATOR_SESSION_USERS_DBUS (self)->priv; + uid = get_uid_for_session (self, ssid); + + if (uid == 999) + { + const char * path; + AccountsUser * user = NULL; + + if ((path = g_hash_table_lookup (p->uid_to_user_path, GUINT_TO_POINTER (uid)))) + user = g_hash_table_lookup (p->path_to_user, path); + + return (user != NULL) && !g_strcmp0 (accounts_user_get_user_name(user), "ubuntu"); + } + + return FALSE; +} + + +static void +set_active_session (IndicatorSessionUsersDbus * self, const char * ssid) +{ + priv_t * p = self->priv; + const guint old_uid = get_uid_for_session (self, p->active_session_id); + const guint new_uid = get_uid_for_session (self, ssid); + const gboolean old_live = is_live_ssid (self, p->active_session_id); + const gboolean new_live = is_live_ssid (self, ssid); + + g_debug ("%s %s changing active_session_id from '%s' to '%s'", + G_STRLOC, G_STRFUNC, p->active_session_id, ssid); + g_free (p->active_session_id); + p->active_session_id = g_strdup (ssid); + + if (old_uid != new_uid) + { + emit_user_changed_for_uid (self, old_uid); + emit_user_changed_for_uid (self, new_uid); + } + + if (old_live != new_live) + { + indicator_session_users_notify_is_live_session (INDICATOR_SESSION_USERS(self)); + } +} + +static void +on_seat_active_session_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar * ssid; + ConsoleKitSeat * seat; + + err = NULL; + ssid = NULL; + seat = CONSOLE_KIT_SEAT (o); + console_kit_seat_call_get_active_session_finish (seat, &ssid, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (ssid != NULL) + { + set_active_session (INDICATOR_SESSION_USERS_DBUS(gself), ssid); + g_free (ssid); + } +} + +static void +set_seat (IndicatorSessionUsersDbus * self, ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + if (p->seat_proxy != NULL) + { + g_signal_handlers_disconnect_by_data (p->seat_proxy, self); + g_clear_object (&p->seat_proxy); + } + + if (seat != NULL) + { + p->seat_proxy = g_object_ref (seat); + + /* ask the seat for a list of all the sessions */ + console_kit_seat_call_get_sessions (seat, + p->cancellable, + on_session_list_ready, + self); + + /* ask the seat for the name of the active session */ + console_kit_seat_call_get_active_session (p->seat_proxy, + p->cancellable, + on_seat_active_session_ready, + self); + + /* listen for session changes in this seat */ + g_signal_connect_swapped (seat, "session-added", + G_CALLBACK(create_session_proxy_for_ssid),self); + g_signal_connect_swapped (seat, "session-removed", + G_CALLBACK(untrack_session), self); + g_signal_connect_swapped (seat, "active-session-changed", + G_CALLBACK(set_active_session), self); + } +} + +/*** +**** +***/ + +static void +set_dm_seat (IndicatorSessionUsersDbus * self, DisplayManagerSeat * dm_seat) +{ + priv_t * p = self->priv; + + g_clear_object (&p->dm_seat); + + if (dm_seat != NULL) + p->dm_seat = g_object_ref (dm_seat); +} + +static void +activate_username (IndicatorSessionUsersDbus * self, const char * username) +{ + priv_t * p = self->priv; + const char * session = ""; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_user (p->dm_seat, username, session, + p->cancellable, NULL, NULL); +} + +/*** +**** +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); + priv_t * p = self->priv; + + if (p->cancellable) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + + set_seat (self, NULL); + set_dm_seat (self, NULL); + set_account_manager (self, NULL); + + g_clear_pointer (&p->path_to_user, g_hash_table_destroy); + g_clear_pointer (&p->session_to_uid, g_hash_table_destroy); + g_clear_pointer (&p->uid_to_sessions, g_hash_table_destroy); + g_clear_pointer (&p->uid_to_user_path, g_hash_table_destroy); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + IndicatorSessionUsersDbus * u = INDICATOR_SESSION_USERS_DBUS (o); + + g_free (u->priv->active_session_id); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->finalize (o); +} + +static void +my_activate_user (IndicatorSessionUsers * users, const char * key) +{ + priv_t * p; + const char * username = 0; + + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + if (p != 0) + { + AccountsUser * au = g_hash_table_lookup (p->path_to_user, key); + + if (au != NULL) + username = accounts_user_get_user_name (au); + } + + if (username != 0) + activate_username (INDICATOR_SESSION_USERS_DBUS(users), username); + else + g_warning ("%s %s can't find user for '%s'", G_STRLOC, G_STRFUNC, key); +} + +static gboolean +my_is_live_session (IndicatorSessionUsers * users) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS(users); + + return is_live_ssid (self, self->priv->active_session_id); +} + +static GStrv +my_get_keys (IndicatorSessionUsers * users) +{ + int i; + priv_t * p; + gchar ** keys; + GHashTableIter iter; + gpointer path; + gpointer user; + + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), NULL); + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + + i = 0; + keys = g_new (gchar*, g_hash_table_size(p->path_to_user)+1); + g_hash_table_iter_init (&iter, p->path_to_user); + while (g_hash_table_iter_next (&iter, &path, &user)) + if (!accounts_user_get_system_account (user)) + keys[i++] = g_strdup (path); + keys[i] = NULL; + + return keys; +} + +static IndicatorSessionUser * +my_get_user (IndicatorSessionUsers * users, const gchar * key) +{ + priv_t * p; + AccountsUser * au; + IndicatorSessionUser * ret = NULL; + + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + + au = g_hash_table_lookup (p->path_to_user, key); + if (au && !accounts_user_get_system_account(au)) + { + const guint uid = (guint) accounts_user_get_uid (au); + GHashTable * s; + + ret = g_new0 (IndicatorSessionUser, 1); + + s = g_hash_table_lookup (p->uid_to_sessions, GUINT_TO_POINTER(uid)); + if (s == NULL) + { + ret->is_logged_in = FALSE; + ret->is_current_user = FALSE; + } + else + { + ret->is_logged_in = g_hash_table_size (s) > 0; + ret->is_current_user = g_hash_table_contains (s, p->active_session_id); + } + + ret->uid = uid; + ret->user_name = g_strdup (accounts_user_get_user_name (au)); + ret->real_name = g_strdup (accounts_user_get_real_name (au)); + ret->icon_file = g_strdup (accounts_user_get_icon_file (au)); + ret->login_frequency = accounts_user_get_login_frequency (au); + } + + return ret; +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_dbus_class_init (IndicatorSessionUsersDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionUsersClass * users_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + users_class = INDICATOR_SESSION_USERS_CLASS (klass); + users_class->is_live_session = my_is_live_session; + users_class->get_keys = my_get_keys; + users_class->get_user = my_get_user; + users_class->activate_user = my_activate_user; + + g_type_class_add_private (klass, sizeof (IndicatorSessionUsersDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_USERS_DBUS, + IndicatorSessionUsersDbusPriv); + self->priv = p; + p->cancellable = g_cancellable_new (); + + p->path_to_user = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + + p->uid_to_user_path = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_free); + + p->session_to_uid = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + p->uid_to_sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify)g_hash_table_destroy); + +#if 0 + console_kit_manager_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + p->cancellable, + on_console_kit_manager_proxy_ready, + self); +#endif +} + +/*** +**** Public +***/ + +IndicatorSessionUsers * +indicator_session_users_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_USERS_DBUS, NULL); + + return INDICATOR_SESSION_USERS (o); +} + +void +indicator_session_users_dbus_set_proxies (IndicatorSessionUsersDbus * self, + Accounts * accounts, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * seat) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS_DBUS (self)); + + set_account_manager (self, accounts); + set_seat (self, seat); + set_dm_seat (self, dm_seat); +} -- cgit v1.2.3 From 6ff4e525b7f1a090450b3ff40cff082888250323 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 18 Apr 2013 11:33:20 -0500 Subject: remove #if 0 code --- src/backend-dbus/users.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 4798d33..34e0c97 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -229,21 +229,6 @@ set_account_manager (IndicatorSessionUsersDbus * self, Accounts * a) } } -#if 0 -static void -create_accounts_proxy (IndicatorSessionUsersDbus * self) -{ - const char * name = "org.freedesktop.Accounts"; - const char * path = "/org/freedesktop/Accounts"; - GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; - - accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - flags, name, path, - self->priv->cancellable, - on_accounts_proxy_ready, self); -} -#endif - /** * SEAT / SESSION TRACKING * @@ -771,17 +756,6 @@ indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) p->uid_to_sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_destroy); - -#if 0 - console_kit_manager_proxy_new_for_bus ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - p->cancellable, - on_console_kit_manager_proxy_ready, - self); -#endif } /*** -- cgit v1.2.3 From 093aed6a5e8c35bfe5a3e187fed3e293e2d12183 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 19 Jun 2013 18:16:56 -0500 Subject: in our async callbacks, don't call g_warning() if the task was cancelled by the client --- src/backend-dbus/users.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 34e0c97..6d9ada6 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -154,7 +154,9 @@ on_user_proxy_ready (GObject * o G_GNUC_UNUSED, user = accounts_user_proxy_new_for_bus_finish (res, &err); if (err != NULL) { - g_warning ("%s: %s", G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s: %s", G_STRFUNC, err->message); + g_error_free (err); } else @@ -187,7 +189,9 @@ on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) accounts_call_list_cached_users_finish (ACCOUNTS(o), &paths, res, &err); if (err != NULL) { - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); } else @@ -317,7 +321,9 @@ on_session_proxy_uid_ready (GObject * o, console_kit_session_call_get_unix_user_finish (session, &uid, res, &err); if (err != NULL) { - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); } else if (uid) @@ -347,7 +353,9 @@ on_session_x11_display_ready (GObject * o, console_kit_session_call_get_x11_display_finish (session, &gui, res, &err); if (err != NULL) { - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); } else @@ -378,7 +386,9 @@ on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer session = console_kit_session_proxy_new_finish (res, &err); if (err != NULL) { - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); } else if (session != NULL) @@ -417,7 +427,9 @@ on_session_list_ready (GObject * o, GAsyncResult * res, gpointer gself) &sessions, res, &err); if (err != NULL) { - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); } else @@ -508,7 +520,9 @@ on_seat_active_session_ready (GObject * o, GAsyncResult * res, gpointer gself) console_kit_seat_call_get_active_session_finish (seat, &ssid, res, &err); if (err != NULL) { - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); } else if (ssid != NULL) -- cgit v1.2.3 From df6db45c1bf1ca1e678e8f19974f48c4ead2b06e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 24 Jun 2013 10:20:23 -0500 Subject: in IndicatorSessionUsers, update to login1 --- src/backend-dbus/users.c | 813 +++++++++++++++++++++-------------------------- 1 file changed, 365 insertions(+), 448 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 6d9ada6..4466ede 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -17,35 +17,28 @@ * with this program. If not, see . */ -#include "dbus-accounts.h" -#include "dbus-consolekit-seat.h" -#include "dbus-consolekit-session.h" -#include "dbus-consolekit-manager.h" #include "dbus-user.h" #include "users.h" struct _IndicatorSessionUsersDbusPriv { - char * active_session_id; - - Accounts * accounts; - + Login1Manager * login1_manager; + Login1Seat * login1_seat; DisplayManagerSeat * dm_seat; + Accounts * accounts; - ConsoleKitSeat * seat_proxy; - - /* user's dbus object path -> AccountsUser* */ - GHashTable * path_to_user; + /* hash table of int uids to AccountsUser* */ + GHashTable * uid_to_account; - /* uint32 user-id --> user's dbus object path */ - GHashTable * uid_to_user_path; + /* a hashset of int uids of users who are logged in */ + GHashTable * logins; - /* uint32 user-id --> hashset of ssid strings */ - GHashTable * uid_to_sessions; + /* the user-id of the owner of the active session */ + guint active_uid; - /* ssid string --> uint32 user-id */ - GHashTable * session_to_uid; + /* true if this is a live session */ + gboolean is_live; GCancellable * cancellable; }; @@ -60,41 +53,176 @@ G_DEFINE_TYPE (IndicatorSessionUsersDbus, **** ***/ -static void create_user_proxy_for_path (IndicatorSessionUsersDbus * self, - const char * path); +static const gchar * +get_public_key_for_uid (guint uid) +{ + static char buf[16]; + g_snprintf (buf, sizeof(buf), "%u", uid); + return buf; +} + +static void +emit_user_added (IndicatorSessionUsersDbus * self, guint uid) +{ + const gchar * const public_key = get_public_key_for_uid (uid); + indicator_session_users_added (INDICATOR_SESSION_USERS(self), public_key); +} + +static void +emit_user_changed (IndicatorSessionUsersDbus * self, guint uid) +{ + const gchar * const public_key = get_public_key_for_uid (uid); + indicator_session_users_changed (INDICATOR_SESSION_USERS(self), public_key); +} + +static void +emit_user_removed (IndicatorSessionUsersDbus * self, guint uid) +{ + const gchar * const public_key = get_public_key_for_uid (uid); + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), public_key); +} -static void create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, - const char * ssid); +/*** +**** +***/ static void -emit_user_changed_for_path (IndicatorSessionUsersDbus * self, const char * path) +set_is_live_session_flag (IndicatorSessionUsersDbus * self, gboolean b) { - AccountsUser * user = g_hash_table_lookup (self->priv->path_to_user, path); + priv_t * p = self->priv; + + if (p->is_live != b) + { + p->is_live = b; - if (user && !accounts_user_get_system_account (user)) - indicator_session_users_changed (INDICATOR_SESSION_USERS(self), path); + indicator_session_users_notify_is_live_session (INDICATOR_SESSION_USERS (self)); + } } static void -emit_user_changed_for_uid (IndicatorSessionUsersDbus * self, guint uid) +set_active_uid (IndicatorSessionUsersDbus * self, guint uid) { - const char * path; + priv_t * p = self->priv; + + g_message ("%s %s setting active uid to %u", G_STRLOC, G_STRFUNC, uid); + + if (p->active_uid != uid) + { + const guint old_uid = p->active_uid; - if ((path = g_hash_table_lookup (self->priv->uid_to_user_path, GUINT_TO_POINTER(uid)))) - emit_user_changed_for_path (self, path); + p->active_uid = uid; + + if (old_uid) + emit_user_changed (self, old_uid); + + if (uid) + emit_user_changed (self, uid); + } +} + +static void +set_logins (IndicatorSessionUsersDbus * self, GHashTable * logins) +{ + GHashTable * old_logins = self->priv->logins; + gpointer key; + GHashTableIter iter; + + self->priv->logins = logins; + + /* fire 'user changed' event for users who logged out */ + g_hash_table_iter_init (&iter, old_logins); + while ((g_hash_table_iter_next (&iter, &key, NULL))) + if (!g_hash_table_contains (logins, key)) + emit_user_changed (self, GPOINTER_TO_INT(key)); + + /* fire 'user changed' event for users who logged in */ + g_hash_table_iter_init (&iter, logins); + while ((g_hash_table_iter_next (&iter, &key, NULL))) + if (!g_hash_table_contains (old_logins, key)) + emit_user_changed (self, GPOINTER_TO_INT(key)); + + g_hash_table_destroy (old_logins); } /*** -**** ACCOUNT MANAGER / USER TRACKING +**** ***/ +static GQuark +get_connection_list_quark (void) +{ + static GQuark q = 0; + + if (G_UNLIKELY (q == 0)) + q = g_quark_from_static_string ("connection-ids"); + + return q; +} + +static void +object_unref_and_disconnect (gpointer instance) +{ + GSList * l; + GSList * ids; + const GQuark q = get_connection_list_quark (); + + ids = g_object_steal_qdata (G_OBJECT(instance), q); + for (l=ids; l!=NULL; l=l->next) + { + gulong * handler_id = l->data; + g_signal_handler_disconnect (instance, *handler_id); + g_free (handler_id); + } + + g_slist_free (ids); +} + +static void +object_add_connection (GObject * o, gulong connection_id) +{ + const GQuark q = get_connection_list_quark (); + GSList * ids; + gulong * ptr; + + ptr = g_new (gulong, 1); + *ptr = connection_id; + + ids = g_object_steal_qdata (o, q); + ids = g_slist_prepend (ids, ptr); + g_object_set_qdata (o, q, ids); +} + +/*** +**** +***/ + +static AccountsUser * +get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) +{ + priv_t * p = self->priv; + + return g_hash_table_lookup (p->uid_to_account, GUINT_TO_POINTER(uid)); +} + +static AccountsUser * +get_user_for_public_key (IndicatorSessionUsersDbus * self, const char * public_key) +{ + return get_user_for_uid (self, g_ascii_strtoull (public_key, NULL, 10)); +} + +/*** +**** User Account Tracking +***/ + +static void create_user_proxy_for_path (IndicatorSessionUsersDbus *, const char *); + /* called when a user proxy gets the 'Changed' signal */ static void on_user_changed (AccountsUser * user, gpointer gself) { /* Accounts.User doesn't update properties in the standard way, * so create a new proxy to pull in the new properties. - * The older proxy is freed when it's removed from our path_to_user hash */ + * The older proxy is freed when it's replaced in our accounts hash */ const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); create_user_proxy_for_path (gself, path); } @@ -103,32 +231,24 @@ static void track_user (IndicatorSessionUsersDbus * self, AccountsUser * user) { - priv_t * p; - const char * path; + priv_t * p = self->priv; + const guint32 uid = accounts_user_get_uid (user); + const gpointer uid_key = GUINT_TO_POINTER (uid); gboolean already_had_user; + gulong id; - p = self->priv; - - path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); - already_had_user = g_hash_table_contains (p->path_to_user, path); + already_had_user = g_hash_table_contains (p->uid_to_account, uid_key); - g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); - g_hash_table_insert (p->path_to_user, g_strdup(path), user); + id = g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); + object_add_connection (G_OBJECT(user), id); + g_hash_table_insert (p->uid_to_account, uid_key, user); - if (already_had_user) - { - emit_user_changed_for_path (self, path); - } - else + if (!accounts_user_get_system_account (user)) { - const guint uid = (guint) accounts_user_get_uid (user); - - g_hash_table_insert (p->uid_to_user_path, - GUINT_TO_POINTER(uid), - g_strdup(path)); - - if (!accounts_user_get_system_account (user)) - indicator_session_users_added (INDICATOR_SESSION_USERS(self), path); + if (already_had_user) + emit_user_changed (self, uid); + else + emit_user_added (self, uid); } } @@ -136,14 +256,28 @@ static void untrack_user (IndicatorSessionUsersDbus * self, const gchar * path) { - g_hash_table_remove (self->priv->path_to_user, path); + guint uid; + gpointer key; + gpointer val; + GHashTableIter iter; + priv_t * p = self->priv; - indicator_session_users_removed (INDICATOR_SESSION_USERS(self), path); -} + uid = 0; + g_hash_table_iter_init (&iter, p->uid_to_account); + while (!uid && g_hash_table_iter_next (&iter, &key, &val)) + if (!g_strcmp0 (path, g_dbus_proxy_get_object_path (val))) + uid = GPOINTER_TO_UINT (key); + + if (uid) + { + g_hash_table_remove (p->uid_to_account, GUINT_TO_POINTER(uid)); + emit_user_removed (self, uid); + } +} static void -on_user_proxy_ready (GObject * o G_GNUC_UNUSED, +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer self) { @@ -169,15 +303,15 @@ static void create_user_proxy_for_path (IndicatorSessionUsersDbus * self, const char * path) { - const char * name = "org.freedesktop.Accounts"; - const GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; - accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - flags, name, path, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.Accounts", + path, self->priv->cancellable, on_user_proxy_ready, self); } +/* create user proxies for everything in Account's user-list */ static void on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) { @@ -233,348 +367,143 @@ set_account_manager (IndicatorSessionUsersDbus * self, Accounts * a) } } -/** - * SEAT / SESSION TRACKING - * - * There are two simple goals here: - * - * 1. Keep track of how many GUI sessions each user has - * so that we can set the 'is_logged_in' flag correctly - * - * 2. Also track which is the current session, - * so that we can compare it to those GUI sessions to - * set the 'is_current_session' flag correctly. - * - * Now that you know the goals, these steps may make more sense: - * - * 1. create a ConsoleKitManager proxy - * 2. ask it for the current session - * 3. create a corresponding Session proxy - * 4. ask that Session proxy for its seat - * 5. create a corresponding Seat proxy - * 6. connect to that seat's session-added / session-removed signals - * 7. ask the seat for a list of its current sessions - * 8. create corresponding Session proxies - * 9. of them, look for the GUI sessions by checking their X11 properties - * 10. for each GUI session, get the corresponding uid - * 11. use the information to update our uid <--> GUI sessions tables - */ - -static void -track_session (IndicatorSessionUsersDbus * self, - const char * ssid, - guint uid) -{ - gpointer uid_key; - GHashTable * sessions; - - uid_key = GUINT_TO_POINTER (uid); - sessions = g_hash_table_lookup (self->priv->uid_to_sessions, uid_key); - if (sessions == NULL) - { - sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_hash_table_insert (self->priv->uid_to_sessions, uid_key, sessions); - } - - g_hash_table_add (sessions, g_strdup (ssid)); - g_hash_table_insert (self->priv->session_to_uid, g_strdup(ssid), uid_key); - - g_debug ("%s %s now tracking ssid:%s uid:%u. uid has %u tracked ssids.", - G_STRLOC, G_STRFUNC, ssid, uid, g_hash_table_size (sessions)); - - emit_user_changed_for_uid (self, uid); -} - -static void -untrack_session (IndicatorSessionUsersDbus * self, - const char * ssid) -{ - gpointer uidptr; - priv_t * p = self->priv; - - if (g_hash_table_lookup_extended (p->session_to_uid, ssid, NULL, &uidptr)) - { - const guint uid = GPOINTER_TO_UINT (uidptr); - GHashTable * sessions = g_hash_table_lookup (p->uid_to_sessions, uidptr); - - g_hash_table_remove (p->session_to_uid, ssid); - g_hash_table_remove (sessions, ssid); - g_debug ("%s %s not tracking ssid:%s uid:%u. uid has %u tracked ssids.", - G_STRLOC, G_STRFUNC, ssid, uid, - sessions ? g_hash_table_size (sessions) : 0); - - emit_user_changed_for_uid (self, uid); - } -} +/*** +**** +***/ +/* Based on the login1 manager's list of current sessions, + update our 'logins', 'is_live', and 'active_uid' fields */ static void -on_session_proxy_uid_ready (GObject * o, - GAsyncResult * res, - gpointer gself) +on_login1_manager_session_list_ready (GObject * o, + GAsyncResult * res, + gpointer gself) { - guint uid; + GVariant * sessions; GError * err; - ConsoleKitSession * session = CONSOLE_KIT_SESSION (o); - uid = 0; + sessions = NULL; err = NULL; - console_kit_session_call_get_unix_user_finish (session, &uid, res, &err); - if (err != NULL) - { - if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); - - g_error_free (err); - } - else if (uid) - { - const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(session)); - track_session (gself, path, uid); - } + login1_manager_call_list_sessions_finish (LOGIN1_MANAGER(o), + &sessions, + res, + &err); - g_object_unref (o); -} - -static void -on_session_x11_display_ready (GObject * o, - GAsyncResult * res, - gpointer gself) -{ - priv_t * p; - GError * err; - gchar * gui; - ConsoleKitSession * session; - - p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; - - err = NULL; - gui = NULL; - session = CONSOLE_KIT_SESSION (o); - console_kit_session_call_get_x11_display_finish (session, &gui, res, &err); if (err != NULL) { if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_warning ("%s: %s", G_STRFUNC, err->message); g_error_free (err); } else { - gboolean is_gui_session; - - is_gui_session = gui && *gui; - - if (!is_gui_session) - g_clear_object (&session); - else - console_kit_session_call_get_unix_user (session, - p->cancellable, - on_session_proxy_uid_ready, - gself); + const gchar * const current_seat_id = g_getenv ("XDG_SEAT"); + const gchar * const current_session_id = g_getenv ("XDG_SESSION_ID"); + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (gself); + const gchar * session_id = NULL; + guint32 uid = 0; + const gchar * user_name = NULL; + const gchar * seat_id = NULL; + const gchar * path = NULL; + gboolean is_live_session = FALSE; + GHashTable * logins = g_hash_table_new (g_direct_hash, g_direct_equal); + GVariantIter iter; + + g_message ("%s %s %s", G_STRLOC, G_STRFUNC, g_variant_print (sessions, TRUE)); + + g_variant_iter_init (&iter, sessions); + while (g_variant_iter_loop (&iter, "(&su&s&s&o)", &session_id, + &uid, + &user_name, + &seat_id, + &path)) + { + /* only track sessions on our seat */ + if (g_strcmp0 (seat_id, current_seat_id)) + continue; - g_free (gui); - } -} + if ((uid==999) && !g_strcmp0 (user_name,"ubuntu")) + is_live_session = TRUE; -static void -on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) -{ - GError * err; - ConsoleKitSession * session; + if (!g_strcmp0 (session_id, current_session_id)) + set_active_uid (self, uid); - err = NULL; - session = console_kit_session_proxy_new_finish (res, &err); - if (err != NULL) - { - if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + /* only count user accounts and the live session */ + if (uid >= 999) + g_hash_table_add (logins, GINT_TO_POINTER(uid)); + } - g_error_free (err); - } - else if (session != NULL) - { - priv_t * p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + set_is_live_session_flag (self, is_live_session); + set_logins (self, logins); - console_kit_session_call_get_x11_display (session, - p->cancellable, - on_session_x11_display_ready, - gself); + g_variant_unref (sessions); } } static void -create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, - const char * ssid) -{ - const char * name = "org.freedesktop.ConsoleKit"; - GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; - - console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - flags, name, ssid, - self->priv->cancellable, - on_session_proxy_ready, self); -} - -static void -on_session_list_ready (GObject * o, GAsyncResult * res, gpointer gself) -{ - GError * err; - gchar ** sessions; - - err = NULL; - sessions = NULL; - console_kit_seat_call_get_sessions_finish (CONSOLE_KIT_SEAT(o), - &sessions, res, &err); - if (err != NULL) - { - if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); - - g_error_free (err); - } - else - { - int i; - - for (i=0; sessions && sessions[i]; i++) - create_session_proxy_for_ssid (gself, sessions[i]); - - g_strfreev (sessions); - } -} - -static inline guint -get_uid_for_session (IndicatorSessionUsersDbus * self, const char * ssid) +update_session_list (IndicatorSessionUsersDbus * self) { - guint uid = 0; - gpointer value; - - if (ssid != NULL) - if ((value = g_hash_table_lookup (self->priv->session_to_uid, ssid))) - uid = GPOINTER_TO_UINT (value); - - return uid; -} - -/* it's a live session if username is 'ubuntu' and uid is 999 */ -static gboolean -is_live_ssid (IndicatorSessionUsersDbus * self, const char * ssid) -{ - priv_t * p; - guint uid; - - p = INDICATOR_SESSION_USERS_DBUS (self)->priv; - uid = get_uid_for_session (self, ssid); + priv_t * p = self->priv; - if (uid == 999) + if (p->login1_manager != NULL) { - const char * path; - AccountsUser * user = NULL; - - if ((path = g_hash_table_lookup (p->uid_to_user_path, GUINT_TO_POINTER (uid)))) - user = g_hash_table_lookup (p->path_to_user, path); - - return (user != NULL) && !g_strcmp0 (accounts_user_get_user_name(user), "ubuntu"); + login1_manager_call_list_sessions (p->login1_manager, + p->cancellable, + on_login1_manager_session_list_ready, + self); } - - return FALSE; } - static void -set_active_session (IndicatorSessionUsersDbus * self, const char * ssid) +set_login1_manager (IndicatorSessionUsersDbus * self, Login1Manager * login1_manager) { priv_t * p = self->priv; - const guint old_uid = get_uid_for_session (self, p->active_session_id); - const guint new_uid = get_uid_for_session (self, ssid); - const gboolean old_live = is_live_ssid (self, p->active_session_id); - const gboolean new_live = is_live_ssid (self, ssid); - - g_debug ("%s %s changing active_session_id from '%s' to '%s'", - G_STRLOC, G_STRFUNC, p->active_session_id, ssid); - g_free (p->active_session_id); - p->active_session_id = g_strdup (ssid); - if (old_uid != new_uid) + if (p->login1_manager != NULL) { - emit_user_changed_for_uid (self, old_uid); - emit_user_changed_for_uid (self, new_uid); - } + g_signal_handlers_disconnect_by_data (p->login1_manager, self); - if (old_live != new_live) - { - indicator_session_users_notify_is_live_session (INDICATOR_SESSION_USERS(self)); + g_clear_object (&p->login1_manager); } -} -static void -on_seat_active_session_ready (GObject * o, GAsyncResult * res, gpointer gself) -{ - GError * err; - gchar * ssid; - ConsoleKitSeat * seat; - - err = NULL; - ssid = NULL; - seat = CONSOLE_KIT_SEAT (o); - console_kit_seat_call_get_active_session_finish (seat, &ssid, res, &err); - if (err != NULL) + if (login1_manager != NULL) { - if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + p->login1_manager = g_object_ref (login1_manager); - g_error_free (err); - } - else if (ssid != NULL) - { - set_active_session (INDICATOR_SESSION_USERS_DBUS(gself), ssid); - g_free (ssid); + g_signal_connect_swapped (login1_manager, "session-new", + G_CALLBACK(update_session_list), self); + g_signal_connect_swapped (login1_manager, "session-removed", + G_CALLBACK(update_session_list), self); + update_session_list (self); } } static void -set_seat (IndicatorSessionUsersDbus * self, ConsoleKitSeat * seat) +set_login1_seat (IndicatorSessionUsersDbus * self, + Login1Seat * login1_seat) { priv_t * p = self->priv; - if (p->seat_proxy != NULL) + if (p->login1_seat != NULL) { - g_signal_handlers_disconnect_by_data (p->seat_proxy, self); - g_clear_object (&p->seat_proxy); + g_signal_handlers_disconnect_by_data (p->login1_seat, self); + + g_clear_object (&p->login1_seat); } - if (seat != NULL) + if (login1_seat != NULL) { - p->seat_proxy = g_object_ref (seat); - - /* ask the seat for a list of all the sessions */ - console_kit_seat_call_get_sessions (seat, - p->cancellable, - on_session_list_ready, - self); + p->login1_seat = g_object_ref (login1_seat); - /* ask the seat for the name of the active session */ - console_kit_seat_call_get_active_session (p->seat_proxy, - p->cancellable, - on_seat_active_session_ready, - self); - - /* listen for session changes in this seat */ - g_signal_connect_swapped (seat, "session-added", - G_CALLBACK(create_session_proxy_for_ssid),self); - g_signal_connect_swapped (seat, "session-removed", - G_CALLBACK(untrack_session), self); - g_signal_connect_swapped (seat, "active-session-changed", - G_CALLBACK(set_active_session), self); + g_signal_connect_swapped (login1_seat, "notify::active-session", + G_CALLBACK(update_session_list), self); + update_session_list (self); } } -/*** -**** -***/ - static void -set_dm_seat (IndicatorSessionUsersDbus * self, DisplayManagerSeat * dm_seat) +set_display_manager_seat (IndicatorSessionUsersDbus * self, + DisplayManagerSeat * dm_seat) { priv_t * p = self->priv; @@ -584,85 +513,49 @@ set_dm_seat (IndicatorSessionUsersDbus * self, DisplayManagerSeat * dm_seat) p->dm_seat = g_object_ref (dm_seat); } -static void -activate_username (IndicatorSessionUsersDbus * self, const char * username) -{ - priv_t * p = self->priv; - const char * session = ""; - - g_return_if_fail (p->dm_seat != NULL); - - display_manager_seat_call_switch_to_user (p->dm_seat, username, session, - p->cancellable, NULL, NULL); -} - /*** -**** +**** IndicatorSessionUsers virtual functions ***/ +/* switch to (or create) a session for the specified user */ static void -my_dispose (GObject * o) +my_activate_user (IndicatorSessionUsers * users, const char * public_key) { - IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS(users); priv_t * p = self->priv; + AccountsUser * au; + const char * username; - if (p->cancellable) + au = get_user_for_public_key (self, public_key); + username = au ? accounts_user_get_user_name (au) : NULL; + + if (!username) { - g_cancellable_cancel (p->cancellable); - g_clear_object (&p->cancellable); + g_warning ("%s %s can't find user for '%s'", G_STRLOC, G_STRFUNC, public_key); } - - set_seat (self, NULL); - set_dm_seat (self, NULL); - set_account_manager (self, NULL); - - g_clear_pointer (&p->path_to_user, g_hash_table_destroy); - g_clear_pointer (&p->session_to_uid, g_hash_table_destroy); - g_clear_pointer (&p->uid_to_sessions, g_hash_table_destroy); - g_clear_pointer (&p->uid_to_user_path, g_hash_table_destroy); - - G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->dispose (o); -} - -static void -my_finalize (GObject * o) -{ - IndicatorSessionUsersDbus * u = INDICATOR_SESSION_USERS_DBUS (o); - - g_free (u->priv->active_session_id); - - G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->finalize (o); -} - -static void -my_activate_user (IndicatorSessionUsers * users, const char * key) -{ - priv_t * p; - const char * username = 0; - - p = INDICATOR_SESSION_USERS_DBUS (users)->priv; - if (p != 0) + else { - AccountsUser * au = g_hash_table_lookup (p->path_to_user, key); + g_return_if_fail (p->dm_seat != NULL); - if (au != NULL) - username = accounts_user_get_user_name (au); + display_manager_seat_call_switch_to_user (p->dm_seat, + username, + "", + p->cancellable, + NULL, + NULL); } - - if (username != 0) - activate_username (INDICATOR_SESSION_USERS_DBUS(users), username); - else - g_warning ("%s %s can't find user for '%s'", G_STRLOC, G_STRFUNC, key); } +/* returns true if this is a live session */ static gboolean my_is_live_session (IndicatorSessionUsers * users) { - IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS(users); + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), FALSE); - return is_live_ssid (self, self->priv->active_session_id); + return INDICATOR_SESSION_USERS_DBUS(users)->priv->is_live; } +/* get a list of public keys for the users that we know about */ static GStrv my_get_keys (IndicatorSessionUsers * users) { @@ -670,64 +563,93 @@ my_get_keys (IndicatorSessionUsers * users) priv_t * p; gchar ** keys; GHashTableIter iter; - gpointer path; + gpointer uid; gpointer user; + GHashTable * h; g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), NULL); p = INDICATOR_SESSION_USERS_DBUS (users)->priv; i = 0; - keys = g_new (gchar*, g_hash_table_size(p->path_to_user)+1); - g_hash_table_iter_init (&iter, p->path_to_user); - while (g_hash_table_iter_next (&iter, &path, &user)) + h = p->uid_to_account; + keys = g_new (gchar*, g_hash_table_size(h)+1); + g_hash_table_iter_init (&iter, h); + while (g_hash_table_iter_next (&iter, &uid, &user)) if (!accounts_user_get_system_account (user)) - keys[i++] = g_strdup (path); + keys[i++] = g_strdup (get_public_key_for_uid ((guint)uid)); keys[i] = NULL; return keys; } +/* build a new struct populated with info on the specified user */ static IndicatorSessionUser * -my_get_user (IndicatorSessionUsers * users, const gchar * key) +my_get_user (IndicatorSessionUsers * users, const gchar * public_key) { - priv_t * p; + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (users); + priv_t * p = self->priv; + IndicatorSessionUser * ret; AccountsUser * au; - IndicatorSessionUser * ret = NULL; - p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + ret = NULL; + au = get_user_for_public_key (self, public_key); - au = g_hash_table_lookup (p->path_to_user, key); if (au && !accounts_user_get_system_account(au)) { - const guint uid = (guint) accounts_user_get_uid (au); - GHashTable * s; + const guint uid = accounts_user_get_uid (au); ret = g_new0 (IndicatorSessionUser, 1); - - s = g_hash_table_lookup (p->uid_to_sessions, GUINT_TO_POINTER(uid)); - if (s == NULL) - { - ret->is_logged_in = FALSE; - ret->is_current_user = FALSE; - } - else - { - ret->is_logged_in = g_hash_table_size (s) > 0; - ret->is_current_user = g_hash_table_contains (s, p->active_session_id); - } - ret->uid = uid; ret->user_name = g_strdup (accounts_user_get_user_name (au)); ret->real_name = g_strdup (accounts_user_get_real_name (au)); ret->icon_file = g_strdup (accounts_user_get_icon_file (au)); ret->login_frequency = accounts_user_get_login_frequency (au); + ret->is_logged_in = g_hash_table_contains (p->logins, GINT_TO_POINTER(uid)); + ret->is_current_user = uid == p->active_uid; } return ret; } +/*** +**** GObject virtual functions +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); + priv_t * p = self->priv; + + if (p->cancellable) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + + set_account_manager (self, NULL); + set_display_manager_seat (self, NULL); + set_login1_seat (self, NULL); + set_login1_manager (self, NULL); + + g_hash_table_remove_all (p->uid_to_account); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); + priv_t * p = self->priv; + + g_hash_table_destroy (p->logins); + g_hash_table_destroy (p->uid_to_account); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->finalize (o); +} + static void -/* cppcheck-suppress unusedFunction */ indicator_session_users_dbus_class_init (IndicatorSessionUsersDbusClass * klass) { GObjectClass * object_class; @@ -747,7 +669,6 @@ indicator_session_users_dbus_class_init (IndicatorSessionUsersDbusClass * klass) } static void -/* cppcheck-suppress unusedFunction */ indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) { priv_t * p; @@ -758,18 +679,12 @@ indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) self->priv = p; p->cancellable = g_cancellable_new (); - p->path_to_user = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - p->uid_to_user_path = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, g_free); - - p->session_to_uid = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); + p->uid_to_account = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + object_unref_and_disconnect); - p->uid_to_sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, - (GDestroyNotify)g_hash_table_destroy); + p->logins = g_hash_table_new (g_direct_hash, g_direct_equal); } /*** @@ -786,13 +701,15 @@ indicator_session_users_dbus_new (void) void indicator_session_users_dbus_set_proxies (IndicatorSessionUsersDbus * self, - Accounts * accounts, + Login1Manager * login1_manager, + Login1Seat * login1_seat, DisplayManagerSeat * dm_seat, - ConsoleKitSeat * seat) + Accounts * accounts) { g_return_if_fail (INDICATOR_IS_SESSION_USERS_DBUS (self)); + set_login1_manager (self, login1_manager); + set_login1_seat (self, login1_seat); + set_display_manager_seat (self, dm_seat); set_account_manager (self, accounts); - set_seat (self, seat); - set_dm_seat (self, dm_seat); } -- cgit v1.2.3 From 0ca4b9a4e6b552b9a59bade1d8d44cc950ded994 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 24 Jun 2013 23:08:12 -0500 Subject: in backend-dbus/users.c, fix a user proxy leak --- src/backend-dbus/users.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 4466ede..c135610 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -172,6 +172,7 @@ object_unref_and_disconnect (gpointer instance) gulong * handler_id = l->data; g_signal_handler_disconnect (instance, *handler_id); g_free (handler_id); + g_object_unref (instance); } g_slist_free (ids); -- cgit v1.2.3 From b3938a1f14b687d62ad1d6e4e27bac47f58722de Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 25 Jun 2013 11:16:34 -0500 Subject: in IndicatorSessionUsers, use the uid as the user's key. Users.ActivateUser is now green. --- src/backend-dbus/users.c | 73 +++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 48 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index c135610..48de06c 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -53,33 +53,22 @@ G_DEFINE_TYPE (IndicatorSessionUsersDbus, **** ***/ -static const gchar * -get_public_key_for_uid (guint uid) -{ - static char buf[16]; - g_snprintf (buf, sizeof(buf), "%u", uid); - return buf; -} - static void emit_user_added (IndicatorSessionUsersDbus * self, guint uid) { - const gchar * const public_key = get_public_key_for_uid (uid); - indicator_session_users_added (INDICATOR_SESSION_USERS(self), public_key); + indicator_session_users_added (INDICATOR_SESSION_USERS(self), uid); } static void emit_user_changed (IndicatorSessionUsersDbus * self, guint uid) { - const gchar * const public_key = get_public_key_for_uid (uid); - indicator_session_users_changed (INDICATOR_SESSION_USERS(self), public_key); + indicator_session_users_changed (INDICATOR_SESSION_USERS(self), uid); } static void emit_user_removed (IndicatorSessionUsersDbus * self, guint uid) { - const gchar * const public_key = get_public_key_for_uid (uid); - indicator_session_users_removed (INDICATOR_SESSION_USERS(self), public_key); + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), uid); } /*** @@ -124,22 +113,22 @@ static void set_logins (IndicatorSessionUsersDbus * self, GHashTable * logins) { GHashTable * old_logins = self->priv->logins; - gpointer key; + gpointer uid; GHashTableIter iter; self->priv->logins = logins; /* fire 'user changed' event for users who logged out */ g_hash_table_iter_init (&iter, old_logins); - while ((g_hash_table_iter_next (&iter, &key, NULL))) - if (!g_hash_table_contains (logins, key)) - emit_user_changed (self, GPOINTER_TO_INT(key)); + while ((g_hash_table_iter_next (&iter, &uid, NULL))) + if (!g_hash_table_contains (logins, uid)) + emit_user_changed (self, GPOINTER_TO_UINT(uid)); /* fire 'user changed' event for users who logged in */ g_hash_table_iter_init (&iter, logins); - while ((g_hash_table_iter_next (&iter, &key, NULL))) - if (!g_hash_table_contains (old_logins, key)) - emit_user_changed (self, GPOINTER_TO_INT(key)); + while ((g_hash_table_iter_next (&iter, &uid, NULL))) + if (!g_hash_table_contains (old_logins, uid)) + emit_user_changed (self, GPOINTER_TO_UINT(uid)); g_hash_table_destroy (old_logins); } @@ -205,12 +194,6 @@ get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) return g_hash_table_lookup (p->uid_to_account, GUINT_TO_POINTER(uid)); } -static AccountsUser * -get_user_for_public_key (IndicatorSessionUsersDbus * self, const char * public_key) -{ - return get_user_for_uid (self, g_ascii_strtoull (public_key, NULL, 10)); -} - /*** **** User Account Tracking ***/ @@ -520,19 +503,19 @@ set_display_manager_seat (IndicatorSessionUsersDbus * self, /* switch to (or create) a session for the specified user */ static void -my_activate_user (IndicatorSessionUsers * users, const char * public_key) +my_activate_user (IndicatorSessionUsers * users, guint uid) { IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS(users); priv_t * p = self->priv; AccountsUser * au; const char * username; - au = get_user_for_public_key (self, public_key); + au = get_user_for_uid (self, uid); username = au ? accounts_user_get_user_name (au) : NULL; if (!username) { - g_warning ("%s %s can't find user for '%s'", G_STRLOC, G_STRFUNC, public_key); + g_warning ("%s %s can't find user '%u'", G_STRLOC, G_STRFUNC, uid); } else { @@ -556,36 +539,31 @@ my_is_live_session (IndicatorSessionUsers * users) return INDICATOR_SESSION_USERS_DBUS(users)->priv->is_live; } -/* get a list of public keys for the users that we know about */ -static GStrv -my_get_keys (IndicatorSessionUsers * users) +/* get a list of our user ids */ +static GList * +my_get_uids (IndicatorSessionUsers * users) { - int i; priv_t * p; - gchar ** keys; + GList * uids; GHashTableIter iter; gpointer uid; gpointer user; - GHashTable * h; g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), NULL); p = INDICATOR_SESSION_USERS_DBUS (users)->priv; - i = 0; - h = p->uid_to_account; - keys = g_new (gchar*, g_hash_table_size(h)+1); - g_hash_table_iter_init (&iter, h); + uids = NULL; + g_hash_table_iter_init (&iter, p->uid_to_account); while (g_hash_table_iter_next (&iter, &uid, &user)) if (!accounts_user_get_system_account (user)) - keys[i++] = g_strdup (get_public_key_for_uid ((guint)uid)); - keys[i] = NULL; + uids = g_list_prepend (uids, uid); - return keys; + return uids; } /* build a new struct populated with info on the specified user */ static IndicatorSessionUser * -my_get_user (IndicatorSessionUsers * users, const gchar * public_key) +my_get_user (IndicatorSessionUsers * users, guint uid) { IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (users); priv_t * p = self->priv; @@ -593,11 +571,10 @@ my_get_user (IndicatorSessionUsers * users, const gchar * public_key) AccountsUser * au; ret = NULL; - au = get_user_for_public_key (self, public_key); - + au = get_user_for_uid (self, uid); if (au && !accounts_user_get_system_account(au)) { - const guint uid = accounts_user_get_uid (au); + g_assert (uid == accounts_user_get_uid (au)); ret = g_new0 (IndicatorSessionUser, 1); ret->uid = uid; @@ -662,7 +639,7 @@ indicator_session_users_dbus_class_init (IndicatorSessionUsersDbusClass * klass) users_class = INDICATOR_SESSION_USERS_CLASS (klass); users_class->is_live_session = my_is_live_session; - users_class->get_keys = my_get_keys; + users_class->get_uids = my_get_uids; users_class->get_user = my_get_user; users_class->activate_user = my_activate_user; -- cgit v1.2.3 From d16aaaed46f3381ea7ac4cb4c2cb491d4c5d2e03 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 25 Jun 2013 11:39:46 -0500 Subject: all the tests in test-users pass --- src/backend-dbus/users.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 48de06c..1ecadf3 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -93,8 +93,6 @@ set_active_uid (IndicatorSessionUsersDbus * self, guint uid) { priv_t * p = self->priv; - g_message ("%s %s setting active uid to %u", G_STRLOC, G_STRFUNC, uid); - if (p->active_uid != uid) { const guint old_uid = p->active_uid; @@ -393,8 +391,6 @@ on_login1_manager_session_list_ready (GObject * o, GHashTable * logins = g_hash_table_new (g_direct_hash, g_direct_equal); GVariantIter iter; - g_message ("%s %s %s", G_STRLOC, G_STRFUNC, g_variant_print (sessions, TRUE)); - g_variant_iter_init (&iter, sessions); while (g_variant_iter_loop (&iter, "(&su&s&s&o)", &session_id, &uid, @@ -406,11 +402,13 @@ on_login1_manager_session_list_ready (GObject * o, if (g_strcmp0 (seat_id, current_seat_id)) continue; - if ((uid==999) && !g_strcmp0 (user_name,"ubuntu")) - is_live_session = TRUE; - if (!g_strcmp0 (session_id, current_session_id)) - set_active_uid (self, uid); + { + set_active_uid (self, uid); + + if ((uid==999) && !g_strcmp0 (user_name,"ubuntu")) + is_live_session = TRUE; + } /* only count user accounts and the live session */ if (uid >= 999) -- cgit v1.2.3 From 4c5a5e7146a878a17239e44ce2debffb5b525bf1 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 27 Jun 2013 13:53:44 -0500 Subject: in users.c, fix bugs that leaked system accounts into the list of users to show in the indicator --- src/backend-dbus/users.c | 137 +++++++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 51 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 1ecadf3..1db5ac1 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -53,22 +53,82 @@ G_DEFINE_TYPE (IndicatorSessionUsersDbus, **** ***/ +/* returns true if the fields indicate this is the 'live cd' user */ +static gboolean +is_live_user (guint uid, const char * username) +{ + return uid==999 && !g_strcmp0 (username, "ubuntu"); +} + +/* returns true if this is a user who should be listed in the session indicator */ +static gboolean +is_public_user (IndicatorSessionUsersDbus * self G_GNUC_UNUSED, + AccountsUser * au) +{ + gboolean is_public; + + /* the 'live session' user is the only system account we'll show */ + if (is_live_user (accounts_user_get_uid(au), accounts_user_get_user_name(au))) + is_public = TRUE; + else + is_public = !accounts_user_get_system_account (au); + + return is_public; +} + +/* get our private org.freedesktop.Accounts.User proxy for the given uid */ +static AccountsUser * +get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) +{ + priv_t * p = self->priv; + + return g_hash_table_lookup (p->uid_to_account, GUINT_TO_POINTER(uid)); +} + +/* returns true if this is a uid that should be listed in the session indicator */ +static gboolean +is_public_uid (IndicatorSessionUsersDbus * self, guint uid) +{ + AccountsUser * au; + gboolean is_public; + + if ((au = get_user_for_uid (self, uid))) + { + is_public = is_public_user (self, au); + } + else + { + /* making a guess to serve until the user's proxy object is ready. + assuming that 999 is a 'live session' user, <999 is system account */ + is_public = uid >= 999; + } + + return is_public; +} + +/*** +**** +***/ + static void emit_user_added (IndicatorSessionUsersDbus * self, guint uid) { - indicator_session_users_added (INDICATOR_SESSION_USERS(self), uid); + if (is_public_uid (self, uid)) + indicator_session_users_added (INDICATOR_SESSION_USERS(self), uid); } static void emit_user_changed (IndicatorSessionUsersDbus * self, guint uid) { - indicator_session_users_changed (INDICATOR_SESSION_USERS(self), uid); + if (is_public_uid (self, uid)) + indicator_session_users_changed (INDICATOR_SESSION_USERS(self), uid); } static void emit_user_removed (IndicatorSessionUsersDbus * self, guint uid) { - indicator_session_users_removed (INDICATOR_SESSION_USERS(self), uid); + if (is_public_uid (self, uid)) + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), uid); } /*** @@ -99,11 +159,8 @@ set_active_uid (IndicatorSessionUsersDbus * self, guint uid) p->active_uid = uid; - if (old_uid) - emit_user_changed (self, old_uid); - - if (uid) - emit_user_changed (self, uid); + emit_user_changed (self, old_uid); + emit_user_changed (self, uid); } } @@ -180,18 +237,6 @@ object_add_connection (GObject * o, gulong connection_id) g_object_set_qdata (o, q, ids); } -/*** -**** -***/ - -static AccountsUser * -get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) -{ - priv_t * p = self->priv; - - return g_hash_table_lookup (p->uid_to_account, GUINT_TO_POINTER(uid)); -} - /*** **** User Account Tracking ***/ @@ -213,25 +258,24 @@ static void track_user (IndicatorSessionUsersDbus * self, AccountsUser * user) { - priv_t * p = self->priv; const guint32 uid = accounts_user_get_uid (user); const gpointer uid_key = GUINT_TO_POINTER (uid); - gboolean already_had_user; + priv_t * p = self->priv; gulong id; + gboolean already_had_user; + + g_return_if_fail (is_public_user (self, user)); already_had_user = g_hash_table_contains (p->uid_to_account, uid_key); - id = g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); + id = g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); object_add_connection (G_OBJECT(user), id); g_hash_table_insert (p->uid_to_account, uid_key, user); - if (!accounts_user_get_system_account (user)) - { - if (already_had_user) - emit_user_changed (self, uid); - else - emit_user_added (self, uid); - } + if (already_had_user) + emit_user_changed (self, uid); + else + emit_user_added (self, uid); } static void @@ -258,6 +302,8 @@ untrack_user (IndicatorSessionUsersDbus * self, } } +/* We got a new org.freedesktop.Accounts.User proxy. + If it's one we want to remember, pass it to track_user() */ static void on_user_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, @@ -275,10 +321,14 @@ on_user_proxy_ready (GObject * o G_GNUC_UNUSED, g_error_free (err); } - else + else if (is_public_user (self, user)) { track_user (self, user); } + else + { + g_object_unref (self); + } } static void @@ -293,7 +343,7 @@ create_user_proxy_for_path (IndicatorSessionUsersDbus * self, on_user_proxy_ready, self); } -/* create user proxies for everything in Account's user-list */ +/* create proxy objects for everything in Account's user-list */ static void on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) { @@ -406,12 +456,11 @@ on_login1_manager_session_list_ready (GObject * o, { set_active_uid (self, uid); - if ((uid==999) && !g_strcmp0 (user_name,"ubuntu")) + if (is_live_user (uid, user_name)) is_live_session = TRUE; } - /* only count user accounts and the live session */ - if (uid >= 999) + if (is_public_uid (self, uid)) g_hash_table_add (logins, GINT_TO_POINTER(uid)); } @@ -541,22 +590,8 @@ my_is_live_session (IndicatorSessionUsers * users) static GList * my_get_uids (IndicatorSessionUsers * users) { - priv_t * p; - GList * uids; - GHashTableIter iter; - gpointer uid; - gpointer user; - - g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), NULL); - p = INDICATOR_SESSION_USERS_DBUS (users)->priv; - - uids = NULL; - g_hash_table_iter_init (&iter, p->uid_to_account); - while (g_hash_table_iter_next (&iter, &uid, &user)) - if (!accounts_user_get_system_account (user)) - uids = g_list_prepend (uids, uid); - - return uids; + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (users); + return g_hash_table_get_keys (self->priv->uid_to_account); } /* build a new struct populated with info on the specified user */ -- cgit v1.2.3 From 69bf3537b0fe5aa00d015c7339ce20e9c2b80d1f Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 28 Jun 2013 09:48:54 -0500 Subject: finish up backend-dbus/users.c: fix an unref bug when creating user proxies. fix an async race condition where we emitted change events for users before their proxy objects had finished being asynchronously constructed. --- src/backend-dbus/users.c | 118 ++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 64 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 1db5ac1..b5a6d32 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -41,6 +41,8 @@ struct _IndicatorSessionUsersDbusPriv gboolean is_live; GCancellable * cancellable; + + guint update_list_tag; }; typedef IndicatorSessionUsersDbusPriv priv_t; @@ -53,29 +55,6 @@ G_DEFINE_TYPE (IndicatorSessionUsersDbus, **** ***/ -/* returns true if the fields indicate this is the 'live cd' user */ -static gboolean -is_live_user (guint uid, const char * username) -{ - return uid==999 && !g_strcmp0 (username, "ubuntu"); -} - -/* returns true if this is a user who should be listed in the session indicator */ -static gboolean -is_public_user (IndicatorSessionUsersDbus * self G_GNUC_UNUSED, - AccountsUser * au) -{ - gboolean is_public; - - /* the 'live session' user is the only system account we'll show */ - if (is_live_user (accounts_user_get_uid(au), accounts_user_get_user_name(au))) - is_public = TRUE; - else - is_public = !accounts_user_get_system_account (au); - - return is_public; -} - /* get our private org.freedesktop.Accounts.User proxy for the given uid */ static AccountsUser * get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) @@ -85,50 +64,30 @@ get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) return g_hash_table_lookup (p->uid_to_account, GUINT_TO_POINTER(uid)); } -/* returns true if this is a uid that should be listed in the session indicator */ static gboolean -is_public_uid (IndicatorSessionUsersDbus * self, guint uid) +is_tracked_uid (IndicatorSessionUsersDbus * self, guint uid) { - AccountsUser * au; - gboolean is_public; - - if ((au = get_user_for_uid (self, uid))) - { - is_public = is_public_user (self, au); - } - else - { - /* making a guess to serve until the user's proxy object is ready. - assuming that 999 is a 'live session' user, <999 is system account */ - is_public = uid >= 999; - } - - return is_public; + return get_user_for_uid (self, uid) != NULL; } -/*** -**** -***/ - static void -emit_user_added (IndicatorSessionUsersDbus * self, guint uid) +emit_user_added (IndicatorSessionUsersDbus * self, guint32 uid) { - if (is_public_uid (self, uid)) + if (is_tracked_uid (self, uid)) indicator_session_users_added (INDICATOR_SESSION_USERS(self), uid); } static void -emit_user_changed (IndicatorSessionUsersDbus * self, guint uid) +emit_user_changed (IndicatorSessionUsersDbus * self, guint32 uid) { - if (is_public_uid (self, uid)) + if (is_tracked_uid (self, uid)) indicator_session_users_changed (INDICATOR_SESSION_USERS(self), uid); } static void -emit_user_removed (IndicatorSessionUsersDbus * self, guint uid) +emit_user_removed (IndicatorSessionUsersDbus * self, guint32 uid) { - if (is_public_uid (self, uid)) - indicator_session_users_removed (INDICATOR_SESSION_USERS(self), uid); + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), uid); } /*** @@ -259,18 +218,13 @@ track_user (IndicatorSessionUsersDbus * self, AccountsUser * user) { const guint32 uid = accounts_user_get_uid (user); - const gpointer uid_key = GUINT_TO_POINTER (uid); priv_t * p = self->priv; gulong id; - gboolean already_had_user; - - g_return_if_fail (is_public_user (self, user)); - - already_had_user = g_hash_table_contains (p->uid_to_account, uid_key); + const gboolean already_had_user = is_tracked_uid (self, uid); id = g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); object_add_connection (G_OBJECT(user), id); - g_hash_table_insert (p->uid_to_account, uid_key, user); + g_hash_table_insert (p->uid_to_account, GUINT_TO_POINTER (uid), user); if (already_had_user) emit_user_changed (self, uid); @@ -321,13 +275,13 @@ on_user_proxy_ready (GObject * o G_GNUC_UNUSED, g_error_free (err); } - else if (is_public_user (self, user)) + else if (!accounts_user_get_system_account (user)) { track_user (self, user); } else { - g_object_unref (self); + g_object_unref (user); } } @@ -456,12 +410,11 @@ on_login1_manager_session_list_ready (GObject * o, { set_active_uid (self, uid); - if (is_live_user (uid, user_name)) + if ((uid==999) && !g_strcmp0 (user_name, "ubuntu")) is_live_session = TRUE; } - if (is_public_uid (self, uid)) - g_hash_table_add (logins, GINT_TO_POINTER(uid)); + g_hash_table_add (logins, GINT_TO_POINTER(uid)); } set_is_live_session_flag (self, is_live_session); @@ -485,8 +438,35 @@ update_session_list (IndicatorSessionUsersDbus * self) } } +static gboolean +on_update_session_list_timer (gpointer gself) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (gself); + + update_session_list (self); + + self->priv->update_list_tag = 0; + return G_SOURCE_REMOVE; +} + +/* A dead session can still show up in list-sessions for a few seconds. + So just to be safe, queue up a rebuild for a few seconds from now */ static void -set_login1_manager (IndicatorSessionUsersDbus * self, Login1Manager * login1_manager) +update_session_list_twice (IndicatorSessionUsersDbus * self) +{ + priv_t * p = self->priv; + + update_session_list (self); + + if (p->update_list_tag == 0) + p->update_list_tag = g_timeout_add_seconds (5, + on_update_session_list_timer, + self); +} + +static void +set_login1_manager (IndicatorSessionUsersDbus * self, + Login1Manager * login1_manager) { priv_t * p = self->priv; @@ -504,7 +484,11 @@ set_login1_manager (IndicatorSessionUsersDbus * self, Login1Manager * login1_man g_signal_connect_swapped (login1_manager, "session-new", G_CALLBACK(update_session_list), self); g_signal_connect_swapped (login1_manager, "session-removed", + G_CALLBACK(update_session_list_twice), self); + g_signal_connect_swapped (login1_manager, "user-new", G_CALLBACK(update_session_list), self); + g_signal_connect_swapped (login1_manager, "user-removed", + G_CALLBACK(update_session_list_twice), self); update_session_list (self); } } @@ -632,6 +616,12 @@ my_dispose (GObject * o) IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); priv_t * p = self->priv; + if (p->update_list_tag != 0) + { + g_source_remove (p->update_list_tag); + p->update_list_tag = 0; + } + if (p->cancellable) { g_cancellable_cancel (p->cancellable); -- cgit v1.2.3 From 604640ebeca2fe1b2eb4aa475dbb4221dd8aeb72 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 1 Jul 2013 13:06:17 -0500 Subject: in src/backend-dbus/users.c's set_logins(), fix ref/unref semantics of the hashtable argument --- src/backend-dbus/users.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index b5a6d32..caf6403 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -130,7 +130,7 @@ set_logins (IndicatorSessionUsersDbus * self, GHashTable * logins) gpointer uid; GHashTableIter iter; - self->priv->logins = logins; + self->priv->logins = g_hash_table_ref (logins); /* fire 'user changed' event for users who logged out */ g_hash_table_iter_init (&iter, old_logins); @@ -420,6 +420,7 @@ on_login1_manager_session_list_ready (GObject * o, set_is_live_session_flag (self, is_live_session); set_logins (self, logins); + g_hash_table_unref (logins); g_variant_unref (sessions); } } -- cgit v1.2.3 From d5421fec0a7e51ddb1979a97de271a3f1733321e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 1 Jul 2013 13:07:33 -0500 Subject: in src/backend-dbus/users.c, use G_DEFINE_QUARK() instead of rolling our own quark func --- src/backend-dbus/users.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index caf6403..b9a79e5 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -151,23 +151,14 @@ set_logins (IndicatorSessionUsersDbus * self, GHashTable * logins) **** ***/ -static GQuark -get_connection_list_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY (q == 0)) - q = g_quark_from_static_string ("connection-ids"); - - return q; -} +G_DEFINE_QUARK (connection-ids, connection_list) static void object_unref_and_disconnect (gpointer instance) { - GSList * l; + const GQuark q = connection_list_quark (); GSList * ids; - const GQuark q = get_connection_list_quark (); + GSList * l; ids = g_object_steal_qdata (G_OBJECT(instance), q); for (l=ids; l!=NULL; l=l->next) @@ -184,7 +175,7 @@ object_unref_and_disconnect (gpointer instance) static void object_add_connection (GObject * o, gulong connection_id) { - const GQuark q = get_connection_list_quark (); + const GQuark q = connection_list_quark (); GSList * ids; gulong * ptr; -- cgit v1.2.3 From eb7e99b24b15a311f188754bf3d0d4f72551deab Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 1 Jul 2013 13:12:08 -0500 Subject: in src/backend-dbus/users.c's track_user(), simplify the ref/unref semantics of the user argument --- src/backend-dbus/users.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index b9a79e5..738eda4 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -215,7 +215,9 @@ track_user (IndicatorSessionUsersDbus * self, id = g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); object_add_connection (G_OBJECT(user), id); - g_hash_table_insert (p->uid_to_account, GUINT_TO_POINTER (uid), user); + g_hash_table_insert (p->uid_to_account, + GUINT_TO_POINTER (uid), + g_object_ref (user)); if (already_had_user) emit_user_changed (self, uid); @@ -266,12 +268,11 @@ on_user_proxy_ready (GObject * o G_GNUC_UNUSED, g_error_free (err); } - else if (!accounts_user_get_system_account (user)) - { - track_user (self, user); - } else { + if (!accounts_user_get_system_account (user)) + track_user (self, user); + g_object_unref (user); } } -- cgit v1.2.3 From bb2129f5fada412c88e5d3f739038d560a5444a9 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 1 Jul 2013 13:13:07 -0500 Subject: in src/backend-dbus/users.c's object_unref_and_disconnect(), fix an unbalanced ref/unref --- src/backend-dbus/users.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 738eda4..6f02a53 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -166,9 +166,10 @@ object_unref_and_disconnect (gpointer instance) gulong * handler_id = l->data; g_signal_handler_disconnect (instance, *handler_id); g_free (handler_id); - g_object_unref (instance); } + g_object_unref (instance); + g_slist_free (ids); } -- cgit v1.2.3 From c96e42d1d00d68b6c858d7d314c13b4d05ca0d8b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 1 Jul 2013 13:28:05 -0500 Subject: in src/backend-dbus/users.c, use a helper struct for disconnecting the signals to the user proxies in our uid-to-user hashtable --- src/backend-dbus/users.c | 94 +++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 49 deletions(-) (limited to 'src/backend-dbus/users.c') diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c index 6f02a53..f770695 100644 --- a/src/backend-dbus/users.c +++ b/src/backend-dbus/users.c @@ -28,7 +28,7 @@ struct _IndicatorSessionUsersDbusPriv DisplayManagerSeat * dm_seat; Accounts * accounts; - /* hash table of int uids to AccountsUser* */ + /* hash table of int uids to UserRecord* */ GHashTable * uid_to_account; /* a hashset of int uids of users who are logged in */ @@ -55,13 +55,46 @@ G_DEFINE_TYPE (IndicatorSessionUsersDbus, **** ***/ +struct UserRecord +{ + AccountsUser * user; + + gulong signal_id; +}; + +struct UserRecord * +user_record_new (AccountsUser * user, gulong signal_id) +{ + struct UserRecord * rec; + rec = g_new (struct UserRecord, 1); + rec->user = g_object_ref (user); + rec->signal_id = signal_id; + return rec; +} + +static void +user_record_free (struct UserRecord * rec) +{ + g_signal_handler_disconnect (rec->user, rec->signal_id); + g_object_unref (G_OBJECT (rec->user)); + g_free (rec); +} + +/*** +**** +***/ + /* get our private org.freedesktop.Accounts.User proxy for the given uid */ static AccountsUser * get_user_for_uid (IndicatorSessionUsersDbus * self, guint uid) { - priv_t * p = self->priv; + struct UserRecord * rec; + + if ((rec = g_hash_table_lookup (self->priv->uid_to_account, + GUINT_TO_POINTER(uid)))) + return rec->user; - return g_hash_table_lookup (p->uid_to_account, GUINT_TO_POINTER(uid)); + return NULL; } static gboolean @@ -147,47 +180,6 @@ set_logins (IndicatorSessionUsersDbus * self, GHashTable * logins) g_hash_table_destroy (old_logins); } -/*** -**** -***/ - -G_DEFINE_QUARK (connection-ids, connection_list) - -static void -object_unref_and_disconnect (gpointer instance) -{ - const GQuark q = connection_list_quark (); - GSList * ids; - GSList * l; - - ids = g_object_steal_qdata (G_OBJECT(instance), q); - for (l=ids; l!=NULL; l=l->next) - { - gulong * handler_id = l->data; - g_signal_handler_disconnect (instance, *handler_id); - g_free (handler_id); - } - - g_object_unref (instance); - - g_slist_free (ids); -} - -static void -object_add_connection (GObject * o, gulong connection_id) -{ - const GQuark q = connection_list_quark (); - GSList * ids; - gulong * ptr; - - ptr = g_new (gulong, 1); - *ptr = connection_id; - - ids = g_object_steal_qdata (o, q); - ids = g_slist_prepend (ids, ptr); - g_object_set_qdata (o, q, ids); -} - /*** **** User Account Tracking ***/ @@ -215,10 +207,9 @@ track_user (IndicatorSessionUsersDbus * self, const gboolean already_had_user = is_tracked_uid (self, uid); id = g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); - object_add_connection (G_OBJECT(user), id); g_hash_table_insert (p->uid_to_account, GUINT_TO_POINTER (uid), - g_object_ref (user)); + user_record_new (user, id)); if (already_had_user) emit_user_changed (self, uid); @@ -236,11 +227,16 @@ untrack_user (IndicatorSessionUsersDbus * self, GHashTableIter iter; priv_t * p = self->priv; + /* find the uid matching this object path */ uid = 0; g_hash_table_iter_init (&iter, p->uid_to_account); while (!uid && g_hash_table_iter_next (&iter, &key, &val)) - if (!g_strcmp0 (path, g_dbus_proxy_get_object_path (val))) - uid = GPOINTER_TO_UINT (key); + { + struct UserRecord * rec = val; + GDBusProxy * proxy = G_DBUS_PROXY (rec->user); + if (!g_strcmp0 (path, g_dbus_proxy_get_object_path (proxy))) + uid = GPOINTER_TO_UINT (key); + } if (uid) { @@ -677,7 +673,7 @@ indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) p->uid_to_account = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - object_unref_and_disconnect); + (GDestroyNotify)user_record_free); p->logins = g_hash_table_new (g_direct_hash, g_direct_equal); } -- cgit v1.2.3