chore: updated rofi clipd e97f71df
Steve · 2026-08-31 23:19 1 file(s) · +29 −3
rofi/scripts/rofi-clipd +29 −3
20 20
# threshold where a copy-then-immediately-quit would be missed in practice.
21 21
LIMIT=${ROFI_CLIP_LIMIT:-200}
22 22
INTERVAL=${ROFI_CLIP_INTERVAL:-1}
23 +
# How long to give an unresponsive selection owner before giving up on a read.
24 +
READ_TIMEOUT=${ROFI_CLIP_READ_TIMEOUT:-2}
23 25
24 26
mkdir -p "$STORE"
25 27
68 70
69 71
# UTF8_STRING keeps this to text: asking for whatever target an image or a
70 72
# file-manager copy offers would store a blob nothing can paste back.
71 -
current() { xclip -o -selection clipboard -t UTF8_STRING 2>/dev/null; }
73 +
#
74 +
# The timeout is not optional. An X selection is served by the process that
75 +
# owns it, so reading one is a round trip to another program — and if that
76 +
# program stops answering (it died mid-transfer, or it is wedged), xclip waits
77 +
# on the reply forever. With no timeout that hangs this loop too, and history
78 +
# quietly stops recording until the daemon is restarted by hand.
79 +
current() { timeout "$READ_TIMEOUT" xclip -o -selection clipboard -t UTF8_STRING 2>/dev/null; }
72 80
73 81
case "${1:-}" in
74 82
    --once)
86 94
esac
87 95
88 96
# A second daemon would double every entry, so check for a live one first.
89 -
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
97 +
# The trap below clears the pidfile on a clean exit, but a kill -9 or a reboot
98 +
# leaves it behind — and that stale pid is eventually handed to some unrelated
99 +
# process, which would make this refuse to start at every login from then on.
100 +
# So the pid has to still be this script, not merely alive.
101 +
running() {
102 +
    [ -f "$PIDFILE" ] || return 1
103 +
    pid=$(cat "$PIDFILE" 2>/dev/null) || return 1
104 +
    [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null || return 1
105 +
    tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null | grep -q "${0##*/}"
106 +
}
107 +
108 +
if running; then
90 109
    echo "rofi-clipd: already running (pid $(cat "$PIDFILE"))" >&2
91 110
    exit 1
92 111
fi
93 112
echo $$ > "$PIDFILE"
94 -
trap 'rm -f "$PIDFILE"' EXIT INT TERM
113 +
# EXIT clears the pidfile on every way out. INT and TERM need handlers that
114 +
# actually exit: a handler that just cleans up returns into the loop, leaving a
115 +
# daemon that ignores kill *and* has already deleted the pidfile guarding
116 +
# against a second one — so the next login starts a duplicate that records
117 +
# every copy twice.
118 +
trap 'rm -f "$PIDFILE"' EXIT
119 +
trap 'exit 130' INT
120 +
trap 'exit 143' TERM
95 121
96 122
last=""
97 123
while :; do