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.
This commit is contained in:
parent
28f11aec31
commit
c138da233b
|
@ -487,6 +487,123 @@ static int dbus_event(int fd, uint32_t mask, void *data) {
|
||||||
return 1;
|
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) {
|
static struct wlr_session *logind_session_create(struct wl_display *disp) {
|
||||||
int ret;
|
int ret;
|
||||||
struct logind_session *session = calloc(1, sizeof(*session));
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_pid_get_session(getpid(), &session->id);
|
if (!get_display_session(&session->id)) {
|
||||||
if (ret < 0) {
|
|
||||||
wlr_log(WLR_ERROR, "Failed to get session id: %s", strerror(-ret));
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue