always-restore-to-a-connected-monitor

Issue #954: If a display is disconnected while KeeWeb is minimized,
when the window position is restored (either during the same session
or after quitting and restarting KeeWeb) it will typically be positioned
where the now disconnected display used to be, making it difficult
for the user to find the window and reposition it to a connected display.

This commit makes KeeWeb check whenever the window position is restored
to be sure there is enough of the title bar on some connected display
that the user can find and drag the window. If there is not, the window
is repositioned to the primary display.
This commit is contained in:
Coises 2018-09-23 14:31:29 -07:00
parent 61ca037357
commit 415eb11677
1 changed files with 43 additions and 7 deletions

View File

@ -162,6 +162,7 @@ function createMainWindow() {
mainWindow.webContents.on('context-menu', onContextMenu);
mainWindow.on('resize', delaySaveMainWindowPosition);
mainWindow.on('move', delaySaveMainWindowPosition);
mainWindow.on('restore', coerceMainWindowPositionToConnectedDisplay);
mainWindow.on('close', updateMainWindowPositionIfPending);
mainWindow.on('blur', mainWindowBlur);
mainWindow.on('closed', () => {
@ -193,6 +194,7 @@ function restoreMainWindow() {
}
mainWindow.setSkipTaskbar(false);
mainWindow.show();
coerceMainWindowPositionToConnectedDisplay();
setTimeout(destroyAppIcon, 0);
}
@ -236,7 +238,6 @@ function updateMainWindowPosition() {
}
mainWindowPosition.maximized = mainWindow.isMaximized();
mainWindowPosition.fullScreen = mainWindow.isFullScreen();
mainWindowPosition.displayBounds = require('electron').screen.getDisplayMatching(bounds).bounds;
mainWindowPosition.changed = true;
}
@ -256,12 +257,8 @@ function restoreMainWindowPosition() {
mainWindowPosition = JSON.parse(data);
if (mainWindow && mainWindowPosition) {
if (mainWindowPosition.width && mainWindowPosition.height) {
const displayBounds = require('electron').screen.getDisplayMatching(mainWindowPosition).bounds;
const db = mainWindowPosition.displayBounds;
if (displayBounds.x === db.x && displayBounds.y === db.y &&
displayBounds.width === db.width && displayBounds.height === db.height) {
mainWindow.setBounds(mainWindowPosition);
}
mainWindow.setBounds(mainWindowPosition);
coerceMainWindowPositionToConnectedDisplay();
}
if (mainWindowPosition.maximized) { mainWindow.maximize(); }
if (mainWindowPosition.fullScreen) { mainWindow.setFullScreen(true); }
@ -430,3 +427,42 @@ function hookRequestHeaders() {
callback({cancel: false, requestHeaders: details.requestHeaders});
});
}
// If a display is disconnected while KeeWeb is minimized, Electron does not
// ensure that the restored window appears on a display that is still connected.
// This checks to be sure the title bar is somewhere the user can grab it,
// without making it impossible to minimize and restore a window keeping it
// partially off-screen or straddling two displays if the user desires that.
function coerceMainWindowPositionToConnectedDisplay() {
const eScreen = require('electron').screen;
const displays = eScreen.getAllDisplays();
if (!displays || !displays.length) return;
const windowBounds = mainWindow.getBounds();
const contentBounds = mainWindow.getContentBounds();
const tbLeft = windowBounds.x;
const tbRight = windowBounds.x + windowBounds.width;
const tbTop = windowBounds.y;
const tbBottom = contentBounds.y;
// 160px width and 2/3s the title bar height should be enough that the user can grab it
for (let i = 0; i < displays.length; ++i) {
const workArea = displays[i].workArea;
const overlapWidth = Math.min(tbRight, workArea.x + workArea.width) - Math.max(tbLeft, workArea.x);
const overlapHeight = Math.min(tbBottom, workArea.y + workArea.height) - Math.max(tbTop, workArea.y);
if (overlapWidth >= 160 && 3 * overlapHeight >= 2 * (tbBottom - tbTop)) return;
}
// If we get here, no display contains a big enough strip of the title bar
// that we can be confident the user can drag it into visibility. Rather than
// attempt to guess what the user wants, just center it on the primary display.
// Try to keep the previous height and width, but clamp each to 90% of the workarea.
const workArea = eScreen.getPrimaryDisplay().workArea;
const newWidth = Math.min(windowBounds.width, Math.floor(0.9 * workArea.width));
const newHeight = Math.min(windowBounds.height, Math.floor(0.9 * workArea.height));
mainWindow.setBounds({
'x': workArea.x + Math.floor((workArea.width - newWidth) / 2),
'y': workArea.y + Math.floor((workArea.height - newHeight) / 2),
'width': newWidth,
'height': newHeight
});
updateMainWindowPosition();
}