Skip to content

Commit

Permalink
Ensure window is visible on some display during state validation
Browse files Browse the repository at this point in the history
  • Loading branch information
MathieuDebit committed Nov 20, 2018
1 parent 91146ae commit 477f3db
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 7 deletions.
25 changes: 24 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ module.exports = function (options) {
};
}

function windowWithinBounds(state, bounds) {
return (
state.x >= bounds.x &&
state.y >= bounds.y &&
state.x + state.width <= bounds.x + bounds.width &&
state.y + state.height <= bounds.y + bounds.height
);
}

function ensureWindowVisibleOnSomeDisplay() {
const visible = screen.getAllDisplays().some(display => {
return windowWithinBounds(state, display.bounds);
});

if (!visible) {
// Window is partially or fully not visible now.
// Reset it to safe defaults.
return resetStateToDefault();
}
}

function validateState() {
const isValid = state && (hasBounds() || state.isMaximized || state.isFullScreen);
if (!isValid) {
Expand All @@ -57,7 +78,9 @@ module.exports = function (options) {
// Check if the display where the window was last open is still available
const displayBounds = screen.getDisplayMatching(state).bounds;
const sameBounds = deepEqual(state.displayBounds, displayBounds, {strict: true});
if (!sameBounds) {
if (sameBounds) {
ensureWindowVisibleOnSomeDisplay();
} else {
resetStateToDefault();
}
}
Expand Down
101 changes: 95 additions & 6 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ test.before(() => {
app: {getPath() {return '/temp';}},
screen: {
getDisplayMatching() {},
getPrimaryDisplay() {}
getPrimaryDisplay() {},
getAllDisplays() {}
}
};
mockery.registerAllowables(['./', 'path', 'object-assign', 'deep-equal', 'sinon', './lib/keys.js', './lib/is_arguments.js']);
Expand Down Expand Up @@ -180,20 +181,98 @@ test('saves the state to the file system', t => {
mkdirp.sync.restore();
});

test('Validate state if saved display is available', t => {
const displayBounds = {x: -2560, y: -480, width: 2560, height: 1440};
test('Validate state if saved display is available and primary', t => {
const displayBounds = {x: 0, y: 0, width: 1920, height: 1080};

const jsonfile = require('jsonfile');
sinon.stub(jsonfile, 'readFileSync').returns({
x: -2000,
y: -1000,
x: 10,
y: 20,
width: 800,
height: 600,
displayBounds
});

const {screen} = require('electron');
sinon.stub(screen, 'getDisplayMatching').returns({bounds: displayBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: displayBounds});
sinon.stub(screen, 'getAllDisplays').returns([{bounds: displayBounds}]);

const state = require('.')({
defaultWidth: 500,
defaultHeight: 300
});

t.is(state.x, 10);
t.is(state.y, 20);
t.is(state.width, 800);
t.is(state.height, 600);
t.is(state.displayBounds, displayBounds);

jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

test('Validate state if saved display is available and secondary on right', t => {
const primaryDisplayBounds = {x: 0, y: 0, width: 1920, height: 1080};
const secondaryDisplayBounds = {x: 1920, y: 0, width: 2560, height: 1440};

const jsonfile = require('jsonfile');
sinon.stub(jsonfile, 'readFileSync').returns({
x: 2000,
y: 1100,
width: 800,
height: 300,
displayBounds: secondaryDisplayBounds
});

const {screen} = require('electron');
sinon.stub(screen, 'getDisplayMatching').returns({bounds: secondaryDisplayBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: primaryDisplayBounds});
sinon.stub(screen, 'getAllDisplays').returns([
{bounds: primaryDisplayBounds},
{bounds: secondaryDisplayBounds}
]);

const state = require('.')({
defaultWidth: 500,
defaultHeight: 300
});

t.is(state.x, 2000);
t.is(state.y, 1100);
t.is(state.width, 800);
t.is(state.height, 300);
t.is(state.displayBounds, secondaryDisplayBounds);

jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

test('Validate state if saved display is available and secondary on left', t => {
const primaryDisplayBounds = {x: 0, y: 0, width: 1920, height: 1080};
const secondaryDisplayBounds = {x: -2560, y: -480, width: 2560, height: 1440};

const jsonfile = require('jsonfile');
sinon.stub(jsonfile, 'readFileSync').returns({
x: -2000,
y: -1000,
width: 800,
height: 600,
displayBounds: secondaryDisplayBounds
});

const {screen} = require('electron');
sinon.stub(screen, 'getDisplayMatching').returns({bounds: secondaryDisplayBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: primaryDisplayBounds});
sinon.stub(screen, 'getAllDisplays').returns([
{bounds: primaryDisplayBounds},
{bounds: secondaryDisplayBounds}
]);

const state = require('.')({
defaultWidth: 500,
Expand All @@ -204,10 +283,12 @@ test('Validate state if saved display is available', t => {
t.is(state.y, -1000);
t.is(state.width, 800);
t.is(state.height, 600);
t.is(state.displayBounds, displayBounds);
t.is(state.displayBounds, secondaryDisplayBounds);

jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

test('Validate state if saved display is available but window outside display bounds', t => {
Expand All @@ -226,6 +307,7 @@ test('Validate state if saved display is available but window outside display bo
const screenBounds = {x: 0, y: 0, width: 1680, height: 1050};
sinon.stub(screen, 'getDisplayMatching').returns({bounds: screenBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: screenBounds});
sinon.stub(screen, 'getAllDisplays').returns([{bounds: screenBounds}]);

const state = require('.')({
defaultWidth: 500,
Expand All @@ -241,6 +323,7 @@ test('Validate state if saved display is available but window outside display bo
jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

test('Ensure window is visible at startup if saved display is unavailable and was on the right', t => {
Expand All @@ -257,6 +340,7 @@ test('Ensure window is visible at startup if saved display is unavailable and wa
const screenBounds = {x: 0, y: 0, width: 1920, height: 1080};
sinon.stub(screen, 'getDisplayMatching').returns({bounds: screenBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: screenBounds});
sinon.stub(screen, 'getAllDisplays').returns([{bounds: screenBounds}]);

const state = require('.')({
defaultWidth: 500,
Expand All @@ -271,6 +355,7 @@ test('Ensure window is visible at startup if saved display is unavailable and wa
jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

test('Ensure window is visible at startup if saved display is unavailable and was on the left', t => {
Expand All @@ -287,6 +372,7 @@ test('Ensure window is visible at startup if saved display is unavailable and wa
const screenBounds = {x: 0, y: 0, width: 1920, height: 1080};
sinon.stub(screen, 'getDisplayMatching').returns({bounds: screenBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: screenBounds});
sinon.stub(screen, 'getAllDisplays').returns([{bounds: screenBounds}]);

const state = require('.')({
defaultWidth: 500,
Expand All @@ -301,6 +387,7 @@ test('Ensure window is visible at startup if saved display is unavailable and wa
jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

test('Reset state to default values if saved display is unavailable', t => {
Expand All @@ -317,6 +404,7 @@ test('Reset state to default values if saved display is unavailable', t => {
const screenBounds = {x: 0, y: 0, width: 1920, height: 1080};
sinon.stub(screen, 'getDisplayMatching').returns({bounds: screenBounds});
sinon.stub(screen, 'getPrimaryDisplay').returns({bounds: screenBounds});
sinon.stub(screen, 'getAllDisplays').returns([{bounds: screenBounds}]);

const state = require('.')({
defaultWidth: 500,
Expand All @@ -332,4 +420,5 @@ test('Reset state to default values if saved display is unavailable', t => {
jsonfile.readFileSync.restore();
screen.getDisplayMatching.restore();
screen.getPrimaryDisplay.restore();
screen.getAllDisplays.restore();
});

0 comments on commit 477f3db

Please sign in to comment.