diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | backend/session/logind.c | 121 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | types/data_device/wlr_drag.c | 3 | ||||
-rw-r--r-- | types/xdg_shell/wlr_xdg_popup.c | 3 | ||||
-rw-r--r-- | types/xdg_shell/wlr_xdg_surface.c | 5 | ||||
-rw-r--r-- | xwayland/selection/dnd.c | 5 |
7 files changed, 135 insertions, 5 deletions
@@ -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; |