aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/session/logind.c154
1 files changed, 152 insertions, 2 deletions
diff --git a/backend/session/logind.c b/backend/session/logind.c
index 393924e8..852b6ae5 100644
--- a/backend/session/logind.c
+++ b/backend/session/logind.c
@@ -35,7 +35,9 @@ struct logind_session {
char *id;
char *path;
+ char *seat_path;
+ bool can_graphical;
// specifies whether a drm device was taken
// if so, the session will be (de)activated with the drm fd,
// otherwise with the dbus PropertiesChanged on "active" signal
@@ -175,6 +177,34 @@ out:
return ret >= 0;
}
+static bool find_seat_path(struct logind_session *session) {
+ int ret;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+
+ ret = sd_bus_call_method(session->bus, "org.freedesktop.login1",
+ "/org/freedesktop/login1", "org.freedesktop.login1.Manager",
+ "GetSeat", &error, &msg, "s", session->base.seat);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Failed to get seat path: %s", error.message);
+ goto out;
+ }
+
+ const char *path;
+ ret = sd_bus_message_read(msg, "o", &path);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Could not parse seat path: %s", error.message);
+ goto out;
+ }
+ session->seat_path = strdup(path);
+
+out:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
+
+ return ret >= 0;
+}
+
static bool session_activate(struct logind_session *session) {
int ret;
sd_bus_message *msg = NULL;
@@ -236,6 +266,7 @@ static void logind_session_destroy(struct wlr_session *base) {
sd_bus_unref(session->bus);
free(session->id);
free(session->path);
+ free(session->seat_path);
free(session);
}
@@ -328,7 +359,7 @@ error:
return 0;
}
-static int properties_changed(sd_bus_message *msg, void *userdata,
+static int session_properties_changed(sd_bus_message *msg, void *userdata,
sd_bus_error *ret_error) {
struct logind_session *session = userdata;
int ret = 0;
@@ -437,6 +468,95 @@ error:
return 0;
}
+static int seat_properties_changed(sd_bus_message *msg, void *userdata,
+ sd_bus_error *ret_error) {
+ struct logind_session *session = userdata;
+ int ret = 0;
+
+ // if we have a drm fd we don't depend on this
+ if (session->has_drm) {
+ return 0;
+ }
+
+ // PropertiesChanged arg 1: interface
+ const char *interface;
+ ret = sd_bus_message_read_basic(msg, 's', &interface); // skip path
+ if (ret < 0) {
+ goto error;
+ }
+
+ if (strcmp(interface, "org.freedesktop.login1.Seat") != 0) {
+ // not interesting for us; ignore
+ wlr_log(WLR_DEBUG, "ignoring PropertiesChanged from %s", interface);
+ return 0;
+ }
+
+ // PropertiesChanged arg 2: changed properties with values
+ ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
+ if (ret < 0) {
+ goto error;
+ }
+
+ const char *s;
+ while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
+ ret = sd_bus_message_read_basic(msg, 's', &s);
+ if (ret < 0) {
+ goto error;
+ }
+
+ if (strcmp(s, "CanGraphical") == 0) {
+ int ret;
+ ret = sd_bus_message_enter_container(msg, 'v', "b");
+ if (ret < 0) {
+ goto error;
+ }
+
+ ret = sd_bus_message_read_basic(msg, 'b', &session->can_graphical);
+ if (ret < 0) {
+ goto error;
+ }
+
+ return 0;
+ } else {
+ sd_bus_message_skip(msg, "{sv}");
+ }
+
+ ret = sd_bus_message_exit_container(msg);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ if (ret < 0) {
+ goto error;
+ }
+
+ ret = sd_bus_message_exit_container(msg);
+ if (ret < 0) {
+ goto error;
+ }
+
+ // PropertiesChanged arg 3: changed properties without values
+ sd_bus_message_enter_container(msg, 'a', "s");
+ while ((ret = sd_bus_message_read_basic(msg, 's', &s)) > 0) {
+ if (strcmp(s, "CanGraphical") == 0) {
+ session->can_graphical = sd_seat_can_graphical(session->base.seat);
+ return 0;
+ }
+ }
+
+ if (ret < 0) {
+ goto error;
+ }
+
+ return 0;
+
+error:
+ wlr_log(WLR_ERROR, "Failed to parse D-Bus PropertiesChanged: %s",
+ strerror(-ret));
+ return 0;
+}
+
static bool add_signal_matches(struct logind_session *session) {
int ret;
@@ -471,7 +591,15 @@ static bool add_signal_matches(struct logind_session *session) {
ret = sd_bus_match_signal(session->bus, NULL, "org.freedesktop.login1",
session->path, "org.freedesktop.DBus.Properties", "PropertiesChanged",
- properties_changed, session);
+ session_properties_changed, session);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Failed to add D-Bus match: %s", strerror(-ret));
+ return false;
+ }
+
+ ret = sd_bus_match_signal(session->bus, NULL, "org.freedesktop.login1",
+ session->seat_path, "org.freedesktop.DBus.Properties",
+ "PropertiesChanged", seat_properties_changed, session);
if (ret < 0) {
wlr_log(WLR_ERROR, "Failed to add D-Bus match: %s", strerror(-ret));
return false;
@@ -656,6 +784,12 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
goto error;
}
+ if (!find_seat_path(session)) {
+ sd_bus_unref(session->bus);
+ free(session->path);
+ goto error;
+ }
+
if (!add_signal_matches(session)) {
goto error_bus;
}
@@ -672,6 +806,21 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
goto error_bus;
}
+ // Check for CanGraphical first
+ session->can_graphical = sd_seat_can_graphical(session->base.seat);
+ if (!session->can_graphical) {
+ wlr_log(WLR_INFO, "Waiting for 'CanGraphical' on seat %s", session->base.seat);
+ }
+
+ while (!session->can_graphical) {
+ ret = wl_event_loop_dispatch(event_loop, -1);
+ if (ret < 0) {
+ wlr_log(WLR_ERROR, "Polling error waiting for 'CanGraphical' on seat %s",
+ session->base.seat);
+ goto error_bus;
+ }
+ }
+
wlr_log(WLR_INFO, "Successfully loaded logind session");
session->base.impl = &session_logind;
@@ -680,6 +829,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
error_bus:
sd_bus_unref(session->bus);
free(session->path);
+ free(session->seat_path);
error:
free(session->id);