Skip to content

Commit 4dc5945

Browse files
fix(web): run navigator.clipboard.write only when window has focus (#858)
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.
1 parent a84a5c0 commit 4dc5945

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

web-client/iron-remote-desktop/src/iron-remote-desktop.svelte

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
let lastClipboardMonitorLoopError: Error | null = null;
7373
7474
let componentDestroyed = false;
75+
let runWhenFocusedQueue: (() => void)[] = [];
7576
7677
/* Firefox-specific BEGIN */
7778
@@ -173,13 +174,23 @@
173174
}
174175
}
175176
177+
function runWhenWindowFocused(fn: () => void) {
178+
if (document.hasFocus()) {
179+
fn();
180+
} else {
181+
runWhenFocusedQueue.push(fn);
182+
}
183+
}
184+
176185
// This callback is required to update client clipboard state when remote side has changed.
177186
function onRemoteClipboardChanged(data: ClipboardData) {
178187
try {
179188
const mime_formats = clipboardDataToRecord(data);
180189
const clipboard_item = new ClipboardItem(mime_formats);
181-
lastReceivedClipboardData = clipboardDataToClipboardItemsRecord(data);
182-
navigator.clipboard.write([clipboard_item]);
190+
runWhenWindowFocused(() => {
191+
lastReceivedClipboardData = clipboardDataToClipboardItemsRecord(data);
192+
navigator.clipboard.write([clipboard_item]);
193+
});
183194
} catch (err) {
184195
console.error('Failed to set client clipboard: ' + err);
185196
}
@@ -445,6 +456,8 @@
445456
446457
window.addEventListener('keydown', captureKeys, false);
447458
window.addEventListener('keyup', captureKeys, false);
459+
460+
window.addEventListener('focus', focusEventHandler);
448461
}
449462
450463
function resetHostStyle() {
@@ -717,6 +730,13 @@
717730
inner.dispatchEvent(new CustomEvent('ready', { detail: result, bubbles: true, composed: true }));
718731
}
719732
733+
function focusEventHandler() {
734+
while (runWhenFocusedQueue.length > 0) {
735+
const fn = runWhenFocusedQueue.shift();
736+
fn?.();
737+
}
738+
}
739+
720740
onMount(async () => {
721741
loggingService.verbose = verbose === 'true';
722742
loggingService.info('Dom ready');
@@ -726,6 +746,7 @@
726746
727747
onDestroy(() => {
728748
window.removeEventListener('resize', resizeHandler);
749+
window.removeEventListener('focus', focusEventHandler);
729750
componentDestroyed = true;
730751
});
731752
</script>

0 commit comments

Comments
 (0)