Prevent clipboard capture hangs (#9488)
* Bound clipboard capture reads * Bound the watched clipboard read and drop copies cut off at the deadline In watch mode capture.sh reads the copy from the owner's pipe on stdin, to EOF, with no bound. An owner that stalls without closing its end keeps the callback alive, and wl-paste --watch handles no further clipboard events until it exits. That matches #9443, whose stuck capture.sh had no wl-paste child: --list-types never reads from the owner. Every read now goes through one bounded reader into a temporary file, and the copy is recorded only when the read finished, so a snapshot that stalls halfway no longer records its first half. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Omarchybot <317366263+omarchybot@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2 files changed
+73
-12
No files matched your search
@@ -10,25 +10,31 @@ STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy"
|
||||
IMAGE_DIR="$STATE_DIR/clipboard-images"
|
||||
mkdir -p "$IMAGE_DIR"
|
||||
|
||||
types=$(wl-paste --list-types 2>/dev/null || true)
|
||||
types=$(timeout 2s wl-paste --list-types 2>/dev/null || true)
|
||||
|
||||
if [[ ${CLIPBOARD_STATE:-} == "sensitive" ]] || grep -qx 'x-kde-passwordManagerHint' <<<"$types"; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
tmp=
|
||||
trap 'rm -f -- "$tmp"' EXIT
|
||||
|
||||
# The clipboard owner streams the copy and can stall without closing its end, so
|
||||
# every read is bounded, and a copy cut off at the deadline is dropped, not kept.
|
||||
read_copy() {
|
||||
timeout 2s "$@" >"$tmp" 2>/dev/null && [[ -s $tmp ]]
|
||||
}
|
||||
|
||||
emit_image() {
|
||||
local mime="$1"
|
||||
local ext tmp hash file
|
||||
local ext hash file
|
||||
shift
|
||||
|
||||
ext=${mime#image/}
|
||||
[[ $ext == jpeg ]] && ext=jpg
|
||||
|
||||
tmp=$(mktemp --tmpdir="$IMAGE_DIR" clipboard.XXXXXX) || return 0
|
||||
cat >"$tmp"
|
||||
if [[ ! -s $tmp ]]; then
|
||||
rm -f "$tmp"
|
||||
return 0
|
||||
fi
|
||||
read_copy "$@" || return
|
||||
|
||||
hash=$(sha256sum "$tmp" | awk '{print $1}')
|
||||
file="$IMAGE_DIR/$hash.$ext"
|
||||
@@ -43,6 +49,9 @@ emit_image() {
|
||||
}
|
||||
|
||||
emit_text() {
|
||||
tmp=$(mktemp --tmpdir="$STATE_DIR" clipboard.XXXXXX) || return 0
|
||||
read_copy "$@" || return
|
||||
|
||||
perl -MEncode=decode,FB_CROAK,LEAVE_SRC -MJSON::PP=encode_json -0777 -e '
|
||||
my $raw = <STDIN>;
|
||||
exit unless length $raw;
|
||||
@@ -86,21 +95,21 @@ emit_text() {
|
||||
}
|
||||
$text = decode("UTF-8", $raw) unless defined $text;
|
||||
print "{\"type\":\"text\",\"text\":", encode_json($text), "}\n";
|
||||
'
|
||||
' <"$tmp"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
text) emit_text; exit 0 ;;
|
||||
image/*) emit_image "$1"; exit 0 ;;
|
||||
text) emit_text cat; exit 0 ;;
|
||||
image/*) emit_image "$1" cat; exit 0 ;;
|
||||
esac
|
||||
|
||||
for mime in image/png image/jpeg image/webp image/gif image/bmp image/tiff; do
|
||||
if grep -qx "$mime" <<<"$types"; then
|
||||
timeout 2s wl-paste --type "$mime" 2>/dev/null | emit_image "$mime"
|
||||
emit_image "$mime" wl-paste --type "$mime"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
if grep -q '^text/' <<<"$types" || grep -qx 'UTF8_STRING' <<<"$types" || grep -qx 'STRING' <<<"$types"; then
|
||||
wl-paste --type text --no-newline 2>/dev/null | emit_text
|
||||
emit_text wl-paste --type text --no-newline
|
||||
fi
|
||||
Reference in new issue
Block a user