};
struct sessiond_context {
+ /* A special value representing the state
+ * before any sub session is switched to. */
+ static constexpr int INITIAL_SUB_SESSION_ID = 0;
+
sessiond_context() : data(xml), id(bus_name, glib_bus_connected, glib_name_lost, this), loop()
{
}
vals_to_g_variant(session_uid, switch_id, prev_subsession_id, next_subsession_id), &err))
g_error_throw(err, "Failed to emit a signal: ");
+ last_subsession_per_session[session_uid] = next_subsession_id;
+
wait_switch.try_emplace(session_uid, session_uid, connection, "SwitchUserCompleted");
wait_switch.at(session_uid).on_start(switch_id, { prev_subsession_id, next_subsession_id });
g_dbus_method_invocation_return_value(invocation, ret);
}
+ void on_get_current_user(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
+ {
+ auto [ session_uid ] = tuple_from_g_variant<int>(parameters);
+
+ if (session_uid <= 0) {
+ g_dbus_method_invocation_return_dbus_error(invocation, "org.freedesktop.DBus.Error.InvalidArgs", "Negative UID passed");
+ return;
+ }
+
+ int subsession_id = INITIAL_SUB_SESSION_ID;
+ if (last_subsession_per_session.contains(session_uid))
+ subsession_id = last_subsession_per_session.at(session_uid);
+
+ auto ret = vals_to_g_variant(subsession_id);
+ g_dbus_method_invocation_return_value(invocation, ret);
+ }
+
static void glib_bus_connected(GDBusConnection *conn, const gchar *name, gpointer user_data)
{
auto self = static_cast<sessiond_context *>(user_data);
"<arg name=\"session_uid\" type=\"i\" direction=\"in\"/>"
"<arg name=\"subsession_id_list\" type=\"ai\" direction=\"out\"/>"
"</method>"
+ "<method name=\"GetCurrentUser\">"
+ "<arg name=\"session_uid\" type=\"i\" direction=\"in\"/>"
+ "<arg name=\"subsession_id\" type=\"i\" direction=\"out\"/>"
+ "</method>"
"<signal name=\"AddUserStarted\">"
"<arg name=\"session_uid\" type=\"i\" direction=\"out\"/>"
"<arg name=\"subsession_id\" type=\"i\" direction=\"out\"/>"
std::pair<
std::string_view,
void (sessiond_context::*)(GDBusMethodInvocation *, std::string_view, GVariant *)
- >, 10> methods = {
+ >, 11> methods = {
std::make_pair("AddUser", &sessiond_context::on_add_user),
std::make_pair("RemoveUser", &sessiond_context::on_remove_user),
std::make_pair("SwitchUser", &sessiond_context::on_switch_user),
std::make_pair("RemoveUserDone", &sessiond_context::on_remove_user_done),
std::make_pair("SwitchUserDone", &sessiond_context::on_switch_user_done),
std::make_pair("GetUserList", &sessiond_context::on_get_user_list),
+ std::make_pair("GetCurrentUser", &sessiond_context::on_get_current_user),
};
// TODO: Currently, the first parameter is always a single-element tuple.
// Consider simplifying wait_manager.
+ // N.B. Although GLib is multi-threaded, the following data structures do not need
+ // to be protected by mutexes as all of them are accessed from DBus handlers only.
std::unordered_map<int, wait_manager<std::tuple<int>, std::tuple<>>> wait_add;
std::unordered_map<int, wait_manager<std::tuple<int>, std::tuple<>>> wait_remove;
std::unordered_map<int, wait_manager<std::tuple<uint64_t>, std::tuple<int, int>>> wait_switch;
+ // used for tracking subsession switches for each `session_uid`
+ std::unordered_map<int, int> last_subsession_per_session;
+
uint64_t switch_id = 0;
introspection_data data;