Windows 10 introduced Virtual Desktop support. Virtual Desktops are similar to Chrome OS and Mac workspaces. A virtual desktop is a collection of windows. Every window belongs to a virtual desktop. When a virtual desktop is selected to be active, the windows associated with that virtual desktop are displayed on the screen. When a virtual desktop is hidden, all of its windows are also hidden. This enables the user to create multiple working environments and to switch between them. An app (e.g., Chromium) can have windows open on different virtual desktops, and thus may need to be Virtual Desktop-aware.
The user-facing Chromium support for virtual desktops consists of two things:
- When launching the browser with session restore, browser windows are moved to the virtual desktop they were on when the browser shutdown.
- When opening a URL with the browser, either open it in a window on the current virtual desktop, or open a new window on the current virtual desktop. Don't open it in a tab in a window on another virtual desktop.
The core UI principles are that windows should be restored to the desktop they were shut down on, and opening an app window shouldn't change the current virtual desktop. Only the user should be able to change virtual desktops, or move windows between virtual desktops.
Windows 10 exposes the COM interface IVirtualDesktopManager to access the Virtual Desktop functionality. To make sure that opening a URL stays on the current virtual desktop, BrowserView::IsOnCurrentWorkspace uses the IVirtualDesktopManager method IsWindowOnCurrentVirtualDesktop. BrowserMatches in browser_finder.cc only returns a browser window on the current desktop.
To restore browser windows to the desktop they were last open on, BrowserDesktopWindowTreeHostWin implements GetWorkspace by using the GetWindowDesktopId method on IVirtualDesktopManager, and restores the workspace using MoveWindowToDesktop, in its ::Init method.
The actual implementation is a bit more complicated in order to avoid calling COM methods on the UI thread, or destroying COM objects on the UI thread, since doing so can cause nested message loops and re-entrant calls, leading to blocked UI threads and crashes. The VirtualDesktopHelper class does the workspace handling for BrowserDesktopWindowTreeHostWin, including doing all the COM operations on a separate COM task runner. The GetWorkspace method is synchronous so VirtualDesktopHelper has to remember and return the most recent virtual desktop. Windows has no notification of a window changing virtual desktops, so BrowserDesktopWindowTreeHostWin updates the virtual desktop of a window whenever it gets focus, and if it has changed, calls WindowTreeHost::OnHostWorkspaceChanged. This means that if a window is moved to a different virtual desktop, but doesn't get focus before the browser is shut down, the browser window will be restored to the previous virtual desktop.
Windows on different virtual desktops share the same coordinate system, so code that iterates over windows generally needs to be Virtual Desktop-aware. For example, the following places in code ignore windows not on the current virtual desktop:
- LocalProcessWindowFinder::GetProcessWindowAtPoint
- third_party/webrtc/modules/desktop_capture/win/window_capture_utils.cc
- Native Window occlusion tracker, when determining if a Chromium window is occluded/covered by other windows. Windows not on the current virtual desktop are considered occluded.