aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authormnussbaum <michaelnussbaum08@gmail.com>2019-02-01 18:56:31 -0800
committermnnussbaum <michaelnussbaum08@gmail.com>2019-02-03 18:45:32 -0800
commitc138da233b618ab5d42e4810f1ad7f2e687f2a59 (patch)
tree1441337adac6927b62bb9262be71b103f7e0dc92 /backend
parent28f11aec3106c5d0528d1835055c82c4d571c286 (diff)
Allow compositors to run as systemd user units
When a wlroots compositor runs as a systemd user unit there is no session associated with the compositor process. Instead we need to attach to an active and graphical user session. This change first looks for an available session for the process, and if there isn't one falls back to display in the oldest available graphical session. This work was modeled after a similar change to mutter - https://gitlab.gnome.org/GNOME/mutter/merge_requests/150.
Diffstat (limited to 'backend')
-rw-r--r--backend/session/logind.c121
1 files changed, 118 insertions, 3 deletions
diff --git a/backend/session/logind.c b/backend/session/logind.c
index 5bde16c2..0bacfbcd 100644
--- a/backend/session/logind.c
+++ b/backend/session/logind.c
@@ -487,6 +487,123 @@ static int dbus_event(int fd, uint32_t mask, void *data) {
return 1;
}
+static bool contains_str(const char *needle, const char **haystack) {
+ for (int i = 0; haystack[i]; i++) {
+ if (strcmp(haystack[i], needle) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool get_greeter_session(char **session_id) {
+ char *class = NULL;
+ char **user_sessions = NULL;
+ int user_session_count = sd_uid_get_sessions(getuid(), 1, &user_sessions);
+
+ if (user_session_count < 0) {
+ wlr_log(WLR_ERROR, "Failed to get sessions");
+ goto out;
+ }
+
+ if (user_session_count == 0) {
+ wlr_log(WLR_ERROR, "User has no sessions");
+ goto out;
+ }
+
+ for (int i = 0; i < user_session_count; ++i) {
+ int ret = sd_session_get_class(user_sessions[i], &class);
+ if (ret < 0) {
+ continue;
+ }
+
+ if (strcmp(class, "greeter") == 0) {
+ *session_id = strdup(user_sessions[i]);
+ goto out;
+ }
+ }
+
+out:
+ free(class);
+ for (int i = 0; i < user_session_count; ++i) {
+ free(user_sessions[i]);
+ }
+ free(user_sessions);
+
+ return *session_id != NULL;
+}
+
+static bool get_display_session(char **session_id) {
+ assert(session_id != NULL);
+ int ret;
+
+ // If there's a session active for the current process then just use that
+ ret = sd_pid_get_session(getpid(), session_id);
+ if (ret == 0) {
+ return true;
+ }
+
+ char *type = NULL;
+ char *state = NULL;
+
+ // Find any active sessions for the user if the process isn't part of an
+ // active session itself
+ ret = sd_uid_get_display(getuid(), session_id);
+ if (ret < 0 && ret != -ENODATA) {
+ wlr_log(WLR_ERROR, "Failed to get display: %s", strerror(-ret));
+ goto error;
+ }
+
+ if (ret != 0 && !get_greeter_session(session_id)) {
+ wlr_log(WLR_ERROR, "Couldn't find an active session or a greeter session");
+ goto error;
+ }
+
+ assert(*session_id != NULL);
+
+ // Check that the available session is graphical
+ ret = sd_session_get_type(*session_id, &type);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Couldn't get a type for session '%s': %s",
+ *session_id, strerror(-ret));
+ goto error;
+ }
+
+ const char *graphical_session_types[] = {"wayland", "x11", "mir", NULL};
+ if (!contains_str(type, graphical_session_types)) {
+ wlr_log(WLR_ERROR, "Session '%s' isn't a graphical session (type: '%s')",
+ *session_id, type);
+ goto error;
+ }
+
+ // Check that the session is active
+ ret = sd_session_get_state(*session_id, &state);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Couldn't get state for session '%s': %s",
+ *session_id, strerror(-ret));
+ goto error;
+ }
+
+ const char *active_states[] = {"active", "online", NULL};
+ if (!contains_str(state, active_states)) {
+ wlr_log(WLR_ERROR, "Session '%s' is not active", *session_id);
+ goto error;
+ }
+
+ free(type);
+ free(state);
+ return true;
+
+error:
+ free(type);
+ free(state);
+ free(*session_id);
+ *session_id = NULL;
+
+ return false;
+}
+
static struct wlr_session *logind_session_create(struct wl_display *disp) {
int ret;
struct logind_session *session = calloc(1, sizeof(*session));
@@ -495,9 +612,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
return NULL;
}
- ret = sd_pid_get_session(getpid(), &session->id);
- if (ret < 0) {
- wlr_log(WLR_ERROR, "Failed to get session id: %s", strerror(-ret));
+ if (!get_display_session(&session->id)) {
goto error;
}