Skip to content

Restore workspace window to last window size/layout/position for the workspace #7452

Description

@sharon-wang

background

#7440 sets the window.openFoldersInNewWindow default value to inherit instead of default, so that new windows opened will inherit the window size and layout from the last active Positron window. This sort of behaviour has been sought out in #3303 and #6277.

The previous default was to center the new window on screen with a default size, which resulted in:

  • a lot of us feel like we resize and reposition every single new window
  • the layout of the new window (especially the panes) are too small and have to be readjusted every time

Before #7440, a few internal users were setting window.openFoldersInNewWindow to inherit and have seen significant improvement in the new window experience, especially for those who tend to use Positron in full-screen mode or in maximized windows.

current state

Once #7440 is merged, we arrive at improved default behaviour as long as the user's last active window has a reasonable size/layout. Users can change their configuration for window.openFoldersInNewWindow back to default or to another available option if they do not prefer this new default.

the remaining gap

Still, the window and pane sizes are something that users may find themselves fiddling with regularly, especially on a workspace/project-specific level.

To some extent, the window size, positioning on screen and layout is persisted and restored when closing and reopening the same project, but there is some inconsistency.

If Positron is exited altogether and reopened, it persists the windows/layouts/positioning, but closing/reopening workspaces/projects without quitting Positron altogether has some inconsistent behaviour in restoring the window to the right size/layout/position.

Desired behaviour: when not using full-screen/maximized Positron windows, when a workspace window is closed and reopened, the window should appear on the screen in the same position, with the same size and layout, as the workspace window at the time it was last closed.

example

closing_reopening_windows.mp4

repro steps

  1. open workspaceA and position it on the left half of the screen
  2. open workspaceB and position it on the right half of the screen
  3. close workspaceA -- focus should shift to workspaceB
  4. reopen workspaceA -- expect it to open on the left half of the screen, but it may not do this

what might be going on

When Positron is exited completely (shutdown), just before shutdown, we save the state in the state service.

// Persist
const state = getWindowsStateStoreData(currentWindowsState);
this.stateService.setItem(WindowsStateHandler.windowsStateStorageKey, state);

The state is loaded the next time Positron is started up, and the size/layout/position of the windows restore as expected.

When a window is closed in Positron (the Positron app is still running, even if all windows have been closed), just before close, we update the in-memory state for the window to the current window state (size, position, etc.)

this._state.openedWindows.forEach(openedWindow => {
const sameWorkspace = isWorkspaceIdentifier(window.openedWorkspace) && openedWindow.workspace?.id === window.openedWorkspace.id;
const sameFolder = isSingleFolderWorkspaceIdentifier(window.openedWorkspace) && openedWindow.folderUri && extUriBiasedIgnorePathCase.isEqual(openedWindow.folderUri, window.openedWorkspace.uri);
if (sameWorkspace || sameFolder) {
openedWindow.uiState = state.uiState;
}
});

From debugging, it looks like that state is updated as expected, but the window size/layout/position looks to be restoring to the previously saved state from a previous shutdown of Positron.

In particular, I'd expect the window state to be loaded here, but stateForFolder is empty.

// Known Folder - load from stored settings
if (isSingleFolderWorkspaceIdentifier(workspace)) {
const stateForFolder = this.state.openedWindows.filter(openedWindow => openedWindow.folderUri && extUriBiasedIgnorePathCase.isEqual(openedWindow.folderUri, workspace.uri)).map(openedWindow => openedWindow.uiState);
if (stateForFolder.length) {
return stateForFolder[0];
}
}

It's possible we need to be storing things a bit differently in the onBeforeClose scenario to get the desired behaviour. Note that the window state/restoration code is a bit hairy, as the events are fired in a different order depending on the OS.

// Note that onBeforeShutdown() and onBeforeCloseWindow() are fired in different order depending on the OS:
// - macOS: since the app will not quit when closing the last window, you will always first get
// the onBeforeShutdown() event followed by N onBeforeCloseWindow() events for each window
// - other: on other OS, closing the last window will quit the app so the order depends on the
// user interaction: closing the last window will first trigger onBeforeCloseWindow()
// and then onBeforeShutdown(). Using the quit action however will first issue onBeforeShutdown()
// and then onBeforeCloseWindow().
//
// Here is the behavior on different OS depending on action taken (Electron 1.7.x):
//
// Legend
// - quit(N): quit application with N windows opened
// - close(1): close one window via the window close button
// - closeAll: close all windows via the taskbar command
// - onBeforeShutdown(N): number of windows reported in this event handler
// - onBeforeCloseWindow(N, M): number of windows reported and quitRequested boolean in this event handler
//
// macOS
// - quit(1): onBeforeShutdown(1), onBeforeCloseWindow(1, true)
// - quit(2): onBeforeShutdown(2), onBeforeCloseWindow(2, true), onBeforeCloseWindow(2, true)
// - quit(0): onBeforeShutdown(0)
// - close(1): onBeforeCloseWindow(1, false)
//
// Windows
// - quit(1): onBeforeShutdown(1), onBeforeCloseWindow(1, true)
// - quit(2): onBeforeShutdown(2), onBeforeCloseWindow(2, true), onBeforeCloseWindow(2, true)
// - close(1): onBeforeCloseWindow(2, false)[not last window]
// - close(1): onBeforeCloseWindow(1, false), onBeforeShutdown(0)[last window]
// - closeAll(2): onBeforeCloseWindow(2, false), onBeforeCloseWindow(2, false), onBeforeShutdown(0)
//
// Linux
// - quit(1): onBeforeShutdown(1), onBeforeCloseWindow(1, true)
// - quit(2): onBeforeShutdown(2), onBeforeCloseWindow(2, true), onBeforeCloseWindow(2, true)
// - close(1): onBeforeCloseWindow(2, false)[not last window]
// - close(1): onBeforeCloseWindow(1, false), onBeforeShutdown(0)[last window]
// - closeAll(2): onBeforeCloseWindow(2, false), onBeforeCloseWindow(2, false), onBeforeShutdown(0)
//

next steps

  • Investigate why exactly the window state is being reloaded differently when windows are closed and reopened while Positron has not been shutdown.
  • Determine if there is a bug with the window restoration, or if we need to implement a new option to support such a workflow, possibly a new option for window.openFoldersInNewWindow (something like remember, which uses the last window size/layout/position for the workspace if known, otherwise falls back to inherit behaviour?)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: layoutIssues related to IDE Layout category.area: uiIssues related to UI category.enhancementNew feature or requestinvestigateNeeds initial, limited investigation to prioritize

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions