Switch hyprlock to QS
This commit is contained in:
@@ -169,12 +169,3 @@ New migration format:
|
|||||||
Some older migrations predate these rules. Do not copy older migrations that start with shebangs, omit the leading `echo`, or hard-code `~/.local/share/omarchy`.
|
Some older migrations predate these rules. Do not copy older migrations that start with shebangs, omit the leading `echo`, or hard-code `~/.local/share/omarchy`.
|
||||||
|
|
||||||
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for historical compatibility or one-off repair work.
|
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for historical compatibility or one-off repair work.
|
||||||
|
|
||||||
Example:
|
|
||||||
```bash
|
|
||||||
echo "Disable fingerprint in hyprlock if fingerprint auth is not configured"
|
|
||||||
|
|
||||||
if omarchy-cmd-missing fprintd-list || ! fprintd-list "$USER" 2>/dev/null | grep -q "finger"; then
|
|
||||||
sed -i 's/fingerprint:enabled = .*/fingerprint:enabled = false/' ~/.config/hypr/hyprlock.conf
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|||||||
Executable
+55
@@ -0,0 +1,55 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Show idle, screensaver, and lock diagnostics
|
||||||
|
# omarchy:group=debug
|
||||||
|
# omarchy:args=[log-lines]
|
||||||
|
# omarchy:examples=omarchy debug idle | omarchy-debug-idle 400
|
||||||
|
|
||||||
|
lines=${1:-200}
|
||||||
|
if [[ ! $lines =~ ^[0-9]+$ ]]; then
|
||||||
|
lines=200
|
||||||
|
fi
|
||||||
|
|
||||||
|
section() {
|
||||||
|
printf '\n== %s ==\n' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
section "Time"
|
||||||
|
date -Is
|
||||||
|
|
||||||
|
section "Idle IPC status"
|
||||||
|
omarchy-shell idle status 2>&1 | jq . 2>/dev/null || omarchy-shell idle status 2>&1 || true
|
||||||
|
|
||||||
|
section "Quickshell instances"
|
||||||
|
quickshell list -p "$OMARCHY_PATH/shell" --any-display 2>&1 || true
|
||||||
|
|
||||||
|
section "Recent idle logs"
|
||||||
|
quickshell --no-color log -p "$OMARCHY_PATH/shell" --any-display --tail "$lines" --log-times -r 'quickshell.wayland.idle_notify=true' 2>&1 \
|
||||||
|
| grep -Ei 'omarchy idle|idle_notify|screensaver|lock|error|warn|failed' || true
|
||||||
|
|
||||||
|
section "Relevant processes"
|
||||||
|
ps -eo pid=,args= \
|
||||||
|
| grep -E 'quickshell -n -p|dbus-monitor.*PrepareForSleep|org\.omarchy\.screensaver|omarchy-screensaver|(^|/| )tte( |$)' \
|
||||||
|
| grep -v grep || true
|
||||||
|
|
||||||
|
section "Hyprland screensaver clients"
|
||||||
|
hyprctl clients -j 2>/dev/null \
|
||||||
|
| jq -r '.[] | select(.class == "org.omarchy.screensaver" or .initialClass == "org.omarchy.screensaver") | [.pid,.class,.initialClass,.title,.focusHistoryID] | @tsv' || true
|
||||||
|
|
||||||
|
section "Idle inhibitors"
|
||||||
|
hyprctl clients -j 2>/dev/null \
|
||||||
|
| jq -r '.[] | select(.inhibitingIdle == true or ((.tags // []) | index("noidle"))) | [.pid,.class,.title,((.tags // []) | join(",")),.inhibitingIdle] | @tsv' || true
|
||||||
|
|
||||||
|
section "Screensaver detector"
|
||||||
|
if hyprctl clients -j 2>/dev/null | jq -e '.[] | select(.class == "org.omarchy.screensaver" or .initialClass == "org.omarchy.screensaver")' >/dev/null; then
|
||||||
|
echo "running-window"
|
||||||
|
elif pgrep -f '[o]rg.omarchy.screensaver' >/dev/null; then
|
||||||
|
echo "running-process"
|
||||||
|
elif omarchy-toggle-enabled screensaver-off; then
|
||||||
|
echo "disabled"
|
||||||
|
else
|
||||||
|
echo "stopped"
|
||||||
|
fi
|
||||||
|
|
||||||
|
section "Lock detector"
|
||||||
|
omarchy-shell lock status 2>&1 | jq . 2>/dev/null || omarchy-shell lock status 2>&1 || true
|
||||||
@@ -26,8 +26,6 @@ if [[ -n $font_name ]]; then
|
|||||||
sed -i "s/^font=.*/font=$font_name:size=9/g" ~/.config/foot/foot.ini
|
sed -i "s/^font=.*/font=$font_name:size=9/g" ~/.config/foot/foot.ini
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sed -i "s/font_family = .*/font_family = $font_name/g" ~/.config/hypr/hyprlock.conf
|
|
||||||
|
|
||||||
# fontconfig is the canonical source of truth — the omarchy shell, Qt
|
# fontconfig is the canonical source of truth — the omarchy shell, Qt
|
||||||
# apps, and anything else that resolves "monospace" all read from here.
|
# apps, and anything else that resolves "monospace" all read from here.
|
||||||
xmlstarlet ed -L \
|
xmlstarlet ed -L \
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# omarchy:summary=Open a config file in the user's editor and surface a toast
|
# omarchy:summary=Open a config file in the user's editor and surface a toast
|
||||||
# omarchy:args=<path>
|
# omarchy:args=<path>
|
||||||
# omarchy:examples=omarchy launch config-editor ~/.config/hypr/hyprlock.conf
|
# omarchy:examples=omarchy launch config-editor ~/.config/hypr/hyprland.lua
|
||||||
|
|
||||||
path="${1-}"
|
path="${1-}"
|
||||||
|
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ if [[ -z $config_file ]]; then
|
|||||||
Usage: $0 [config_file]
|
Usage: $0 [config_file]
|
||||||
|
|
||||||
Must provide a file path from the .config directory to be refreshed.
|
Must provide a file path from the .config directory to be refreshed.
|
||||||
To copy ~/.local/share/omarchy/config/hypr/hyprlock.conf to ~/.config/hypr/hyprlock.conf
|
To copy ~/.local/share/omarchy/config/hypr/hyprland.lua to ~/.config/hypr/hyprland.lua
|
||||||
|
|
||||||
$0 hypr/hyprlock.conf
|
$0 hypr/hyprland.lua
|
||||||
USAGE
|
USAGE
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Backup the destination file (with timestamp) to avoid clobbering (Ex: hyprlock.conf.bak.1753817951)
|
# Backup the destination file (with timestamp) to avoid clobbering (Ex: hyprland.lua.bak.1753817951)
|
||||||
user_config_file="${HOME}/.config/$config_file"
|
user_config_file="${HOME}/.config/$config_file"
|
||||||
default_config_file="$OMARCHY_PATH/config/$config_file"
|
default_config_file="$OMARCHY_PATH/config/$config_file"
|
||||||
backup_config_file="$user_config_file.bak.$(date +%s)"
|
backup_config_file="$user_config_file.bak.$(date +%s)"
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Overwrite the user config for hyprlock with the Omarchy default.
|
|
||||||
|
|
||||||
omarchy-refresh-config hypr/hyprlock.conf
|
|
||||||
@@ -20,16 +20,18 @@ remove_pam_config() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_hyprlock_fingerprint_icon() {
|
remove_lock_fingerprint_pam() {
|
||||||
echo "Removing fingerprint icon from hyprlock placeholder text..."
|
if [[ -f /etc/pam.d/omarchy-lock-fingerprint ]]; then
|
||||||
sed -i 's/placeholder_text = .*/placeholder_text = Enter Password/' ~/.config/hypr/hyprlock.conf
|
echo "Removing lock screen fingerprint authentication..."
|
||||||
sed -i 's/fingerprint:enabled = .*/fingerprint:enabled = false/' ~/.config/hypr/hyprlock.conf
|
sudo rm -f /etc/pam.d/omarchy-lock-fingerprint
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
echo -e "\e[32mRemoving fingerprint scanner from authentication.\n\e[0m"
|
echo -e "\e[32mRemoving fingerprint scanner from authentication.\n\e[0m"
|
||||||
|
|
||||||
remove_pam_config
|
remove_pam_config
|
||||||
remove_hyprlock_fingerprint_icon
|
remove_lock_fingerprint_pam
|
||||||
|
|
||||||
echo "Removing fingerprint packages..."
|
echo "Removing fingerprint packages..."
|
||||||
omarchy-pkg-drop fprintd libfprint-git
|
omarchy-pkg-drop fprintd libfprint-git
|
||||||
|
|||||||
@@ -5,6 +5,6 @@
|
|||||||
|
|
||||||
CONFIG_DIR="$OMARCHY_PATH/shell"
|
CONFIG_DIR="$OMARCHY_PATH/shell"
|
||||||
|
|
||||||
if ! quickshell reload -p "$CONFIG_DIR" >/dev/null 2>&1; then
|
quickshell kill -p "$CONFIG_DIR" --any-display >/dev/null 2>&1 || true
|
||||||
setsid quickshell -n -p "$CONFIG_DIR" >/dev/null 2>&1 &
|
sleep 0.2
|
||||||
fi
|
setsid quickshell -n -p "$CONFIG_DIR" >/dev/null 2>&1 &
|
||||||
|
|||||||
Executable
+62
@@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Configure Quickshell lock screen authentication
|
||||||
|
# omarchy:group=setup
|
||||||
|
# omarchy:name=lock
|
||||||
|
# omarchy:requires-sudo=true
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
target_user=${SUDO_USER:-}
|
||||||
|
if [[ -z $target_user && -n ${PKEXEC_UID:-} ]]; then
|
||||||
|
target_user=$(getent passwd "$PKEXEC_UID" | cut -d: -f1)
|
||||||
|
fi
|
||||||
|
target_user=${target_user:-$USER}
|
||||||
|
target_home=$(getent passwd "$target_user" | cut -d: -f6)
|
||||||
|
target_group=$(id -gn "$target_user" 2>/dev/null || echo "$target_user")
|
||||||
|
|
||||||
|
as_root() {
|
||||||
|
if (( EUID == 0 )); then
|
||||||
|
"$@"
|
||||||
|
else
|
||||||
|
sudo "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
tee_root() {
|
||||||
|
local path="$1"
|
||||||
|
|
||||||
|
if (( EUID == 0 )); then
|
||||||
|
tee "$path"
|
||||||
|
else
|
||||||
|
sudo tee "$path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Configuring lock screen password authentication..."
|
||||||
|
|
||||||
|
tee_root /etc/pam.d/omarchy-lock-password >/dev/null <<'EOF'
|
||||||
|
#%PAM-1.0
|
||||||
|
auth required pam_faillock.so preauth silent deny=10 unlock_time=120
|
||||||
|
-auth [success=2 default=ignore] pam_systemd_home.so
|
||||||
|
auth [success=1 default=bad] pam_unix.so try_first_pass nullok
|
||||||
|
auth [default=die] pam_faillock.so authfail deny=10 unlock_time=120
|
||||||
|
auth optional pam_permit.so
|
||||||
|
auth required pam_env.so
|
||||||
|
auth required pam_faillock.so authsucc
|
||||||
|
account include system-local-login
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if omarchy-cmd-present fprintd-list && fprintd-list "$target_user" 2>/dev/null | grep -qi finger; then
|
||||||
|
echo "Configuring lock screen fingerprint authentication..."
|
||||||
|
tee_root /etc/pam.d/omarchy-lock-fingerprint >/dev/null <<'EOF'
|
||||||
|
#%PAM-1.0
|
||||||
|
auth required pam_fprintd.so
|
||||||
|
account include system-local-login
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
as_root rm -f /etc/pam.d/omarchy-lock-fingerprint
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
omarchy-shell lock status >/dev/null 2>&1 && echo "Lock screen authentication configured."
|
||||||
@@ -42,12 +42,16 @@ EOF
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
add_hyprlock_fingerprint_icon() {
|
setup_lock_fingerprint_pam() {
|
||||||
echo "Adding fingerprint icon to hyprlock placeholder text..."
|
echo "Configuring lock screen for fingerprint authentication..."
|
||||||
sed -i 's/placeholder_text = .*/placeholder_text = <span> Enter Password <\/span>/' ~/.config/hypr/hyprlock.conf
|
sudo tee /etc/pam.d/omarchy-lock-fingerprint >/dev/null <<'EOF'
|
||||||
sed -i 's/fingerprint:enabled = .*/fingerprint:enabled = true/' ~/.config/hypr/hyprlock.conf
|
#%PAM-1.0
|
||||||
|
auth required pam_fprintd.so
|
||||||
|
account include system-local-login
|
||||||
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
echo -e "\e[32mSetting up fingerprint scanner for authentication.\n\e[0m"
|
echo -e "\e[32mSetting up fingerprint scanner for authentication.\n\e[0m"
|
||||||
|
|
||||||
# Install required packages
|
# Install required packages
|
||||||
@@ -71,9 +75,6 @@ fi
|
|||||||
# Configure PAM
|
# Configure PAM
|
||||||
setup_pam_config
|
setup_pam_config
|
||||||
|
|
||||||
# Add fingerprint icon to hyprlock placeholder text
|
|
||||||
add_hyprlock_fingerprint_icon
|
|
||||||
|
|
||||||
# Enroll first fingerprint
|
# Enroll first fingerprint
|
||||||
echo -e "\e[32m\nLet's setup your right index finger as the first fingerprint.\e[0m"
|
echo -e "\e[32m\nLet's setup your right index finger as the first fingerprint.\e[0m"
|
||||||
echo -e "Keep moving the finger around on sensor until the process completes.\n"
|
echo -e "Keep moving the finger around on sensor until the process completes.\n"
|
||||||
@@ -84,8 +85,9 @@ if sudo fprintd-enroll "$USER"; then
|
|||||||
# Verify
|
# Verify
|
||||||
echo -e "\nNow let's verify that it's working correctly.\n"
|
echo -e "\nNow let's verify that it's working correctly.\n"
|
||||||
if fprintd-verify; then
|
if fprintd-verify; then
|
||||||
|
setup_lock_fingerprint_pam
|
||||||
echo -e "\e[32m\nPerfect! Fingerprint authentication is now configured.\e[0m"
|
echo -e "\e[32m\nPerfect! Fingerprint authentication is now configured.\e[0m"
|
||||||
echo "You can use your fingerprint for sudo, polkit, and lock screen (Super + Escape)."
|
echo "You can use your fingerprint for sudo, polkit, and lock screen (Super + Ctrl + L)."
|
||||||
else
|
else
|
||||||
echo -e "\e[31m\nVerification failed. You may want to try enrolling again.\e[0m"
|
echo -e "\e[31m\nVerification failed. You may want to try enrolling again.\e[0m"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Set Hyprland, Hyprlock, and Walker corners to sharp or round (the shell mirrors Hyprland)
|
# omarchy:summary=Set Hyprland and Walker corners to sharp or round (the shell mirrors Hyprland)
|
||||||
# omarchy:args=<sharp|round>
|
# omarchy:args=<sharp|round>
|
||||||
# omarchy:examples=omarchy style corners round | omarchy style corners sharp
|
# omarchy:examples=omarchy style corners round | omarchy style corners sharp
|
||||||
|
|
||||||
@@ -14,7 +14,6 @@ fi
|
|||||||
# state file is written. The old omarchy-style-corners-quickshell shim is
|
# state file is written. The old omarchy-style-corners-quickshell shim is
|
||||||
# kept as a no-op so external callers don't error.
|
# kept as a no-op so external callers don't error.
|
||||||
omarchy-style-corners-hyprland "$1"
|
omarchy-style-corners-hyprland "$1"
|
||||||
omarchy-style-corners-hyprlock "$1"
|
|
||||||
omarchy-style-corners-walker "$1"
|
omarchy-style-corners-walker "$1"
|
||||||
|
|
||||||
case $1 in
|
case $1 in
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Set or toggle rounded Hyprlock input field corners
|
|
||||||
# omarchy:args=[toggle|sharp|round]
|
|
||||||
# omarchy:examples=omarchy style corners hyprlock toggle | omarchy style corners hyprlock round | omarchy style corners hyprlock sharp
|
|
||||||
|
|
||||||
TOGGLES_CONFIG="$HOME/.local/state/omarchy/toggles/hyprlock.conf"
|
|
||||||
|
|
||||||
set_rounding() {
|
|
||||||
local radius="$1"
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "$TOGGLES_CONFIG")"
|
|
||||||
|
|
||||||
cat >"$TOGGLES_CONFIG" <<EOF
|
|
||||||
input-field {
|
|
||||||
rounding = $radius
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
case "${1:-toggle}" in
|
|
||||||
round) set_rounding 6 ;;
|
|
||||||
sharp) set_rounding 0 ;;
|
|
||||||
toggle)
|
|
||||||
if [[ -f $TOGGLES_CONFIG ]] && grep -q '^ rounding = 6$' "$TOGGLES_CONFIG"; then
|
|
||||||
set_rounding 0
|
|
||||||
else
|
|
||||||
set_rounding 6
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: omarchy-style-corners-hyprlock [toggle|sharp|round]"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@@ -5,12 +5,7 @@
|
|||||||
# omarchy:name=lock
|
# omarchy:name=lock
|
||||||
# omarchy:examples=omarchy system lock
|
# omarchy:examples=omarchy system lock
|
||||||
|
|
||||||
if ! pidof hyprlock >/dev/null; then
|
omarchy-shell lock lock >/dev/null
|
||||||
(
|
|
||||||
hyprlock
|
|
||||||
omarchy-system-wake
|
|
||||||
) &
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set keyboard layout to default (first layout)
|
# Set keyboard layout to default (first layout)
|
||||||
hyprctl switchxkblayout all 0 > /dev/null 2>&1
|
hyprctl switchxkblayout all 0 > /dev/null 2>&1
|
||||||
@@ -21,12 +16,12 @@ if pgrep -x "1password" >/dev/null; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Avoid running screensaver when locked
|
# Avoid running screensaver when locked
|
||||||
pkill -f org.omarchy.screensaver
|
pkill -f '[o]rg.omarchy.screensaver'
|
||||||
|
|
||||||
if [[ ${OMARCHY_LOCK_ONLY:-false} != "true" ]]; then
|
if [[ ${OMARCHY_LOCK_ONLY:-false} != "true" ]]; then
|
||||||
(
|
(
|
||||||
sleep 3
|
sleep 3
|
||||||
pidof hyprlock >/dev/null || exit 0
|
[[ $(omarchy-shell lock isLocked 2>/dev/null) == "true" ]] || exit 0
|
||||||
omarchy-brightness-keyboard off
|
omarchy-brightness-keyboard off
|
||||||
omarchy-brightness-display off
|
omarchy-brightness-display off
|
||||||
) &
|
) &
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
source = ~/.config/omarchy/current/theme/hyprlock.conf
|
|
||||||
|
|
||||||
general {
|
|
||||||
ignore_empty_input = true
|
|
||||||
}
|
|
||||||
|
|
||||||
background {
|
|
||||||
monitor =
|
|
||||||
color = $color
|
|
||||||
path = ~/.config/omarchy/current/background
|
|
||||||
blur_passes = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
animations {
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
input-field {
|
|
||||||
monitor =
|
|
||||||
size = 650, 100
|
|
||||||
position = 0, 0
|
|
||||||
halign = center
|
|
||||||
valign = center
|
|
||||||
|
|
||||||
inner_color = $inner_color
|
|
||||||
outer_color = $outer_color
|
|
||||||
outline_thickness = 4
|
|
||||||
|
|
||||||
font_family = JetBrainsMono Nerd Font
|
|
||||||
font_color = $font_color
|
|
||||||
|
|
||||||
placeholder_text = Enter Password
|
|
||||||
check_color = $check_color
|
|
||||||
fail_text = <i>$FAIL ($ATTEMPTS)</i>
|
|
||||||
|
|
||||||
rounding = 0
|
|
||||||
shadow_passes = 0
|
|
||||||
fade_on_empty = false
|
|
||||||
}
|
|
||||||
|
|
||||||
auth {
|
|
||||||
fingerprint:enabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
source = ~/.local/state/omarchy/toggles/hyprlock.conf
|
|
||||||
@@ -136,7 +136,7 @@ Run `omarchy --help` for the full list. The most common groups:
|
|||||||
├── looknfeel.conf # Appearance (gaps, borders, animations)
|
├── looknfeel.conf # Appearance (gaps, borders, animations)
|
||||||
├── envs.conf # Environment variables
|
├── envs.conf # Environment variables
|
||||||
├── autostart.conf # Startup applications
|
├── autostart.conf # Startup applications
|
||||||
├── hyprlock.conf # Lock screen appearance and auth
|
├── shell.json # Omarchy shell, bar, idle, and lock settings
|
||||||
└── hyprsunset.conf # Night light / blue light filter
|
└── hyprsunset.conf # Night light / blue light filter
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ omarchy refresh <app>
|
|||||||
|
|
||||||
# Refresh specific config file
|
# Refresh specific config file
|
||||||
# config-file path is relative to ~/.config/
|
# config-file path is relative to ~/.config/
|
||||||
# eg. `omarchy refresh config hypr/hyprlock.conf` will refresh ~/.config/hypr/hyprlock.conf
|
# eg. `omarchy refresh config hypr/hyprland.lua` will refresh ~/.config/hypr/hyprland.lua
|
||||||
omarchy refresh config <config-file>
|
omarchy refresh config <config-file>
|
||||||
|
|
||||||
# Full reinstall of configs (nuclear option)
|
# Full reinstall of configs (nuclear option)
|
||||||
|
|||||||
@@ -162,7 +162,6 @@
|
|||||||
"setup.security.fingerprint": {"icon":"","label":"Fingerprint","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fingerprint"},
|
"setup.security.fingerprint": {"icon":"","label":"Fingerprint","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fingerprint"},
|
||||||
"setup.security.fido2": {"icon":"","label":"Fido2","keywords":"key","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fido2"},
|
"setup.security.fido2": {"icon":"","label":"Fido2","keywords":"key","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-security-fido2"},
|
||||||
"setup.config.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/hyprland.lua\""},
|
"setup.config.hyprland": {"icon":"","label":"Hyprland","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/hyprland.lua\""},
|
||||||
"setup.config.hyprlock": {"icon":"","label":"Hyprlock","keywords":"lock","action":"omarchy-launch-config-editor ~/.config/hypr/hyprlock.conf"},
|
|
||||||
"setup.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"night light","action":"omarchy-launch-config-editor ~/.config/hypr/hyprsunset.conf && omarchy-restart-hyprsunset"},
|
"setup.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"night light","action":"omarchy-launch-config-editor ~/.config/hypr/hyprsunset.conf && omarchy-restart-hyprsunset"},
|
||||||
"setup.config.walker": {"icon":"","label":"Walker","keywords":"launcher","action":"omarchy-launch-config-editor ~/.config/walker/config.toml && omarchy-restart-walker"},
|
"setup.config.walker": {"icon":"","label":"Walker","keywords":"launcher","action":"omarchy-launch-config-editor ~/.config/walker/config.toml && omarchy-restart-walker"},
|
||||||
"setup.config.bar": {"icon":"","label":"Bar","keywords":"quickshell shell config settings widgets position","action":"omarchy-launch-bar-settings"},
|
"setup.config.bar": {"icon":"","label":"Bar","keywords":"quickshell shell config settings widgets position","action":"omarchy-launch-bar-settings"},
|
||||||
@@ -313,7 +312,6 @@
|
|||||||
"update.process.walker": {"icon":"","label":"Walker","keywords":"restart launcher","action":"omarchy-restart-walker"},
|
"update.process.walker": {"icon":"","label":"Walker","keywords":"restart launcher","action":"omarchy-restart-walker"},
|
||||||
"update.process.shell": {"icon":"","label":"Shell","keywords":"restart bar quickshell omarchy-shell","action":"omarchy-restart-shell"},
|
"update.process.shell": {"icon":"","label":"Shell","keywords":"restart bar quickshell omarchy-shell","action":"omarchy-restart-shell"},
|
||||||
"update.config.hyprland": {"icon":"","label":"Hyprland","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-hyprland"},
|
"update.config.hyprland": {"icon":"","label":"Hyprland","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-hyprland"},
|
||||||
"update.config.hyprlock": {"icon":"","label":"Hyprlock","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-hyprlock"},
|
|
||||||
"update.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-hyprsunset"},
|
"update.config.hyprsunset": {"icon":"","label":"Hyprsunset","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-hyprsunset"},
|
||||||
"update.config.plymouth": {"icon":"","label":"Plymouth","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-plymouth"},
|
"update.config.plymouth": {"icon":"","label":"Plymouth","keywords":"refresh","action":"omarchy-launch-floating-terminal-with-presentation omarchy-refresh-plymouth"},
|
||||||
"update.config.osd": {"icon":"","label":"OSD","keywords":"refresh","action":"omarchy-restart-shell"},
|
"update.config.osd": {"icon":"","label":"OSD","keywords":"refresh","action":"omarchy-restart-shell"},
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
$color = rgba({{ background_rgb }}, 1.0)
|
|
||||||
$inner_color = rgba({{ background_rgb }}, 0.8)
|
|
||||||
$outer_color = rgba({{ foreground_rgb }}, 1.0)
|
|
||||||
$font_color = rgba({{ foreground_rgb }}, 1.0)
|
|
||||||
$check_color = rgba({{ accent_rgb }}, 1.0)
|
|
||||||
@@ -6,6 +6,7 @@ run_logged $OMARCHY_INSTALL/config/gpg.sh
|
|||||||
run_logged $OMARCHY_INSTALL/config/timezones.sh
|
run_logged $OMARCHY_INSTALL/config/timezones.sh
|
||||||
run_logged $OMARCHY_INSTALL/config/increase-sudo-tries.sh
|
run_logged $OMARCHY_INSTALL/config/increase-sudo-tries.sh
|
||||||
run_logged $OMARCHY_INSTALL/config/increase-lockout-limit.sh
|
run_logged $OMARCHY_INSTALL/config/increase-lockout-limit.sh
|
||||||
|
run_logged $OMARCHY_INSTALL/config/lockscreen-pam.sh
|
||||||
run_logged $OMARCHY_INSTALL/config/ssh-flakiness.sh
|
run_logged $OMARCHY_INSTALL/config/ssh-flakiness.sh
|
||||||
run_logged $OMARCHY_INSTALL/config/increase-file-watchers.sh
|
run_logged $OMARCHY_INSTALL/config/increase-file-watchers.sh
|
||||||
run_logged $OMARCHY_INSTALL/config/increase-fd-limit.sh
|
run_logged $OMARCHY_INSTALL/config/increase-fd-limit.sh
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
echo "Defaults passwd_tries=10" | sudo tee /etc/sudoers.d/passwd-tries
|
echo "Defaults passwd_tries=10" | sudo tee /etc/sudoers.d/passwd-tries
|
||||||
sudo chmod 440 /etc/sudoers.d/passwd-tries
|
sudo chmod 440 /etc/sudoers.d/passwd-tries
|
||||||
|
|
||||||
# Set for hyprlock too
|
# Set for the lock screen too
|
||||||
sudo sed -i 's/^# *deny = .*/deny = 10/' /etc/security/faillock.conf
|
sudo sed -i 's/^# *deny = .*/deny = 10/' /etc/security/faillock.conf
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
omarchy-setup-lock
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# Make sure toggles are available
|
# Make sure toggles are available
|
||||||
mkdir -p ~/.local/state/omarchy/toggles
|
mkdir -p ~/.local/state/omarchy/toggles
|
||||||
touch ~/.local/state/omarchy/toggles/hyprlock.conf
|
|
||||||
touch ~/.local/state/omarchy/toggles/walker.css
|
touch ~/.local/state/omarchy/toggles/walker.css
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ gvfs-smb
|
|||||||
hyprland
|
hyprland
|
||||||
hyprland-guiutils
|
hyprland-guiutils
|
||||||
hyprland-preview-share-picker
|
hyprland-preview-share-picker
|
||||||
hyprlock
|
|
||||||
hyprpicker
|
hyprpicker
|
||||||
hyprsunset
|
hyprsunset
|
||||||
imagemagick
|
imagemagick
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
echo "Update Hyprlock with better placeholder position and show all fail text"
|
|
||||||
|
|
||||||
omarchy-refresh-hyprlock
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
echo "Update hyprlock font to match current system font"
|
|
||||||
|
|
||||||
font_name=$(omarchy-font-current)
|
|
||||||
|
|
||||||
if [[ -n $font_name ]]; then
|
|
||||||
cp ~/.config/hypr/hyprlock.conf ~/.config/hypr/hyprlock.conf.bak.$(date +%s)
|
|
||||||
|
|
||||||
echo "Found font '$font_name', updating hyprlock"
|
|
||||||
sed -i "s/font_family = .*/font_family = $font_name/g" ~/.config/hypr/hyprlock.conf
|
|
||||||
else
|
|
||||||
echo "No font found, skipping migration"
|
|
||||||
fi
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
echo "Update hyprlock placeholder text based on fingerprint setup status"
|
|
||||||
|
|
||||||
cp ~/.config/hypr/hyprlock.conf ~/.config/hypr/hyprlock.conf.bak.$(date +%s)
|
|
||||||
|
|
||||||
# Check if fprintd is installed and has enrolled fingerprints
|
|
||||||
if command -v fprintd-list &>/dev/null && fprintd-list "$USER" 2>/dev/null | grep -q "Fingerprints for user"; then
|
|
||||||
echo "Fingerprint detected, updating placeholder text with fingerprint icon"
|
|
||||||
sed -i 's/placeholder_text = .*/placeholder_text = <span> Enter Password <\/span>/' ~/.config/hypr/hyprlock.conf
|
|
||||||
else
|
|
||||||
echo "No fingerprint enrolled, updating placeholder text without fingerprint icon"
|
|
||||||
sed -i 's/placeholder_text = .*/placeholder_text = Enter Password/' ~/.config/hypr/hyprlock.conf
|
|
||||||
fi
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
echo "Ignore empty passwords on lock screen"
|
|
||||||
|
|
||||||
if ! grep -q "ignore_empty_input" ~/.config/hypr/hyprlock.conf; then
|
|
||||||
sed -i "/source =/a\ \ngeneral {\n ignore_empty_input = true\n}" ~/.config/hypr/hyprlock.conf
|
|
||||||
fi
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
echo "Disable fingerprint in hyprlock if fingerprint auth is not configured"
|
|
||||||
|
|
||||||
if omarchy-cmd-missing fprintd-list || ! fprintd-list "$USER" 2>/dev/null | grep -q "finger"; then
|
|
||||||
sed -i 's/fingerprint:enabled = .*/fingerprint:enabled = false/' ~/.config/hypr/hyprlock.conf
|
|
||||||
fi
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
echo "Switch lock screen authentication to Quickshell"
|
||||||
|
|
||||||
|
omarchy-setup-lock
|
||||||
|
|
||||||
|
rm -f ~/.local/state/omarchy/toggles/hyprlock.conf ~/.local/state/omarchy/toggles/lock.conf
|
||||||
|
|
||||||
|
rm -f ~/.config/hypr/hyprlock.conf ~/.config/omarchy/current/theme/hyprlock.conf
|
||||||
|
|
||||||
|
omarchy-pkg-drop hyprlock
|
||||||
@@ -19,6 +19,7 @@ User-installed plugins live alongside these conceptually but on disk under
|
|||||||
| Omarchy menu | `omarchy.menu` | `menu` | `menu/Menu.qml` |
|
| Omarchy menu | `omarchy.menu` | `menu` | `menu/Menu.qml` |
|
||||||
| Notifications | `omarchy.notifications` | `service` | `notifications/Service.qml` |
|
| Notifications | `omarchy.notifications` | `service` | `notifications/Service.qml` |
|
||||||
| Idle monitor | `omarchy.idle` | `service` | `idle/Service.qml` |
|
| Idle monitor | `omarchy.idle` | `service` | `idle/Service.qml` |
|
||||||
|
| Lock screen | `omarchy.lock` | `service` | `lock/Service.qml` |
|
||||||
| OSD | `omarchy.osd` | `panel` | `osd/Osd.qml` |
|
| OSD | `omarchy.osd` | `panel` | `osd/Osd.qml` |
|
||||||
| Polkit agent | `omarchy.polkit` | `service` | `polkit/PolkitAgent.qml` |
|
| Polkit agent | `omarchy.polkit` | `service` | `polkit/PolkitAgent.qml` |
|
||||||
|
|
||||||
@@ -69,6 +70,14 @@ clears it without writing a selection.
|
|||||||
The plugin has `keepLoaded: true` so the layer-shell window survives
|
The plugin has `keepLoaded: true` so the layer-shell window survives
|
||||||
between summons within a single shell session.
|
between summons within a single shell session.
|
||||||
|
|
||||||
|
## Lock screen
|
||||||
|
|
||||||
|
Session-lock surface using Quickshell's native `WlSessionLock` and two
|
||||||
|
separate PAM services: `omarchy-lock-password` for password auth and,
|
||||||
|
only when fingerprints are enrolled, `omarchy-lock-fingerprint` for
|
||||||
|
fingerprint auth. It mirrors the previous lock screen field dimensions,
|
||||||
|
colors, blurred wallpaper, placeholder, and corner toggle.
|
||||||
|
|
||||||
## Polkit agent
|
## Polkit agent
|
||||||
|
|
||||||
Theme-aware authentication dialog for privileged actions. It uses
|
Theme-aware authentication dialog for privileged actions. It uses
|
||||||
|
|||||||
+131
-32
@@ -21,6 +21,11 @@ Item {
|
|||||||
|
|
||||||
property bool idledThisCycle: false
|
property bool idledThisCycle: false
|
||||||
property bool screensaverStartedThisCycle: false
|
property bool screensaverStartedThisCycle: false
|
||||||
|
property string lastEvent: "starting"
|
||||||
|
property string lastEventAt: ""
|
||||||
|
property string lastScreensaverState: "unknown"
|
||||||
|
property string lastScreensaverCheckAt: ""
|
||||||
|
property int screensaverCheckCount: 0
|
||||||
|
|
||||||
PersistentProperties {
|
PersistentProperties {
|
||||||
id: persisted
|
id: persisted
|
||||||
@@ -34,8 +39,23 @@ Item {
|
|||||||
return Math.floor(n)
|
return Math.floor(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
function runProcess(process, command) {
|
function nowIso() {
|
||||||
if (process.running) return false
|
return new Date().toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
|
function logEvent(event, details) {
|
||||||
|
var suffix = details === undefined || details === null || details === "" ? "" : ": " + String(details)
|
||||||
|
root.lastEventAt = nowIso()
|
||||||
|
root.lastEvent = event + suffix
|
||||||
|
console.log("omarchy idle " + root.lastEventAt + " " + root.lastEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
function runProcess(process, label, command) {
|
||||||
|
if (process.running) {
|
||||||
|
logEvent("process-skip", label + " already running")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
logEvent("process-start", label + " " + command)
|
||||||
process.command = ["bash", "-lc", command]
|
process.command = ["bash", "-lc", command]
|
||||||
process.running = true
|
process.running = true
|
||||||
return true
|
return true
|
||||||
@@ -43,21 +63,27 @@ Item {
|
|||||||
|
|
||||||
function launchScreensaver() {
|
function launchScreensaver() {
|
||||||
root.screensaverStartedThisCycle = true
|
root.screensaverStartedThisCycle = true
|
||||||
runProcess(screensaverProcess, "pidof hyprlock >/dev/null || omarchy-launch-screensaver")
|
screensaverResumePollTimer.restart()
|
||||||
|
runProcess(screensaverProcess, "screensaver", "[[ $(omarchy-shell lock isLocked 2>/dev/null) == \"true\" ]] || omarchy-launch-screensaver")
|
||||||
}
|
}
|
||||||
|
|
||||||
function lockSystem() {
|
function lockSystem(reason) {
|
||||||
|
logEvent("lock-system", reason || "requested")
|
||||||
screensaverTimer.stop()
|
screensaverTimer.stop()
|
||||||
lockTimer.stop()
|
lockTimer.stop()
|
||||||
screensaverResumePollTimer.stop()
|
screensaverResumePollTimer.stop()
|
||||||
root.idledThisCycle = false
|
root.idledThisCycle = false
|
||||||
root.screensaverStartedThisCycle = false
|
root.screensaverStartedThisCycle = false
|
||||||
runProcess(lockProcess, "omarchy-system-lock")
|
runProcess(lockProcess, "lock", "omarchy-system-lock")
|
||||||
}
|
}
|
||||||
|
|
||||||
function startIdleCycle() {
|
function startIdleCycle() {
|
||||||
if (root.idledThisCycle) return
|
if (root.idledThisCycle) {
|
||||||
|
logEvent("idle-cycle-already-running")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logEvent("idle-cycle-start", "screensaver=" + root.screensaverTimeoutSeconds + " lock=" + root.lockTimeoutSeconds)
|
||||||
root.idledThisCycle = true
|
root.idledThisCycle = true
|
||||||
root.screensaverStartedThisCycle = false
|
root.screensaverStartedThisCycle = false
|
||||||
screensaverResumePollTimer.stop()
|
screensaverResumePollTimer.stop()
|
||||||
@@ -65,16 +91,17 @@ Item {
|
|||||||
if (root.screensaverDelaySeconds === 0) launchScreensaver()
|
if (root.screensaverDelaySeconds === 0) launchScreensaver()
|
||||||
else screensaverTimer.restart()
|
else screensaverTimer.restart()
|
||||||
|
|
||||||
if (root.lockDelaySeconds === 0) lockSystem()
|
if (root.lockDelaySeconds === 0) lockSystem("lock-timeout-immediate")
|
||||||
else lockTimer.restart()
|
else lockTimer.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelIdleCycle() {
|
function cancelIdleCycle(reason) {
|
||||||
|
logEvent("idle-cycle-cancel", reason || "requested")
|
||||||
screensaverTimer.stop()
|
screensaverTimer.stop()
|
||||||
lockTimer.stop()
|
lockTimer.stop()
|
||||||
screensaverResumePollTimer.stop()
|
screensaverResumePollTimer.stop()
|
||||||
|
|
||||||
if (root.idledThisCycle) runProcess(wakeProcess, "omarchy-system-wake")
|
if (root.idledThisCycle) runProcess(wakeProcess, "wake", "omarchy-system-wake")
|
||||||
|
|
||||||
root.idledThisCycle = false
|
root.idledThisCycle = false
|
||||||
root.screensaverStartedThisCycle = false
|
root.screensaverStartedThisCycle = false
|
||||||
@@ -83,7 +110,9 @@ Item {
|
|||||||
function checkScreensaverAfterActiveSignal() {
|
function checkScreensaverAfterActiveSignal() {
|
||||||
if (!root.idledThisCycle || !root.screensaverStartedThisCycle) return
|
if (!root.idledThisCycle || !root.screensaverStartedThisCycle) return
|
||||||
if (screensaverCheckProcess.running) return
|
if (screensaverCheckProcess.running) return
|
||||||
screensaverCheckProcess.command = ["bash", "-lc", "pgrep -f org.omarchy.screensaver >/dev/null && echo running || echo stopped"]
|
root.lastScreensaverState = "checking"
|
||||||
|
root.lastScreensaverCheckAt = nowIso()
|
||||||
|
screensaverCheckProcess.command = ["bash", "-lc", "if hyprctl clients -j 2>/dev/null | jq -e '.[] | select(.class == \"org.omarchy.screensaver\" or .initialClass == \"org.omarchy.screensaver\")' >/dev/null; then echo running-window; elif pgrep -f '[o]rg.omarchy.screensaver' >/dev/null; then echo running-process; elif omarchy-toggle-enabled screensaver-off; then echo disabled; else echo stopped; fi"]
|
||||||
screensaverCheckProcess.running = true
|
screensaverCheckProcess.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,14 +123,16 @@ Item {
|
|||||||
// the lock timer running while the screensaver is still alive so the lock
|
// the lock timer running while the screensaver is still alive so the lock
|
||||||
// deadline remains `idle.lock` seconds from the original user idle time.
|
// deadline remains `idle.lock` seconds from the original user idle time.
|
||||||
if (root.screensaverStartedThisCycle) {
|
if (root.screensaverStartedThisCycle) {
|
||||||
|
logEvent("idle-monitor-active", "screensaver cycle remains armed")
|
||||||
screensaverResumePollTimer.restart()
|
screensaverResumePollTimer.restart()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelIdleCycle()
|
cancelIdleCycle("activity")
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleIdleChanged() {
|
function handleIdleChanged() {
|
||||||
|
logEvent("idle-monitor", idleMonitor.isIdle ? "idle" : "active")
|
||||||
if (!root.idleEnabled) return
|
if (!root.idleEnabled) return
|
||||||
|
|
||||||
if (idleMonitor.isIdle) startIdleCycle()
|
if (idleMonitor.isIdle) startIdleCycle()
|
||||||
@@ -113,9 +144,31 @@ Item {
|
|||||||
enabled: root.idleEnabled,
|
enabled: root.idleEnabled,
|
||||||
idle: idleMonitor.isIdle,
|
idle: idleMonitor.isIdle,
|
||||||
inIdleCycle: root.idledThisCycle,
|
inIdleCycle: root.idledThisCycle,
|
||||||
|
screensaverStarted: root.screensaverStartedThisCycle,
|
||||||
sleepMonitor: sleepMonitorProcess.running,
|
sleepMonitor: sleepMonitorProcess.running,
|
||||||
screensaver: root.screensaverTimeoutSeconds,
|
screensaver: root.screensaverTimeoutSeconds,
|
||||||
lock: root.lockTimeoutSeconds
|
lock: root.lockTimeoutSeconds,
|
||||||
|
screensaverDelay: root.screensaverDelaySeconds,
|
||||||
|
lockDelay: root.lockDelaySeconds,
|
||||||
|
timers: {
|
||||||
|
screensaver: screensaverTimer.running,
|
||||||
|
lock: lockTimer.running,
|
||||||
|
poll: screensaverResumePollTimer.running,
|
||||||
|
sleepMonitorRestart: sleepMonitorRestartTimer.running
|
||||||
|
},
|
||||||
|
processes: {
|
||||||
|
screensaver: screensaverProcess.running,
|
||||||
|
lock: lockProcess.running,
|
||||||
|
wake: wakeProcess.running,
|
||||||
|
check: screensaverCheckProcess.running,
|
||||||
|
sleepLock: sleepLockProcess.running,
|
||||||
|
sleepWake: sleepWakeProcess.running
|
||||||
|
},
|
||||||
|
lastEvent: root.lastEvent,
|
||||||
|
lastEventAt: root.lastEventAt,
|
||||||
|
lastScreensaverState: root.lastScreensaverState,
|
||||||
|
lastScreensaverCheckAt: root.lastScreensaverCheckAt,
|
||||||
|
screensaverCheckCount: root.screensaverCheckCount
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,10 +176,10 @@ Item {
|
|||||||
if (!root.idleEnabled) return
|
if (!root.idleEnabled) return
|
||||||
|
|
||||||
if (preparing) {
|
if (preparing) {
|
||||||
cancelIdleCycle()
|
cancelIdleCycle("sleep-preparing")
|
||||||
runProcess(sleepLockProcess, "OMARCHY_LOCK_ONLY=true omarchy-system-lock")
|
runProcess(sleepLockProcess, "sleep-lock", "OMARCHY_LOCK_ONLY=true omarchy-system-lock")
|
||||||
} else {
|
} else {
|
||||||
runProcess(sleepWakeProcess, "sleep 1 && omarchy-system-wake")
|
runProcess(sleepWakeProcess, "sleep-wake", "sleep 1 && omarchy-system-wake")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +188,8 @@ Item {
|
|||||||
if (persisted.idleEnabled === enabled) return enabled ? "enabled" : "disabled"
|
if (persisted.idleEnabled === enabled) return enabled ? "enabled" : "disabled"
|
||||||
|
|
||||||
persisted.idleEnabled = enabled
|
persisted.idleEnabled = enabled
|
||||||
if (!enabled) cancelIdleCycle()
|
logEvent("idle-enabled", enabled ? "enabled" : "disabled")
|
||||||
|
if (!enabled) cancelIdleCycle("disabled")
|
||||||
else Qt.callLater(root.handleIdleChanged)
|
else Qt.callLater(root.handleIdleChanged)
|
||||||
|
|
||||||
return enabled ? "enabled" : "disabled"
|
return enabled ? "enabled" : "disabled"
|
||||||
@@ -160,7 +214,7 @@ Item {
|
|||||||
id: lockTimer
|
id: lockTimer
|
||||||
interval: root.lockDelaySeconds * 1000
|
interval: root.lockDelaySeconds * 1000
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: if (root.idleEnabled && root.idledThisCycle) root.lockSystem()
|
onTriggered: if (root.idleEnabled && root.idledThisCycle) root.lockSystem("lock-timeout")
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -170,22 +224,52 @@ Item {
|
|||||||
onTriggered: root.checkScreensaverAfterActiveSignal()
|
onTriggered: root.checkScreensaverAfterActiveSignal()
|
||||||
}
|
}
|
||||||
|
|
||||||
Process { id: screensaverProcess }
|
Process {
|
||||||
Process { id: lockProcess }
|
id: screensaverProcess
|
||||||
Process { id: wakeProcess }
|
onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "screensaver exitCode=" + exitCode + " status=" + exitStatus) }
|
||||||
Process { id: sleepLockProcess }
|
}
|
||||||
Process { id: sleepWakeProcess }
|
Process {
|
||||||
|
id: lockProcess
|
||||||
|
onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "lock exitCode=" + exitCode + " status=" + exitStatus) }
|
||||||
|
}
|
||||||
|
Process {
|
||||||
|
id: wakeProcess
|
||||||
|
onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "wake exitCode=" + exitCode + " status=" + exitStatus) }
|
||||||
|
}
|
||||||
|
Process {
|
||||||
|
id: sleepLockProcess
|
||||||
|
onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "sleep-lock exitCode=" + exitCode + " status=" + exitStatus) }
|
||||||
|
}
|
||||||
|
Process {
|
||||||
|
id: sleepWakeProcess
|
||||||
|
onExited: function(exitCode, exitStatus) { root.logEvent("process-exit", "sleep-wake exitCode=" + exitCode + " status=" + exitStatus) }
|
||||||
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: screensaverCheckProcess
|
id: screensaverCheckProcess
|
||||||
stdout: StdioCollector {
|
stdout: SplitParser {
|
||||||
id: screensaverCheckStdout
|
onRead: function(line) {
|
||||||
waitForEnd: true
|
root.lastScreensaverState = String(line || "").trim()
|
||||||
|
root.lastScreensaverCheckAt = root.nowIso()
|
||||||
|
root.screensaverCheckCount++
|
||||||
|
root.logEvent("screensaver-check", root.lastScreensaverState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: function(exitCode, exitStatus) {
|
||||||
if (!root.idledThisCycle || !root.screensaverStartedThisCycle) return
|
root.logEvent("process-exit", "screensaver-check exitCode=" + exitCode + " status=" + exitStatus + " state=" + root.lastScreensaverState)
|
||||||
if (String(screensaverCheckStdout.text || "").trim() === "running") return
|
if (!root.idleEnabled || !root.idledThisCycle || !root.screensaverStartedThisCycle) return
|
||||||
root.cancelIdleCycle()
|
|
||||||
|
var state = String(root.lastScreensaverState || "").trim()
|
||||||
|
if (state.indexOf("running") === 0) return
|
||||||
|
if (state === "disabled") {
|
||||||
|
screensaverResumePollTimer.stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the screensaver disappears while we're still in the idle cycle,
|
||||||
|
// treat that as the user returning and require authentication before
|
||||||
|
// showing the desktop again.
|
||||||
|
root.lockSystem("screensaver-stopped state=" + state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,17 +284,28 @@ Item {
|
|||||||
else if (text === "boolean false") root.handleSleepPreparing(false)
|
else if (text === "boolean false") root.handleSleepPreparing(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: sleepMonitorRestartTimer.restart()
|
onExited: {
|
||||||
|
root.logEvent("sleep-monitor-exit", "restarting")
|
||||||
|
sleepMonitorRestartTimer.restart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: sleepMonitorRestartTimer
|
id: sleepMonitorRestartTimer
|
||||||
interval: 5000
|
interval: 5000
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: if (!sleepMonitorProcess.running) sleepMonitorProcess.running = true
|
onTriggered: {
|
||||||
|
if (!sleepMonitorProcess.running) {
|
||||||
|
root.logEvent("sleep-monitor-restart")
|
||||||
|
sleepMonitorProcess.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: Qt.callLater(root.handleIdleChanged)
|
Component.onCompleted: {
|
||||||
|
logEvent("service-ready")
|
||||||
|
Qt.callLater(root.handleIdleChanged)
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
target: "idle"
|
target: "idle"
|
||||||
@@ -219,6 +314,10 @@ Item {
|
|||||||
return root.statusJson()
|
return root.statusJson()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function debug(): string {
|
||||||
|
return root.statusJson()
|
||||||
|
}
|
||||||
|
|
||||||
function enable(): string {
|
function enable(): string {
|
||||||
return root.setIdleEnabled(true)
|
return root.setIdleEnabled(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string backgroundPath: ""
|
||||||
|
property int backgroundVersion: 0
|
||||||
|
property bool fingerprintConfigured: false
|
||||||
|
property bool authenticatingPassword: false
|
||||||
|
property string failureMessage: ""
|
||||||
|
property int failedAttempts: 0
|
||||||
|
property bool inputEnabled: true
|
||||||
|
property real scaleFactor: 1
|
||||||
|
property bool hasTyped: false
|
||||||
|
|
||||||
|
readonly property string fingerprintGlyph: "\uDB80\uDE37"
|
||||||
|
readonly property string placeholderText: fingerprintConfigured ? "Enter Password " + fingerprintGlyph : "Enter Password"
|
||||||
|
readonly property real effectiveScale: Math.max(1, scaleFactor)
|
||||||
|
readonly property int fieldWidth: Math.round(650 / effectiveScale)
|
||||||
|
readonly property int fieldHeight: Math.round(100 / effectiveScale)
|
||||||
|
readonly property int outlineThickness: Math.max(1, Math.round(4 / effectiveScale))
|
||||||
|
readonly property int fieldFontSize: Style.font.heading
|
||||||
|
|
||||||
|
signal submitPassword(string password)
|
||||||
|
|
||||||
|
function withAlpha(color, alpha) {
|
||||||
|
return Qt.rgba(color.r, color.g, color.b, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileUrl(path) {
|
||||||
|
if (!path) return ""
|
||||||
|
var encoded = String(path).split("/").map(encodeURIComponent).join("/")
|
||||||
|
return "file://" + encoded + "?v=" + backgroundVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
function forcePasswordFocus() {
|
||||||
|
passwordInput.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearPassword() {
|
||||||
|
passwordInput.text = ""
|
||||||
|
hasTyped = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onInputEnabledChanged: {
|
||||||
|
hasTyped = false
|
||||||
|
if (inputEnabled) Qt.callLater(forcePasswordFocus)
|
||||||
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
hasTyped = false
|
||||||
|
if (inputEnabled) Qt.callLater(forcePasswordFocus)
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Color.background
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: wallpaper
|
||||||
|
anchors.fill: parent
|
||||||
|
source: root.fileUrl(root.backgroundPath)
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
asynchronous: true
|
||||||
|
cache: false
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: height
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: wallpaper
|
||||||
|
source: wallpaper
|
||||||
|
blurEnabled: wallpaper.status === Image.Ready
|
||||||
|
blur: 1.0
|
||||||
|
blurMax: 64
|
||||||
|
blurMultiplier: 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.forcePasswordFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: inputField
|
||||||
|
width: root.fieldWidth
|
||||||
|
height: root.fieldHeight
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: root.withAlpha(Color.background, 0.8)
|
||||||
|
border.color: root.failureMessage.length > 0 ? Color.urgent : (root.authenticatingPassword ? Color.accent : Color.foreground)
|
||||||
|
border.width: root.outlineThickness
|
||||||
|
radius: Style.cornerRadius
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: passwordInput
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: root.outlineThickness + 18
|
||||||
|
anchors.rightMargin: root.outlineThickness + 18
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
activeFocusOnPress: true
|
||||||
|
clip: true
|
||||||
|
enabled: root.inputEnabled && !root.authenticatingPassword
|
||||||
|
readOnly: root.authenticatingPassword
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
passwordCharacter: "\u2022"
|
||||||
|
passwordMaskDelay: 0
|
||||||
|
color: Color.foreground
|
||||||
|
selectionColor: root.withAlpha(Color.accent, 0.45)
|
||||||
|
selectedTextColor: Color.foreground
|
||||||
|
font.family: "monospace"
|
||||||
|
font.pixelSize: root.fieldFontSize
|
||||||
|
cursorVisible: activeFocus && !root.authenticatingPassword && root.hasTyped
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
if (text.length > 0) root.hasTyped = true
|
||||||
|
if (text.length > 0 && root.failureMessage.length > 0) root.failureMessage = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
var submitted = text
|
||||||
|
text = ""
|
||||||
|
root.hasTyped = false
|
||||||
|
if (submitted.length > 0) root.submitPassword(submitted)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: function(event) {
|
||||||
|
if (event.key === Qt.Key_Escape || (event.modifiers & Qt.ControlModifier && event.key === Qt.Key_U)) {
|
||||||
|
text = ""
|
||||||
|
root.hasTyped = false
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: passwordInput
|
||||||
|
text: root.failureMessage.length > 0 ? root.failureMessage : root.placeholderText
|
||||||
|
visible: passwordInput.text.length === 0
|
||||||
|
color: root.failureMessage.length > 0 ? Color.urgent : Color.foreground
|
||||||
|
font.family: "monospace"
|
||||||
|
font.pixelSize: root.fieldFontSize
|
||||||
|
font.italic: root.failureMessage.length > 0
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.Pam
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var shell: null
|
||||||
|
property string omarchyPath: ""
|
||||||
|
|
||||||
|
readonly property string home: Quickshell.env("HOME")
|
||||||
|
readonly property string userName: Quickshell.env("USER") || Quickshell.env("LOGNAME")
|
||||||
|
readonly property string currentBackgroundLink: home + "/.config/omarchy/current/background"
|
||||||
|
|
||||||
|
property bool lockRequested: false
|
||||||
|
property bool authenticatingPassword: false
|
||||||
|
property bool fingerprintAuthenticating: false
|
||||||
|
property bool passwordPamConfigured: false
|
||||||
|
property bool fingerprintConfigured: false
|
||||||
|
property bool previewVisible: false
|
||||||
|
property string pendingPassword: ""
|
||||||
|
property string failureMessage: ""
|
||||||
|
property int failedAttempts: 0
|
||||||
|
property string backgroundPath: ""
|
||||||
|
property int backgroundVersion: 0
|
||||||
|
|
||||||
|
readonly property bool locked: lockRequested || sessionLock.locked || sessionLock.secure
|
||||||
|
readonly property bool authenticating: authenticatingPassword || fingerprintAuthenticating
|
||||||
|
|
||||||
|
function refreshBackground() {
|
||||||
|
if (!readlinkProc.running) readlinkProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshFingerprintStatus() {
|
||||||
|
if (!fingerprintCheckProc.running) fingerprintCheckProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetAuthenticationState() {
|
||||||
|
pendingPassword = ""
|
||||||
|
failureMessage = ""
|
||||||
|
failedAttempts = 0
|
||||||
|
authenticatingPassword = false
|
||||||
|
fingerprintAuthenticating = false
|
||||||
|
fingerprintRetryTimer.stop()
|
||||||
|
if (passwordPam.active) passwordPam.abort()
|
||||||
|
if (fingerprintPam.active) fingerprintPam.abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
function beginLock() {
|
||||||
|
if (!passwordPamConfigured) return false
|
||||||
|
|
||||||
|
resetAuthenticationState()
|
||||||
|
refreshBackground()
|
||||||
|
refreshFingerprintStatus()
|
||||||
|
lockRequested = true
|
||||||
|
sessionLock.locked = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishUnlock() {
|
||||||
|
if (!root.locked && !lockRequested) return
|
||||||
|
|
||||||
|
lockRequested = false
|
||||||
|
resetAuthenticationState()
|
||||||
|
sessionLock.locked = false
|
||||||
|
runWake()
|
||||||
|
}
|
||||||
|
|
||||||
|
function runWake() {
|
||||||
|
if (!wakeProcess.running) wakeProcess.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitPassword(value) {
|
||||||
|
var password = String(value || "")
|
||||||
|
if (!lockRequested || authenticatingPassword || password.length === 0) return
|
||||||
|
|
||||||
|
pendingPassword = password
|
||||||
|
failureMessage = ""
|
||||||
|
authenticatingPassword = true
|
||||||
|
|
||||||
|
if (!passwordPam.start()) {
|
||||||
|
handlePasswordFailure()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt.callLater(respondToPasswordPrompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
function respondToPasswordPrompt() {
|
||||||
|
if (!authenticatingPassword || !passwordPam.active || !passwordPam.responseRequired) return
|
||||||
|
passwordPam.respond(pendingPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePasswordFailure() {
|
||||||
|
if (!lockRequested) return
|
||||||
|
|
||||||
|
authenticatingPassword = false
|
||||||
|
pendingPassword = ""
|
||||||
|
failedAttempts += 1
|
||||||
|
failureMessage = "Authentication failed (" + failedAttempts + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function startFingerprint() {
|
||||||
|
if (!lockRequested || !sessionLock.secure || !fingerprintConfigured) return
|
||||||
|
if (fingerprintPam.active || fingerprintAuthenticating) return
|
||||||
|
|
||||||
|
fingerprintAuthenticating = true
|
||||||
|
if (!fingerprintPam.start()) {
|
||||||
|
fingerprintAuthenticating = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFingerprintFinished(result) {
|
||||||
|
fingerprintAuthenticating = false
|
||||||
|
|
||||||
|
if (!lockRequested) return
|
||||||
|
if (result === PamResult.Success) {
|
||||||
|
finishUnlock()
|
||||||
|
} else if (fingerprintConfigured) {
|
||||||
|
fingerprintRetryTimer.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WlSessionLock {
|
||||||
|
id: sessionLock
|
||||||
|
|
||||||
|
locked: false
|
||||||
|
|
||||||
|
onSecureStateChanged: {
|
||||||
|
if (secure) root.startFingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
|
onLockStateChanged: {
|
||||||
|
if (!locked && root.lockRequested) {
|
||||||
|
root.lockRequested = false
|
||||||
|
root.resetAuthenticationState()
|
||||||
|
root.runWake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WlSessionLockSurface {
|
||||||
|
id: lockSurface
|
||||||
|
color: Color.background
|
||||||
|
|
||||||
|
LockView {
|
||||||
|
id: lockView
|
||||||
|
anchors.fill: parent
|
||||||
|
backgroundPath: root.backgroundPath
|
||||||
|
backgroundVersion: root.backgroundVersion
|
||||||
|
fingerprintConfigured: root.fingerprintConfigured
|
||||||
|
authenticatingPassword: root.authenticatingPassword
|
||||||
|
failureMessage: root.failureMessage
|
||||||
|
failedAttempts: root.failedAttempts
|
||||||
|
inputEnabled: root.lockRequested
|
||||||
|
scaleFactor: lockSurface.screen && lockSurface.screen.devicePixelRatio > 0 ? lockSurface.screen.devicePixelRatio : 1
|
||||||
|
onSubmitPassword: function(password) { root.submitPassword(password) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: previewWindow
|
||||||
|
visible: root.previewVisible
|
||||||
|
anchors { top: true; bottom: true; left: true; right: true }
|
||||||
|
color: "transparent"
|
||||||
|
WlrLayershell.namespace: "omarchy-lock-preview"
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
|
||||||
|
LockView {
|
||||||
|
anchors.fill: parent
|
||||||
|
backgroundPath: root.backgroundPath
|
||||||
|
backgroundVersion: root.backgroundVersion
|
||||||
|
fingerprintConfigured: root.fingerprintConfigured
|
||||||
|
authenticatingPassword: false
|
||||||
|
failureMessage: ""
|
||||||
|
failedAttempts: 0
|
||||||
|
inputEnabled: false
|
||||||
|
scaleFactor: previewWindow.screen && previewWindow.screen.devicePixelRatio > 0 ? previewWindow.screen.devicePixelRatio : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: root.previewVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PamContext {
|
||||||
|
id: passwordPam
|
||||||
|
config: "omarchy-lock-password"
|
||||||
|
user: root.userName
|
||||||
|
|
||||||
|
onResponseRequiredChanged: root.respondToPasswordPrompt()
|
||||||
|
onPamMessage: root.respondToPasswordPrompt()
|
||||||
|
|
||||||
|
onCompleted: function(result) {
|
||||||
|
root.authenticatingPassword = false
|
||||||
|
root.pendingPassword = ""
|
||||||
|
|
||||||
|
if (!root.lockRequested) return
|
||||||
|
if (result === PamResult.Success) root.finishUnlock()
|
||||||
|
else root.handlePasswordFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
onError: function(error) {
|
||||||
|
root.handlePasswordFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PamContext {
|
||||||
|
id: fingerprintPam
|
||||||
|
config: "omarchy-lock-fingerprint"
|
||||||
|
user: root.userName
|
||||||
|
|
||||||
|
onCompleted: function(result) {
|
||||||
|
root.handleFingerprintFinished(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
onError: function(error) {
|
||||||
|
root.fingerprintAuthenticating = false
|
||||||
|
if (root.lockRequested && root.fingerprintConfigured) fingerprintRetryTimer.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fingerprintRetryTimer
|
||||||
|
interval: 250
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.startFingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: readlinkProc
|
||||||
|
command: ["readlink", "-f", root.currentBackgroundLink]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
waitForEnd: true
|
||||||
|
onStreamFinished: {
|
||||||
|
var next = String(text || "").trim()
|
||||||
|
if (next !== root.backgroundPath) {
|
||||||
|
root.backgroundPath = next
|
||||||
|
root.backgroundVersion += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: fingerprintCheckProc
|
||||||
|
command: ["bash", "-lc", "if [[ -f /etc/pam.d/omarchy-lock-fingerprint ]] && command -v fprintd-list >/dev/null 2>&1 && fprintd-list \"$USER\" 2>/dev/null | grep -qi finger; then echo yes; else echo no; fi"]
|
||||||
|
stdout: StdioCollector { id: fingerprintCheckStdout; waitForEnd: true }
|
||||||
|
onExited: {
|
||||||
|
root.fingerprintConfigured = String(fingerprintCheckStdout.text || "").trim() === "yes"
|
||||||
|
if (root.lockRequested && root.fingerprintConfigured) root.startFingerprint()
|
||||||
|
else if (!root.fingerprintConfigured && fingerprintPam.active) fingerprintPam.abort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: wakeProcess
|
||||||
|
command: ["bash", "-lc", "omarchy-system-wake"]
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: "/etc/pam.d/omarchy-lock-password"
|
||||||
|
watchChanges: true
|
||||||
|
printErrors: false
|
||||||
|
onLoaded: root.passwordPamConfigured = true
|
||||||
|
onLoadFailed: root.passwordPamConfigured = false
|
||||||
|
onFileChanged: reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
refreshBackground()
|
||||||
|
refreshFingerprintStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "lock"
|
||||||
|
|
||||||
|
function lock(): string {
|
||||||
|
if (!root.passwordPamConfigured) return "missing-pam"
|
||||||
|
if (!root.locked && !root.beginLock()) return "failed"
|
||||||
|
return "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLocked(): string {
|
||||||
|
return root.locked ? "true" : "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
function status(): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
locked: root.locked,
|
||||||
|
secure: sessionLock.secure,
|
||||||
|
passwordPam: root.passwordPamConfigured,
|
||||||
|
fingerprint: root.fingerprintConfigured,
|
||||||
|
authenticating: root.authenticating
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function preview(): string {
|
||||||
|
root.refreshBackground()
|
||||||
|
root.refreshFingerprintStatus()
|
||||||
|
root.previewVisible = true
|
||||||
|
return "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
function hidePreview(): string {
|
||||||
|
root.previewVisible = false
|
||||||
|
return "ok"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "omarchy.lock",
|
||||||
|
"name": "Lock Screen",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "Omarchy",
|
||||||
|
"description": "Quickshell session lock with separate password and fingerprint PAM flows.",
|
||||||
|
"kinds": [
|
||||||
|
"service"
|
||||||
|
],
|
||||||
|
"keepLoaded": true,
|
||||||
|
"entryPoints": {
|
||||||
|
"service": "Service.qml"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
$color = rgba(12, 11, 12, 1)
|
|
||||||
$inner_color = rgba(12, 11, 12, 0.66)
|
|
||||||
$outer_color = rgba(195, 139, 123, 1)
|
|
||||||
$font_color = rgba(226, 221, 220, 1)
|
|
||||||
$placeholder_color = rgba(255, 255, 255, 0.7)
|
|
||||||
$check_color = rgba(181, 151, 144, 1)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
$color = rgba(16, 19, 21, 1)
|
|
||||||
$inner_color = rgba(16, 19, 21, 1)
|
|
||||||
$outer_color = rgba(121, 129, 134, 1)
|
|
||||||
$font_color = rgba(202, 204, 204, 1)
|
|
||||||
$placeholder_color = rgba(202, 204, 204, 0.7)
|
|
||||||
$check_color = rgba(52, 61, 65, 1)
|
|
||||||
Reference in New Issue
Block a user