aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--backend/session/logind.c121
-rw-r--r--meson.build2
-rw-r--r--types/data_device/wlr_drag.c3
-rw-r--r--types/xdg_shell/wlr_xdg_popup.c3
-rw-r--r--types/xdg_shell/wlr_xdg_surface.c5
-rw-r--r--xwayland/selection/dnd.c5
7 files changed, 135 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index be30a5fc..516afff1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
bin/
test/
build/
+build-*/
wayland-*-protocol.*
wlr-example.ini
rootston.ini
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;
}
diff --git a/meson.build b/meson.build
index 3284d5ca..4d68bd6c 100644
--- a/meson.build
+++ b/meson.build
@@ -1,7 +1,7 @@
project(
'wlroots',
'c',
- version: '0.2.0',
+ version: '0.3.0',
license: 'MIT',
meson_version: '>=0.48.0',
default_options: [
diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c
index 9bd63d96..2b676fdc 100644
--- a/types/data_device/wlr_drag.c
+++ b/types/data_device/wlr_drag.c
@@ -490,6 +490,9 @@ bool seat_client_start_drag(struct wlr_seat_client *client,
seat->drag = drag; // TODO: unset this thing somewhere
seat->drag_serial = serial;
+ if (seat->drag_source != NULL) {
+ wl_list_remove(&seat->drag_source_destroy.link);
+ }
seat->drag_source = source;
if (source != NULL) {
seat->drag_source_destroy.notify = seat_handle_drag_source_destroy;
diff --git a/types/xdg_shell/wlr_xdg_popup.c b/types/xdg_shell/wlr_xdg_popup.c
index 598c14ef..b27a629e 100644
--- a/types/xdg_shell/wlr_xdg_popup.c
+++ b/types/xdg_shell/wlr_xdg_popup.c
@@ -285,7 +285,8 @@ void destroy_xdg_popup(struct wlr_xdg_surface *xdg_surface) {
if (xdg_surface == NULL) {
return;
}
- assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
+ assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP ||
+ xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE);
reset_xdg_surface(xdg_surface);
}
diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c
index 0e98155a..db3fc29a 100644
--- a/types/xdg_shell/wlr_xdg_surface.c
+++ b/types/xdg_shell/wlr_xdg_surface.c
@@ -524,9 +524,14 @@ void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) {
}
void wlr_xdg_popup_destroy(struct wlr_xdg_surface *surface) {
+ if (surface == NULL) {
+ return;
+ }
assert(surface->popup);
assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
xdg_popup_send_popup_done(surface->popup->resource);
+ wl_resource_set_user_data(surface->popup->resource, NULL);
+ destroy_xdg_popup(surface);
}
static void xdg_popup_get_position(struct wlr_xdg_popup *popup,
diff --git a/xwayland/selection/dnd.c b/xwayland/selection/dnd.c
index ec5f16c7..fc090936 100644
--- a/xwayland/selection/dnd.c
+++ b/xwayland/selection/dnd.c
@@ -315,6 +315,8 @@ static void seat_handle_drag_source_destroy(struct wl_listener *listener,
wl_container_of(listener, xwm, seat_drag_source_destroy);
wl_list_remove(&xwm->seat_drag_source_destroy.link);
+ xwm->seat_drag_source_destroy.link.prev = NULL;
+ xwm->seat_drag_source_destroy.link.next = NULL;
xwm->drag_focus = NULL;
}
@@ -332,6 +334,9 @@ void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag) {
wl_signal_add(&drag->events.destroy, &xwm->seat_drag_destroy);
xwm->seat_drag_destroy.notify = seat_handle_drag_destroy;
+ if (xwm->seat_drag_source_destroy.link.prev != NULL) {
+ wl_list_remove(&xwm->seat_drag_source_destroy.link);
+ }
wl_signal_add(&drag->source->events.destroy,
&xwm->seat_drag_source_destroy);
xwm->seat_drag_source_destroy.notify = seat_handle_drag_source_destroy;