Question
The standard window visibility events used to track regular app windows (for example, to deactivate apps when they are minimized or running as a background tab) do not give a complete picture for apps that run inside Workspaces. How can you determine whether a window inside a Workspace is currently visible, and how can you react to changes in its visibility?
Answer
The snippet below covers visible windows that are part of Workspaces. It does not replace the standard visibility handling for regular floating windows.
const isWindowVisible = async (windowId) => {
const allWorkspaces = await io.workspaces.getAllWorkspaces();
const workspaceWithWindow = allWorkspaces.find((wsp) => {
const allWindows = wsp.getAllWindows();
return allWindows.find((win) => win.id === windowId);
});
if (!workspaceWithWindow) {
// handle the case where the window is not found in any workspace
return false;
}
const isWorkspaceSelected = workspaceWithWindow.isSelected;
const frameState = await workspaceWithWindow.frame.state();
const isFrameNormalOrMaximized = frameState === 'normal' || frameState === 'maximized';
const workspaceWindow = workspaceWithWindow.getAllWindows().find((win) => win.id === windowId);
const isWindowSelected = workspaceWindow.isSelected;
// A window is considered visible if its workspace is selected,
// the workspace frame is either normal or maximized,
// and the window itself is selected.
return isWorkspaceSelected && isFrameNormalOrMaximized && isWindowSelected;
};
const onWindowVisibilityChange = async (windowId, callback) => {
const allWorkspaces = await io.workspaces.getAllWorkspaces();
const workspaceWithWindow = allWorkspaces.find((wsp) => {
const allWindows = wsp.getAllWindows();
return allWindows.find((win) => win.id === windowId);
});
if (!workspaceWithWindow) {
// handle the case where the window is not found in any workspace
return () => { };
}
// Pre-populating the initial state
let isWorkspaceSelected = workspaceWithWindow.isSelected;
const frameState = await workspaceWithWindow.frame.state();
let isFrameNormalOrMaximized = frameState === 'normal' || frameState === 'maximized';
const workspaceWindow = workspaceWithWindow.getAllWindows().find((win) => win.id === windowId);
let isWindowSelected = workspaceWindow.isSelected;
const triggerCallback = () => {
// A window is considered visible if its workspace is selected,
// the workspace frame is either normal or maximized,
// and the window itself is selected.
const isVisible = isFrameNormalOrMaximized && isWindowSelected && isWorkspaceSelected;
callback(isVisible);
};
const minimizedUnsub = await workspaceWithWindow.frame.onMinimized(() => {
isFrameNormalOrMaximized = false;
triggerCallback();
});
const restoredUnsub = await workspaceWithWindow.frame.onNormal(() => {
isFrameNormalOrMaximized = true;
triggerCallback();
});
const maximizedUnsub = await workspaceWithWindow.frame.onMaximized(() => {
isFrameNormalOrMaximized = true;
triggerCallback();
});
const workspaceSelectedUnsub = await workspaceWithWindow.frame.onWorkspaceSelected((w) => {
if (w.id === workspaceWithWindow.id) {
isWorkspaceSelected = true;
} else {
isWorkspaceSelected = false;
}
triggerCallback();
});
const windowSelectedUnsub = await workspaceWithWindow.onWindowSelected((win) => {
if (win.id === windowId) {
isWindowSelected = true;
} else {
isWindowSelected = false;
}
triggerCallback();
});
triggerCallback();
return () => {
minimizedUnsub();
restoredUnsub();
maximizedUnsub();
workspaceSelectedUnsub();
windowSelectedUnsub();
}
};
A window inside a Workspace is considered visible when:
-
The Workspace that contains the window is the selected (active) Workspace in its Frame.
-
The Frame that hosts the Workspace is in
normalormaximizedstate (i.e. not minimized). -
The window itself is the selected window within its tab group in the Workspace.