From 234ac7b3b6f791b3d1cfebea94e2e446ca005945 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 28 Jul 2026 08:09:45 -0700 Subject: [PATCH] Bring back clipboard watchers that die Clipboard history is fed by two wl-paste --watch processes started once when the shell loads. When one dies, nothing notices: copying still works, the picker still opens, and the old entries are all still there, so history just silently stops recording until the next shell reload. Respawn them on exit instead. The one-shot timer both coalesces the case where both watchers die together and keeps a wl-paste that cannot start at all from spinning as fast as fork allows. Co-Authored-By: Claude Opus 5 (1M context) --- shell/plugins/clipboard/Clipboard.qml | 15 +++++++++++++++ test/shell.d/clipboard-test.sh | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/shell/plugins/clipboard/Clipboard.qml b/shell/plugins/clipboard/Clipboard.qml index 95a04f7f..fde49b3f 100644 --- a/shell/plugins/clipboard/Clipboard.qml +++ b/shell/plugins/clipboard/Clipboard.qml @@ -283,6 +283,7 @@ Item { Process { id: textWatchProc command: ["setpriv", "--pdeathsig", "TERM", "wl-paste", "--type", "text", "--watch", root.captureScript, "text"] + onExited: watchRestartTimer.restart() stdout: SplitParser { onRead: function(data) { root.addClipboardJson(data) } } @@ -291,11 +292,25 @@ Item { Process { id: imageWatchProc command: ["setpriv", "--pdeathsig", "TERM", "wl-paste", "--type", "image/png", "--watch", root.captureScript, "image/png"] + onExited: watchRestartTimer.restart() stdout: SplitParser { onRead: function(data) { root.addClipboardJson(data) } } } + // A watcher that dies takes clipboard history with it, silently: copying still + // works, the picker still opens, and the old entries are all still there, so + // nothing recorded until the next shell reload. Bring it back instead. + Timer { + id: watchRestartTimer + interval: 1000 + repeat: false + onTriggered: { + if (!textWatchProc.running) textWatchProc.running = true + if (!imageWatchProc.running) imageWatchProc.running = true + } + } + PanelWindow { id: panel visible: root.opened diff --git a/test/shell.d/clipboard-test.sh b/test/shell.d/clipboard-test.sh index 055c3e66..d3d839ab 100644 --- a/test/shell.d/clipboard-test.sh +++ b/test/shell.d/clipboard-test.sh @@ -174,6 +174,11 @@ assert( clipboardQml.includes('command: ["pkill", "-f", "wl-paste .*--watch .*/shell/plugins/clipboard/capture\\\\.sh"]'), 'clipboard init reaps stale watchers before starting new ones' ) +assertEqual( + (clipboardQml.match(/onExited: watchRestartTimer\.restart\(\)/g) || []).length, + 2, + 'clipboard respawns both watchers when they die' +) JS TMPDIR=$(mktemp -d)