Name: sl-desktop-utils Version: 1.2.0 Release: 100.1.1%{?dist} Summary: Sl's custom greeter and lock tools for Niri, including idle and sleep services License: LicenseRef-SlsRepo URL: https://slsrepo.com Source0: sl-session.zip Source1: niri-greeter.kdl BuildRequires: unzip BuildRequires: gcc BuildRequires: zig >= 0.16.0 BuildRequires: pkgconf-pkg-config BuildRequires: gtk4-devel BuildRequires: gtk4-layer-shell-devel BuildRequires: json-glib-devel BuildRequires: fontconfig-devel BuildRequires: pam-devel BuildRequires: systemd-rpm-macros Requires: bash Requires: coreutils Requires: grep Requires: util-linux Requires: systemd Requires: greetd Requires: niri Requires: wayidle Requires: gnome-keyring Requires: gtk4 Requires: gtk4-layer-shell Requires: json-glib Requires: fontconfig Requires: pam Requires(post): shadow-utils %description sl-greeter provides the greetd login interface and sl-lock provides the niri session lock. The package also includes idle, suspend and logind lock integration. %prep rm -rf sl-session mkdir -p sl-session unzip -q %{SOURCE0} -d sl-session # If the archive is wrapped in a single top-level folder, flatten it. dir="sl-session" num_dirs=$(find "$dir" -mindepth 1 -maxdepth 1 -type d ! -name "__MACOSX" | wc -l) num_files=$(find "$dir" -mindepth 1 -maxdepth 1 -type f ! -name ".DS_Store" | wc -l) if [ "$num_dirs" -eq 1 ] && [ "$num_files" -eq 0 ]; then wrapper=$(find "$dir" -mindepth 1 -maxdepth 1 -type d ! -name "__MACOSX" | head -n 1) find "$wrapper" -mindepth 1 -maxdepth 1 -exec mv -t "$dir" {} + rm -rf "$wrapper" "$dir/__MACOSX" "$dir/.DS_Store" 2>/dev/null || true fi %build cd sl-session ./build.sh %install rm -rf %{buildroot} install -Dm755 sl-session/zig-out/bin/sl-session \ %{buildroot}%{_bindir}/sl-session ln -s sl-session %{buildroot}%{_bindir}/sl-lock ln -s sl-session %{buildroot}%{_bindir}/sl-greeter install -Dm644 %{SOURCE1} %{buildroot}%{_sysconfdir}/greetd/niri-greeter.kdl install -d -m 755 %{buildroot}%{_sysconfdir}/greetd/sl-greeter cat > %{buildroot}%{_bindir}/sl-lock-listener <<'EOF_LISTENER' #!/bin/bash LOCK_FILE="${XDG_RUNTIME_DIR:-/tmp}/sl-lock-listener.lock" exec 200>"$LOCK_FILE" flock -n 200 || exit 0 SESSION_ID=$(loginctl show-user "$USER" -p Display --value 2>/dev/null) if [ -z "$SESSION_ID" ]; then SESSION_ID=$(loginctl list-sessions --no-legend | grep " $USER " | awk '{print $1}' | head -n 1) fi if [ -z "$SESSION_ID" ]; then echo "Error: Failed to find a session for user $USER" exit 1 fi SESSION_PATH=$(busctl call org.freedesktop.login1 /org/freedesktop/login1 \ org.freedesktop.login1.Manager GetSession s "$SESSION_ID" 2>/dev/null | \ awk '{print $2}' | tr -d '"') if [ -z "$SESSION_PATH" ]; then echo "Error: Could not determine DBus path for session $SESSION_ID" exit 1 fi echo "Success! Listening for locks on session: $SESSION_ID ($SESSION_PATH)" gdbus monitor --system --dest org.freedesktop.login1 --object-path "$SESSION_PATH" | grep --line-buffered "Session.Lock" | while read -r _; do if ! pgrep -u "$(id -u)" -f '(/usr/bin/sl-lock|/usr/bin/sl-session[[:space:]]+lock)' >/dev/null 2>&1; then /usr/bin/sl-lock & fi done EOF_LISTENER chmod 755 %{buildroot}%{_bindir}/sl-lock-listener cat > %{buildroot}%{_bindir}/sl-idle-lock <<'EOF_IDLE' #!/bin/bash TIMEOUT=${1:-300} SL_DISPLAY_MIRROR_INHIBIT="${XDG_RUNTIME_DIR:-/tmp}/sl-idle/display-mirror.inhibit" is_display_mirror_inhibited() { [ -f "$SL_DISPLAY_MIRROR_INHIBIT" ] || return 1 if pgrep -xu "${USER:-$(id -un)}" -x "wl-mirror" >/dev/null 2>&1; then return 0 fi rm -f "$SL_DISPLAY_MIRROR_INHIBIT" return 1 } while true; do /usr/bin/wayidle -t "$TIMEOUT" if is_display_mirror_inhibited; then echo "sl-idle-lock: sl-display-mirror is active; skipping lock." sleep 2 continue fi loginctl lock-session while [ "$(loginctl show-session "$XDG_SESSION_ID" -p LockedHint --value 2>/dev/null)" = "yes" ]; do sleep 2 done sleep 2 done EOF_IDLE chmod 755 %{buildroot}%{_bindir}/sl-idle-lock install -d -m 755 %{buildroot}%{_unitdir} cat > %{buildroot}%{_unitdir}/sl-sleep-lock.service <<'EOF_SLEEP' [Unit] Description=Lock sessions before sleep Before=sleep.target [Service] Type=oneshot ExecStart=/usr/bin/loginctl lock-sessions [Install] WantedBy=sleep.target EOF_SLEEP install -d -m 755 %{buildroot}%{_userunitdir} cat > %{buildroot}%{_userunitdir}/sl-lock-listener.service <<'EOF_USER_SERVICE' [Unit] Description=Sl Lock DBus Listener PartOf=graphical-session.target After=graphical-session.target [Service] ExecStart=/usr/bin/sl-lock-listener Restart=always RestartSec=3 [Install] WantedBy=graphical-session.target EOF_USER_SERVICE install -d -m 755 %{buildroot}%{_unitdir}/greetd.service.d cat > %{buildroot}%{_unitdir}/greetd.service.d/override.conf <<'EOF_GREETD_OVERRIDE' [Unit] After=systemd-user-sessions.service plymouth-quit.service plymouth-quit-wait.service Conflicts=getty@tty2.service [Service] Environment=LIBSEAT_BACKEND=logind EOF_GREETD_OVERRIDE install -d -m 755 %{buildroot}/usr/lib/elogind/system-sleep cat > %{buildroot}/usr/lib/elogind/system-sleep/10-sl-sleep-lock.sh <<'EOF_ELOGIND' #!/bin/sh if [ "$1" = "pre" ]; then /usr/bin/loginctl lock-sessions fi EOF_ELOGIND chmod 755 %{buildroot}/usr/lib/elogind/system-sleep/10-sl-sleep-lock.sh install -d -m 755 %{buildroot}%{_sysconfdir}/profile.d cat > %{buildroot}%{_sysconfdir}/profile.d/sl-lock-autostart.sh <<'EOF_PROFILE' # Start sl-lock-listener for graphical sessions on non-systemd systems. if [ ! -d /run/systemd/system ] && [ "$XDG_SESSION_CLASS" != "greeter" ]; then ( timeout=60 while [ "$timeout" -gt 0 ]; do if [ -n "$WAYLAND_DISPLAY" ] && [ -S "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" ]; then break fi sock=$(ls -1t "$XDG_RUNTIME_DIR"/wayland-* 2>/dev/null | head -n 1) if [ -n "$sock" ] && [ -S "$sock" ]; then export WAYLAND_DISPLAY="$(basename "$sock")" break fi sleep 1 timeout=$((timeout - 1)) done if [ -n "$WAYLAND_DISPLAY" ]; then sleep 1 /usr/bin/sl-lock-listener >/dev/null 2>&1 & fi ) & fi EOF_PROFILE chmod 644 %{buildroot}%{_sysconfdir}/profile.d/sl-lock-autostart.sh %post if ! getent passwd greeter >/dev/null 2>&1; then if command -v systemd-sysusers >/dev/null 2>&1 && [ -f /usr/lib/sysusers.d/greetd.conf ]; then systemd-sysusers /usr/lib/sysusers.d/greetd.conf || true fi fi if ! getent group greeter >/dev/null 2>&1; then groupadd -r greeter fi if ! getent passwd greeter >/dev/null 2>&1; then NOLOGIN="$(command -v nologin 2>/dev/null || printf '%s' /bin/false)" useradd \ -r \ -M \ -d /var/lib/greetd \ -s "$NOLOGIN" \ -g greeter \ greeter fi cat > /etc/greetd/config.toml <<'EOF_GREETD' [terminal] vt = 2 [default_session] command = "niri -c /etc/greetd/niri-greeter.kdl > /dev/null 2>&1" user = "greeter" EOF_GREETD mkdir -p /usr/local/share/backgrounds /etc/greetd/sl-greeter /etc/greetd/last-session /var/lib/greetd/.config if [ -e /usr/share/backgrounds/default.png ]; then ln -sf /usr/share/backgrounds/default.png /usr/local/share/backgrounds/sl-greeter-current-background fi ln -sf /usr/local/share/backgrounds/sl-greeter-current-background /etc/greetd/sl-greeter/current-background if getent passwd greeter >/dev/null 2>&1; then chown -R greeter:greeter /var/lib/greetd chown greeter:greeter /etc/greetd/last-session chmod 755 /etc/greetd/last-session fi if [ -f /etc/pam.d/greetd ] && ! grep -q 'pam_gnome_keyring\.so' /etc/pam.d/greetd; then echo 'auth optional pam_gnome_keyring.so' >> /etc/pam.d/greetd echo 'session optional pam_gnome_keyring.so auto_start' >> /etc/pam.d/greetd fi if [ -d /run/systemd/system ]; then systemctl daemon-reload || true systemctl enable sl-sleep-lock.service || true systemctl --global enable sl-lock-listener.service || true fi REAL_USER=${SUDO_USER:-$(awk -F ":" '$3 >= 1000 && $3 < 60000 && $6 ~ /^\/home\// {print $1; exit}' /etc/passwd)} if [ -n "$REAL_USER" ] && [ "$REAL_USER" != "root" ]; then USER_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6) if [ -n "$USER_HOME" ] && [ -d "$USER_HOME" ]; then mkdir -p "$USER_HOME/.local/bin" if [ ! -e "$USER_HOME/.local/bin/current-background" ] && [ ! -L "$USER_HOME/.local/bin/current-background" ]; then ln -s /usr/local/share/backgrounds/sl-greeter-current-background "$USER_HOME/.local/bin/current-background" fi chown -R "$REAL_USER:$REAL_USER" "$USER_HOME/.local" fi fi cat <<'EOF' ================================================================= sl-desktop-utils installed successfully! To use sl-lock with Niri, add the following to your config.kdl: // Idle timer and listener spawn-at-startup "sl-lock-listener" spawn-at-startup "sl-idle-lock" "300" // Add a keybind inside your binds { ... } block Mod+Alt+L { spawn "sl-lock"; } // Lock the screen when the laptop lid is closed switch-events { lid-closed { spawn "sl-lock"; } } To apply the new greetd configuration, restart greetd or reboot. ================================================================= EOF %postun if [ $1 -eq 0 ]; then if [ -d /run/systemd/system ]; then systemctl disable --now sl-sleep-lock.service >/dev/null 2>&1 || true systemctl --global disable sl-lock-listener.service >/dev/null 2>&1 || true systemctl daemon-reload >/dev/null 2>&1 || true fi fi %files %config(noreplace) %{_sysconfdir}/greetd/niri-greeter.kdl %dir %{_sysconfdir}/greetd/sl-greeter %{_bindir}/sl-session %{_bindir}/sl-lock %{_bindir}/sl-greeter %{_bindir}/sl-lock-listener %{_bindir}/sl-idle-lock %{_unitdir}/sl-sleep-lock.service %{_userunitdir}/sl-lock-listener.service %{_unitdir}/greetd.service.d/override.conf /usr/lib/elogind/system-sleep/10-sl-sleep-lock.sh %config(noreplace) %{_sysconfdir}/profile.d/sl-lock-autostart.sh