According to the windows.onFocusChanged event documentation, it returns either the focused window’s ID, or -1 (windows.WINDOW_ID_NONE).
Will be windows.WINDOW_ID_NONE if all browser windows have lost focus.
But…
In Windows and some Linux window managers, WINDOW_ID_NONE will always be sent immediately preceding a switch from one browser window to another.
meaning on some (most) OSes (e.g. Windows), a focus switch between windows fires this event twice, one returning -1 and the other a windowId. While on others (e.g. MacOS), only one is fired, returning windowId. And I suppose all OSes fire just one, returning -1, when no window has focus.
Given the need to check for these twin simultaneous events, what is the best way to detect each of these conditions on any platform?
Thanks @juraj.masiar for that idea. I’ve come up with something using windows.getLastFocused() and manual tracking of focus instead:
(For brevity, browser.windows.WindowState.MINIMIZED = 'minimized' and browser.windows.WINDOW_ID_NONE = -1)
// Manually track which window has focus.
// This is how we find out which window was defocused and whether it was/is minimized.
const FocusedWindowId = {
set: focusedWindowId => browser.storage.session.set({ focusedWindowId }),
get: async () => (await browser.storage.session.get('focusedWindowId')).focusedWindowId,
}
function handleDefocusedWindow(window) {
console.log(`windowId ${window.id} defocused ${window.state === 'minimized' ? 'and minimized' : ''}`);
}
browser.windows.onFocusChanged.addListener(async focusedWindowId => {
// focusedWindowId is -1 when a window loses focus in Windows and some Linux window managers, or only when no window has focus in MacOS and others.
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows/onFocusChanged
// Hence when a window switch happens, this event is fired twice in Windows et al: from the defocused window (-1) and from the focused window.
if (focusedWindowId === -1) {
const lastFocusedWindow = await browser.windows.getLastFocused();
if (lastFocusedWindow.focused) {
// We are in Windows et al - the counterpart event capture will handle the focused window separately
} else {
handleDefocusedWindow(lastFocusedWindow);
FocusedWindowId.set(null);
console.log('No window is focused');
}
return;
}
const defocusedWindowId = await FocusedWindowId.get();
const defocusedWindow = defocusedWindowId && await browser.windows.get(defocusedWindowId).catch(() => null);
if (defocusedWindow)
handleDefocusedWindow(defocusedWindow);
FocusedWindowId.set(focusedWindowId);
});