Simplify clipboard watcher lifecycle with pdeathsig
Replace the three-layer process management (trap cleanup, PPID-polling watchdog subshell, /proc-scanning reaper) with kernel-level lifetime binding: each wl-paste watcher is spawned under setpriv --pdeathsig TERM, so it dies with the shell no matter how the shell exits. - Delete watch.sh: the shell now spawns both watchers directly as declarative Process commands instead of a wrapper script with traps and a 1s polling loop - Delete init.sh: reaping stale watchers from a crashed pre-pdeathsig shell is a single pkill at startup - Collapse capture.sh's dual stream/snapshot modes: wl-paste forwards arguments to its watch command, so the mime rides along as $1 instead of an env var, letting both modes share one emit_image function - Turn the six-branch image mime chain into a loop Net: two fewer files, three fewer runtime processes, and the watch-mode capture tests now exercise the same argument protocol the shell uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
055ffaccd4
commit
60e0a2a0cd
@@ -19,8 +19,6 @@ Item {
|
|||||||
|
|
||||||
property string historyPath: Quickshell.env("HOME") + "/.local/state/omarchy/clipboard-history.json"
|
property string historyPath: Quickshell.env("HOME") + "/.local/state/omarchy/clipboard-history.json"
|
||||||
property string captureScript: root.omarchyPath + "/shell/plugins/clipboard/capture.sh"
|
property string captureScript: root.omarchyPath + "/shell/plugins/clipboard/capture.sh"
|
||||||
property string initScript: root.omarchyPath + "/shell/plugins/clipboard/init.sh"
|
|
||||||
property string watchScript: root.omarchyPath + "/shell/plugins/clipboard/watch.sh"
|
|
||||||
// Shares the [menu] surface tokens — themes that style the menu also
|
// Shares the [menu] surface tokens — themes that style the menu also
|
||||||
// style the clipboard. Selected-row colors composed in the
|
// style the clipboard. Selected-row colors composed in the
|
||||||
// singleton so consumers drop them straight into Rectangle bindings.
|
// singleton so consumers drop them straight into Rectangle bindings.
|
||||||
@@ -260,19 +258,22 @@ Item {
|
|||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reap watchers left behind by a previous shell instance, then start our
|
||||||
|
// own. The pdeathsig on the watchers makes the kernel kill them whenever
|
||||||
|
// the shell exits, however it exits, so no further lifecycle management.
|
||||||
Process {
|
Process {
|
||||||
id: initProc
|
id: initProc
|
||||||
command: [root.initScript, root.captureScript]
|
command: ["pkill", "-f", "wl-paste .*--watch .*/shell/plugins/clipboard/capture\\.sh"]
|
||||||
onExited: {
|
onExited: {
|
||||||
currentProc.command = [root.captureScript]
|
|
||||||
currentProc.running = true
|
currentProc.running = true
|
||||||
watchProc.command = [root.watchScript, root.captureScript]
|
textWatchProc.running = true
|
||||||
watchProc.running = true
|
imageWatchProc.running = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: currentProc
|
id: currentProc
|
||||||
|
command: [root.captureScript]
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
waitForEnd: true
|
waitForEnd: true
|
||||||
onStreamFinished: root.addClipboardJson(text)
|
onStreamFinished: root.addClipboardJson(text)
|
||||||
@@ -280,7 +281,16 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: watchProc
|
id: textWatchProc
|
||||||
|
command: ["setpriv", "--pdeathsig", "TERM", "wl-paste", "--type", "text", "--watch", root.captureScript, "text"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: function(data) { root.addClipboardJson(data) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: imageWatchProc
|
||||||
|
command: ["setpriv", "--pdeathsig", "TERM", "wl-paste", "--type", "image/png", "--watch", root.captureScript, "image/png"]
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: function(data) { root.addClipboardJson(data) }
|
onRead: function(data) { root.addClipboardJson(data) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Captures the current clipboard as a JSON entry on stdout. In watch mode,
|
||||||
|
# wl-paste invokes this with the payload on stdin and the mime as $1. Without
|
||||||
|
# arguments, it snapshots the current selection itself.
|
||||||
|
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy"
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy"
|
||||||
@@ -14,35 +18,10 @@ fi
|
|||||||
|
|
||||||
emit_image() {
|
emit_image() {
|
||||||
local mime="$1"
|
local mime="$1"
|
||||||
local ext="$2"
|
local ext tmp hash file
|
||||||
local tmp=""
|
|
||||||
local hash=""
|
|
||||||
local file=""
|
|
||||||
|
|
||||||
tmp=$(mktemp --tmpdir="$IMAGE_DIR" clipboard.XXXXXX) || return 0
|
ext=${mime#image/}
|
||||||
if ! timeout 2s wl-paste --type "$mime" > "$tmp" 2>/dev/null || [[ ! -s $tmp ]]; then
|
[[ $ext == jpeg ]] && ext=jpg
|
||||||
rm -f "$tmp"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
hash=$(sha256sum "$tmp" | awk '{print $1}')
|
|
||||||
file="$IMAGE_DIR/$hash.$ext"
|
|
||||||
if [[ -e $file ]]; then
|
|
||||||
rm -f "$tmp"
|
|
||||||
else
|
|
||||||
mv "$tmp" "$file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
jq -cn --arg mime "$mime" --arg path "$file" --arg captured_at "$(date +'%A %H:%M')" \
|
|
||||||
'{type:"image", mime:$mime, path:$path, capturedAt:$captured_at}'
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_image_stream() {
|
|
||||||
local mime="$1"
|
|
||||||
local ext="$2"
|
|
||||||
local tmp=""
|
|
||||||
local hash=""
|
|
||||||
local file=""
|
|
||||||
|
|
||||||
tmp=$(mktemp --tmpdir="$IMAGE_DIR" clipboard.XXXXXX) || return 0
|
tmp=$(mktemp --tmpdir="$IMAGE_DIR" clipboard.XXXXXX) || return 0
|
||||||
cat >"$tmp"
|
cat >"$tmp"
|
||||||
@@ -63,32 +42,22 @@ emit_image_stream() {
|
|||||||
'{type:"image", mime:$mime, path:$path, capturedAt:$captured_at}'
|
'{type:"image", mime:$mime, path:$path, capturedAt:$captured_at}'
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_text_stream() {
|
emit_text() {
|
||||||
jq -cRs 'select(length > 0) | {type:"text", text:.}'
|
jq -cRs 'select(length > 0) | {type:"text", text:.}'
|
||||||
}
|
}
|
||||||
|
|
||||||
case "${OMARCHY_CLIPBOARD_WATCH_MIME:-}" in
|
case "${1:-}" in
|
||||||
text) emit_text_stream; exit 0 ;;
|
text) emit_text; exit 0 ;;
|
||||||
image/png) emit_image_stream 'image/png' 'png'; exit 0 ;;
|
image/*) emit_image "$1"; exit 0 ;;
|
||||||
image/jpeg) emit_image_stream 'image/jpeg' 'jpg'; exit 0 ;;
|
|
||||||
image/webp) emit_image_stream 'image/webp' 'webp'; exit 0 ;;
|
|
||||||
image/gif) emit_image_stream 'image/gif' 'gif'; exit 0 ;;
|
|
||||||
image/bmp) emit_image_stream 'image/bmp' 'bmp'; exit 0 ;;
|
|
||||||
image/tiff) emit_image_stream 'image/tiff' 'tiff'; exit 0 ;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if grep -qx 'image/png' <<<"$types"; then
|
for mime in image/png image/jpeg image/webp image/gif image/bmp image/tiff; do
|
||||||
emit_image 'image/png' 'png'
|
if grep -qx "$mime" <<<"$types"; then
|
||||||
elif grep -qx 'image/jpeg' <<<"$types"; then
|
timeout 2s wl-paste --type "$mime" 2>/dev/null | emit_image "$mime"
|
||||||
emit_image 'image/jpeg' 'jpg'
|
exit 0
|
||||||
elif grep -qx 'image/webp' <<<"$types"; then
|
fi
|
||||||
emit_image 'image/webp' 'webp'
|
done
|
||||||
elif grep -qx 'image/gif' <<<"$types"; then
|
|
||||||
emit_image 'image/gif' 'gif'
|
if grep -q '^text/' <<<"$types" || grep -qx 'UTF8_STRING' <<<"$types" || grep -qx 'STRING' <<<"$types"; then
|
||||||
elif grep -qx 'image/bmp' <<<"$types"; then
|
wl-paste --type text --no-newline 2>/dev/null | emit_text
|
||||||
emit_image 'image/bmp' 'bmp'
|
|
||||||
elif grep -qx 'image/tiff' <<<"$types"; then
|
|
||||||
emit_image 'image/tiff' 'tiff'
|
|
||||||
elif grep -q '^text/' <<<"$types" || grep -qx 'UTF8_STRING' <<<"$types" || grep -qx 'STRING' <<<"$types"; then
|
|
||||||
wl-paste --type text --no-newline 2>/dev/null | jq -cRs 'select(length > 0) | {type:"text", text:.}'
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
current_script=${1:-}
|
|
||||||
[[ -n $current_script ]] || exit 0
|
|
||||||
|
|
||||||
is_clipboard_capture() {
|
|
||||||
local path=$1
|
|
||||||
|
|
||||||
[[ $path == */shell/plugins/clipboard/capture.sh ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
watched_script_for_pid() {
|
|
||||||
local pid=$1
|
|
||||||
local -a args=()
|
|
||||||
local i
|
|
||||||
|
|
||||||
[[ -r /proc/$pid/cmdline ]] || return 1
|
|
||||||
mapfile -d '' -t args <"/proc/$pid/cmdline" || return 1
|
|
||||||
((${#args[@]} > 0)) || return 1
|
|
||||||
|
|
||||||
for ((i = 0; i < ${#args[@]}; i++)); do
|
|
||||||
if [[ ${args[i]} == "--watch" ]]; then
|
|
||||||
printf '%s\n' "${args[i + 1]:-}"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
for pid in $(pgrep -x wl-paste 2>/dev/null || true); do
|
|
||||||
watched_script=$(watched_script_for_pid "$pid" || true)
|
|
||||||
[[ -n $watched_script ]] || continue
|
|
||||||
is_clipboard_capture "$watched_script" || continue
|
|
||||||
|
|
||||||
if [[ $watched_script == $current_script || ! -e $watched_script ]]; then
|
|
||||||
kill "$pid" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
capture_script=${1:-}
|
|
||||||
[[ -n $capture_script && -x $capture_script ]] || exit 1
|
|
||||||
|
|
||||||
owner_pid=$PPID
|
|
||||||
watchdog_pid=""
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
local pid
|
|
||||||
|
|
||||||
if [[ -n $watchdog_pid ]]; then
|
|
||||||
kill "$watchdog_pid" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
for pid in $(jobs -p); do
|
|
||||||
[[ $pid == $watchdog_pid ]] && continue
|
|
||||||
kill "$pid" 2>/dev/null || true
|
|
||||||
done
|
|
||||||
|
|
||||||
wait 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
cleanup
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
trap cleanup EXIT
|
|
||||||
trap stop HUP INT TERM
|
|
||||||
|
|
||||||
(
|
|
||||||
while kill -0 "$owner_pid" 2>/dev/null; do
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
|
|
||||||
kill -TERM "$$" 2>/dev/null || true
|
|
||||||
) &
|
|
||||||
watchdog_pid=$!
|
|
||||||
|
|
||||||
OMARCHY_CLIPBOARD_WATCH_MIME=text wl-paste --type text --watch "$capture_script" 2>/dev/null &
|
|
||||||
OMARCHY_CLIPBOARD_WATCH_MIME=image/png wl-paste --type image/png --watch "$capture_script" 2>/dev/null &
|
|
||||||
|
|
||||||
wait
|
|
||||||
@@ -162,6 +162,18 @@ assert(
|
|||||||
!/onContainsMouseChanged:[\s\S]*root\.selectedIndex/.test(clipboardQml),
|
!/onContainsMouseChanged:[\s\S]*root\.selectedIndex/.test(clipboardQml),
|
||||||
'clipboard does not select rows from containsMouse'
|
'clipboard does not select rows from containsMouse'
|
||||||
)
|
)
|
||||||
|
assert(
|
||||||
|
clipboardQml.includes('command: ["setpriv", "--pdeathsig", "TERM", "wl-paste", "--type", "text", "--watch", root.captureScript, "text"]'),
|
||||||
|
'clipboard text watcher dies with the shell via pdeathsig'
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
clipboardQml.includes('command: ["setpriv", "--pdeathsig", "TERM", "wl-paste", "--type", "image/png", "--watch", root.captureScript, "image/png"]'),
|
||||||
|
'clipboard image watcher dies with the shell via pdeathsig'
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
clipboardQml.includes('command: ["pkill", "-f", "wl-paste .*--watch .*/shell/plugins/clipboard/capture\\\\.sh"]'),
|
||||||
|
'clipboard init reaps stale watchers before starting new ones'
|
||||||
|
)
|
||||||
JS
|
JS
|
||||||
|
|
||||||
TMPDIR=$(mktemp -d)
|
TMPDIR=$(mktemp -d)
|
||||||
@@ -245,17 +257,22 @@ capture_output=$(XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="
|
|||||||
[[ $capture_output == '{"type":"text","text":"terminal copy"}' ]] || fail "clipboard capture records normal text events"
|
[[ $capture_output == '{"type":"text","text":"terminal copy"}' ]] || fail "clipboard capture records normal text events"
|
||||||
pass "clipboard capture records normal text events"
|
pass "clipboard capture records normal text events"
|
||||||
|
|
||||||
capture_output=$(printf 'closing app copy' | OMARCHY_CLIPBOARD_WATCH_MIME=text WL_PASTE_TEXT="stale read" XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh")
|
capture_output=$(printf 'closing app copy' | WL_PASTE_TEXT="stale read" XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh" text)
|
||||||
[[ $capture_output == '{"type":"text","text":"closing app copy"}' ]] || fail "clipboard capture records watched text from stdin"
|
[[ $capture_output == '{"type":"text","text":"closing app copy"}' ]] || fail "clipboard capture records watched text from stdin"
|
||||||
pass "clipboard capture records watched text from stdin"
|
pass "clipboard capture records watched text from stdin"
|
||||||
|
|
||||||
capture_output=$(printf 'png-data' | OMARCHY_CLIPBOARD_WATCH_MIME=image/png XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh")
|
capture_output=$(printf 'png-data' | XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh" image/png)
|
||||||
image_path=$(jq -r '.path' <<<"$capture_output")
|
image_path=$(jq -r '.path' <<<"$capture_output")
|
||||||
jq -e '.type == "image" and .mime == "image/png" and (.capturedAt | type == "string")' <<<"$capture_output" >/dev/null || fail "clipboard capture records watched png images"
|
jq -e '.type == "image" and .mime == "image/png" and (.capturedAt | type == "string")' <<<"$capture_output" >/dev/null || fail "clipboard capture records watched png images"
|
||||||
[[ -s $image_path && $(<"$image_path") == "png-data" ]] || fail "clipboard capture stores watched png image data"
|
[[ -s $image_path && $(<"$image_path") == "png-data" ]] || fail "clipboard capture stores watched png image data"
|
||||||
pass "clipboard capture records watched png images"
|
pass "clipboard capture records watched png images"
|
||||||
|
|
||||||
capture_output=$(printf 'secret' | CLIPBOARD_STATE=sensitive OMARCHY_CLIPBOARD_WATCH_MIME=text XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh")
|
capture_output=$(printf 'jpg-data' | XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh" image/jpeg)
|
||||||
|
image_path=$(jq -r '.path' <<<"$capture_output")
|
||||||
|
jq -e '.mime == "image/jpeg"' <<<"$capture_output" >/dev/null && [[ $image_path == *.jpg ]] || fail "clipboard capture stores watched jpeg images with jpg extension"
|
||||||
|
pass "clipboard capture stores watched jpeg images with jpg extension"
|
||||||
|
|
||||||
|
capture_output=$(printf 'secret' | CLIPBOARD_STATE=sensitive XDG_RUNTIME_DIR="$TMPDIR" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh" text)
|
||||||
[[ -z $capture_output ]] || fail "clipboard capture ignores sensitive watched text"
|
[[ -z $capture_output ]] || fail "clipboard capture ignores sensitive watched text"
|
||||||
pass "clipboard capture ignores sensitive watched text"
|
pass "clipboard capture ignores sensitive watched text"
|
||||||
|
|
||||||
@@ -288,39 +305,24 @@ chmod +x "$TMPDIR/bin/wl-paste"
|
|||||||
|
|
||||||
clipboard_lifecycle_dir="$TMPDIR/clipboard-lifecycle"
|
clipboard_lifecycle_dir="$TMPDIR/clipboard-lifecycle"
|
||||||
current_script="$clipboard_lifecycle_dir/current/shell/plugins/clipboard/capture.sh"
|
current_script="$clipboard_lifecycle_dir/current/shell/plugins/clipboard/capture.sh"
|
||||||
other_script="$clipboard_lifecycle_dir/other/shell/plugins/clipboard/capture.sh"
|
mkdir -p "$(dirname "$current_script")"
|
||||||
missing_script="$clipboard_lifecycle_dir/missing/shell/plugins/clipboard/capture.sh"
|
|
||||||
watch_log="$clipboard_lifecycle_dir/wl-paste.log"
|
|
||||||
mkdir -p "$(dirname "$current_script")" "$(dirname "$other_script")"
|
|
||||||
cp "$ROOT/shell/plugins/clipboard/capture.sh" "$current_script"
|
cp "$ROOT/shell/plugins/clipboard/capture.sh" "$current_script"
|
||||||
cp "$ROOT/shell/plugins/clipboard/capture.sh" "$other_script"
|
chmod +x "$current_script"
|
||||||
chmod +x "$current_script" "$other_script"
|
|
||||||
|
|
||||||
WL_PASTE_LOG="$watch_log" PATH="$TMPDIR/bin:$PATH" wl-paste --type text --watch "$current_script" &
|
|
||||||
current_pid=$!
|
|
||||||
PIDS_TO_KILL+=("$current_pid")
|
|
||||||
WL_PASTE_LOG="$watch_log" PATH="$TMPDIR/bin:$PATH" wl-paste --type text --watch "$other_script" &
|
|
||||||
other_pid=$!
|
|
||||||
PIDS_TO_KILL+=("$other_pid")
|
|
||||||
WL_PASTE_LOG="$watch_log" PATH="$TMPDIR/bin:$PATH" wl-paste --type text --watch "$missing_script" &
|
|
||||||
missing_pid=$!
|
|
||||||
PIDS_TO_KILL+=("$missing_pid")
|
|
||||||
|
|
||||||
|
PATH="$TMPDIR/bin:$PATH" wl-paste --type text --watch "$current_script" text &
|
||||||
|
stale_pid=$!
|
||||||
|
PIDS_TO_KILL+=("$stale_pid")
|
||||||
sleep 0.2
|
sleep 0.2
|
||||||
PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/init.sh" "$current_script"
|
pgrep -f 'wl-paste .*--watch .*/shell/plugins/clipboard/capture\.sh' | grep -qx "$stale_pid" || fail "clipboard reaper pattern matches running watchers"
|
||||||
process_gone "$current_pid" || fail "clipboard init kills watchers for the current capture script"
|
kill "$stale_pid" 2>/dev/null || true
|
||||||
process_gone "$missing_pid" || fail "clipboard init kills stale temp-root watchers"
|
wait "$stale_pid" 2>/dev/null || true
|
||||||
process_alive "$other_pid" || fail "clipboard init preserves watchers for another existing capture script"
|
pass "clipboard reaper pattern matches running watchers"
|
||||||
kill "$other_pid" 2>/dev/null || true
|
|
||||||
wait "$other_pid" 2>/dev/null || true
|
|
||||||
pass "clipboard init cleans current and stale watchers without killing other live roots"
|
|
||||||
|
|
||||||
watch_owner="$clipboard_lifecycle_dir/watch-owner.sh"
|
watch_owner="$clipboard_lifecycle_dir/watch-owner.sh"
|
||||||
watch_pid_file="$clipboard_lifecycle_dir/watch.pid"
|
watch_pid_file="$clipboard_lifecycle_dir/watch.pid"
|
||||||
: >"$watch_log"
|
|
||||||
cat >"$watch_owner" <<SH
|
cat >"$watch_owner" <<SH
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
WL_PASTE_LOG="$watch_log" PATH="$TMPDIR/bin:\$PATH" "$ROOT/shell/plugins/clipboard/watch.sh" "$current_script" &
|
PATH="$TMPDIR/bin:\$PATH" setpriv --pdeathsig TERM wl-paste --type text --watch "$current_script" text &
|
||||||
printf '%s\n' "\$!" >"$watch_pid_file"
|
printf '%s\n' "\$!" >"$watch_pid_file"
|
||||||
wait
|
wait
|
||||||
SH
|
SH
|
||||||
@@ -331,21 +333,17 @@ owner_pid=$!
|
|||||||
PIDS_TO_KILL+=("$owner_pid")
|
PIDS_TO_KILL+=("$owner_pid")
|
||||||
|
|
||||||
for _ in {1..40}; do
|
for _ in {1..40}; do
|
||||||
[[ -s $watch_pid_file && $(wc -l <"$watch_log") -ge 2 ]] && break
|
[[ -s $watch_pid_file ]] && break
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
|
|
||||||
watch_pid=$(<"$watch_pid_file")
|
watch_pid=$(<"$watch_pid_file")
|
||||||
mapfile -t watch_child_pids < <(awk '{print $1}' "$watch_log")
|
[[ -n $watch_pid ]] && process_alive "$watch_pid" || fail "clipboard watcher starts under setpriv"
|
||||||
[[ -n $watch_pid && ${#watch_child_pids[@]} -ge 2 ]] || fail "clipboard watch helper starts text and image watchers"
|
PIDS_TO_KILL+=("$watch_pid")
|
||||||
PIDS_TO_KILL+=("$watch_pid" "${watch_child_pids[@]}")
|
|
||||||
|
|
||||||
kill "$owner_pid" 2>/dev/null || true
|
kill "$owner_pid" 2>/dev/null || true
|
||||||
process_gone "$watch_pid" || fail "clipboard watch helper exits when its owner exits"
|
process_gone "$watch_pid" || fail "clipboard watcher dies with its owner via pdeathsig"
|
||||||
for child_pid in "${watch_child_pids[@]}"; do
|
pass "clipboard watcher dies with its owner via pdeathsig"
|
||||||
process_gone "$child_pid" || fail "clipboard watch helper stops child wl-paste watchers"
|
|
||||||
done
|
|
||||||
pass "clipboard watch helper cleans up when its owner exits"
|
|
||||||
|
|
||||||
jq -n --arg text "$(printf 'large block line 1\nlarge block line 2\n')" '[{type:"text", text:"ignored"}, {type:"text", text:$text}]' >"$TMPDIR/home/.local/state/omarchy/clipboard-history.json"
|
jq -n --arg text "$(printf 'large block line 1\nlarge block line 2\n')" '[{type:"text", text:"ignored"}, {type:"text", text:$text}]' >"$TMPDIR/home/.local/state/omarchy/clipboard-history.json"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user