fix(web): run navigator.clipboard.write only when window has focus (#858)
Some checks failed
CI / Check formatting (push) Has been cancelled
CI / Check typos (push) Has been cancelled
Coverage / Coverage Report (push) Has been cancelled
Release crates / Open release PR (push) Has been cancelled
Release crates / Release crates (push) Has been cancelled
CI / Success (push) Has been cancelled
CI / Checks [linux] (push) Has been cancelled
CI / Checks [macos] (push) Has been cancelled
CI / Checks [windows] (push) Has been cancelled
CI / Fuzzing (push) Has been cancelled
CI / Web Client (push) Has been cancelled
CI / FFI (push) Has been cancelled

When we receive clipboard update from the server and the browser window
is not in focus (for example, when the user copies some text directly on
the machine, not via the browser's VNC viewer), we got an error that
`navigator.clipboard.write` is not allowed when window is not in focus.
This PR adds a window check that the window has focus, and now
`clipboard.write` runs only when the window is in focus.
This commit is contained in:
Alex Yusiuk 2025-07-04 14:21:52 +03:00 committed by GitHub
parent a84a5c0571
commit 4dc5945019
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -72,6 +72,7 @@
let lastClipboardMonitorLoopError: Error | null = null;
let componentDestroyed = false;
let runWhenFocusedQueue: (() => void)[] = [];
/* Firefox-specific BEGIN */
@ -173,13 +174,23 @@
}
}
function runWhenWindowFocused(fn: () => void) {
if (document.hasFocus()) {
fn();
} else {
runWhenFocusedQueue.push(fn);
}
}
// This callback is required to update client clipboard state when remote side has changed.
function onRemoteClipboardChanged(data: ClipboardData) {
try {
const mime_formats = clipboardDataToRecord(data);
const clipboard_item = new ClipboardItem(mime_formats);
runWhenWindowFocused(() => {
lastReceivedClipboardData = clipboardDataToClipboardItemsRecord(data);
navigator.clipboard.write([clipboard_item]);
});
} catch (err) {
console.error('Failed to set client clipboard: ' + err);
}
@ -445,6 +456,8 @@
window.addEventListener('keydown', captureKeys, false);
window.addEventListener('keyup', captureKeys, false);
window.addEventListener('focus', focusEventHandler);
}
function resetHostStyle() {
@ -717,6 +730,13 @@
inner.dispatchEvent(new CustomEvent('ready', { detail: result, bubbles: true, composed: true }));
}
function focusEventHandler() {
while (runWhenFocusedQueue.length > 0) {
const fn = runWhenFocusedQueue.shift();
fn?.();
}
}
onMount(async () => {
loggingService.verbose = verbose === 'true';
loggingService.info('Dom ready');
@ -726,6 +746,7 @@
onDestroy(() => {
window.removeEventListener('resize', resizeHandler);
window.removeEventListener('focus', focusEventHandler);
componentDestroyed = true;
});
</script>