diff --git a/app/browser/reducers/tabsReducer.js b/app/browser/reducers/tabsReducer.js index c57d8571385..78665f7e378 100644 --- a/app/browser/reducers/tabsReducer.js +++ b/app/browser/reducers/tabsReducer.js @@ -373,7 +373,7 @@ const tabsReducer = (state, action, immutableAction) => { if (dragData && dragData.get('type') === dragTypes.TAB) { const frame = dragData.get('data') const frameOpts = frameOptsFromFrame(frame).toJS() - const browserOpts = { positionByMouseCursor: true } + const browserOpts = { positionByMouseCursor: true, checkMaximized: true } frameOpts.indexByFrameKey = dragData.getIn(['dragOverData', 'draggingOverKey']) frameOpts.prependIndexByFrameKey = dragData.getIn(['dragOverData', 'draggingOverLeftHalf']) tabs.moveTo(state, frame.get('tabId'), frameOpts, browserOpts, dragData.get('dropWindowId')) diff --git a/app/browser/reducers/windowsReducer.js b/app/browser/reducers/windowsReducer.js index 233bdc4132b..3487c4e496f 100644 --- a/app/browser/reducers/windowsReducer.js +++ b/app/browser/reducers/windowsReducer.js @@ -44,20 +44,22 @@ const navbarHeight = () => { */ const setWindowDimensions = (browserOpts, defaults, immutableWindowState) => { assert(isImmutable(immutableWindowState)) - if (immutableWindowState.getIn(['ui', 'size'])) { - browserOpts.width = firstDefinedValue(browserOpts.width, immutableWindowState.getIn(['ui', 'size', 0])) - browserOpts.height = firstDefinedValue(browserOpts.height, immutableWindowState.getIn(['ui', 'size', 1])) - } - browserOpts.width = firstDefinedValue(browserOpts.width, browserOpts.innerWidth, defaults.width) - // height and innerHeight are the frame webview size - browserOpts.height = firstDefinedValue(browserOpts.height, browserOpts.innerHeight) - if (typeof browserOpts.height === 'number') { - // add navbar height to get total height for BrowserWindow - browserOpts.height = browserOpts.height + navbarHeight() + if (immutableWindowState.getIn(['windowInfo'])) { + browserOpts.width = firstDefinedValue(browserOpts.width, immutableWindowState.getIn(['windowInfo', 'width'])) + browserOpts.height = firstDefinedValue(browserOpts.height, immutableWindowState.getIn(['windowInfo', 'height'])) } else { - // no inner height so check outer height or use default - browserOpts.height = firstDefinedValue(browserOpts.outerHeight, defaults.height) + browserOpts.width = firstDefinedValue(browserOpts.width, browserOpts.innerWidth, defaults.width) + // height and innerHeight are the frame webview size + browserOpts.height = firstDefinedValue(browserOpts.height, browserOpts.innerHeight) + if (typeof browserOpts.height === 'number') { + // add navbar height to get total height for BrowserWindow + browserOpts.height = browserOpts.height + navbarHeight() + } else { + // no inner height so check outer height or use default + browserOpts.height = firstDefinedValue(browserOpts.outerHeight, defaults.height) + } } + return browserOpts } @@ -69,10 +71,10 @@ const setWindowPosition = (browserOpts, defaults, immutableWindowState) => { const screenPos = electron.screen.getCursorScreenPoint() browserOpts.x = screenPos.x browserOpts.y = screenPos.y - } else if (immutableWindowState.getIn(['ui', 'position'])) { + } else if (immutableWindowState.getIn(['windowInfo'])) { // Position comes from window state - browserOpts.x = firstDefinedValue(browserOpts.x, immutableWindowState.getIn(['ui', 'position', 0])) - browserOpts.y = firstDefinedValue(browserOpts.y, immutableWindowState.getIn(['ui', 'position', 1])) + browserOpts.x = firstDefinedValue(browserOpts.x, immutableWindowState.getIn(['windowInfo', 'left'])) + browserOpts.y = firstDefinedValue(browserOpts.y, immutableWindowState.getIn(['windowInfo', 'top'])) } else if (typeof defaults.x === 'number' && typeof defaults.y === 'number') { // Position comes from the default position browserOpts.x = firstDefinedValue(browserOpts.x, defaults.x) @@ -85,6 +87,18 @@ const setWindowPosition = (browserOpts, defaults, immutableWindowState) => { return browserOpts } +const setMaximized = (state, browserOpts, immutableWindowState) => { + if (Object.keys(browserOpts).length > 0 && !browserOpts.checkMaximized) { + return false + } + + if (immutableWindowState.getIn(['windowInfo'])) { + return immutableWindowState.getIn(['windowInfo', 'state']) === 'maximized' + } + + return state.getIn(['defaultWindowParams', 'maximized']) || false +} + function windowDefaults (state) { return { show: false, @@ -116,6 +130,7 @@ function setDefaultWindowSize (state) { if (!state) { return } + const screen = electron.screen const primaryDisplay = screen.getPrimaryDisplay() if (!state.getIn(['defaultWindowParams', 'width']) && !state.get('defaultWindowWidth') && @@ -133,6 +148,7 @@ const createWindow = (state, action) => { const immutableWindowState = action.get('restoredState') || Immutable.Map() state = setDefaultWindowSize(state) const defaults = windowDefaults(state) + const isMaximized = setMaximized(state, browserOpts, immutableWindowState) browserOpts = setWindowDimensions(browserOpts, defaults, immutableWindowState) browserOpts = setWindowPosition(browserOpts, defaults, immutableWindowState) @@ -141,9 +157,18 @@ const createWindow = (state, action) => { delete browserOpts.top const screen = electron.screen - const primaryDisplay = screen.getPrimaryDisplay() + let primaryDisplay = screen.getPrimaryDisplay() const parentWindowKey = browserOpts.parentWindowKey - const parentWindow = parentWindowKey ? BrowserWindow.fromId(parentWindowKey) : BrowserWindow.getFocusedWindow() + if (browserOpts.x != null && browserOpts.y != null) { + const matchingDisplay = screen.getDisplayMatching(browserOpts) + if (matchingDisplay != null) { + primaryDisplay = matchingDisplay + } + } + + const parentWindow = parentWindowKey + ? BrowserWindow.fromId(parentWindowKey) + : BrowserWindow.getFocusedWindow() const bounds = parentWindow ? parentWindow.getBounds() : primaryDisplay.bounds // position on screen should be relative to focused window @@ -207,6 +232,10 @@ const createWindow = (state, action) => { windowProps.icon = path.join(__dirname, '..', '..', 'res', 'app.png') } + if (immutableWindowState.getIn(['windowInfo', 'state']) === 'fullscreen') { + windowProps.fullscreen = true + } + const homepageSetting = getSetting(settings.HOMEPAGE) const startupSetting = getSetting(settings.STARTUP_MODE) const toolbarUserInterfaceScale = getSetting(settings.TOOLBAR_UI_SCALE) @@ -218,7 +247,7 @@ const createWindow = (state, action) => { // initialize frames state let frames = Immutable.List() - if (restoredImmutableWindowState) { + if (restoredImmutableWindowState && restoredImmutableWindowState.get('frames', Immutable.List()).size > 0) { frames = restoredImmutableWindowState.get('frames') restoredImmutableWindowState = restoredImmutableWindowState.set('frames', Immutable.List()) restoredImmutableWindowState = restoredImmutableWindowState.set('tabs', Immutable.List()) @@ -242,14 +271,10 @@ const createWindow = (state, action) => { frames = Immutable.fromJS([{}]) } - if (immutableWindowState.getIn(['ui', 'isMaximized'])) { + if (isMaximized) { mainWindow.maximize() } - if (immutableWindowState.getIn(['ui', 'isFullScreen'])) { - mainWindow.setFullScreen(true) - } - mainWindow.webContents.on('did-finish-load', (e) => { const appStore = require('../../../js/stores/appStore') mainWindow.webContents.setZoomLevel(zoomLevel[toolbarUserInterfaceScale] || 0.0) @@ -310,15 +335,13 @@ const windowsReducer = (state, action, immutableAction) => { break case appConstants.APP_WINDOW_UPDATED: state = windowState.maybeCreateWindow(state, action) - break - case appConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED: - if (action.get('size')) { - state = state.setIn(['defaultWindowParams', 'width'], action.getIn(['size', 0])) - state = state.setIn(['defaultWindowParams', 'height'], action.getIn(['size', 1])) - } - if (action.get('position')) { - state = state.setIn(['defaultWindowParams', 'x'], action.getIn(['position', 0])) - state = state.setIn(['defaultWindowParams', 'y'], action.getIn(['position', 1])) + if (action.get('updateDefault')) { + state = state + .setIn(['defaultWindowParams', 'width'], action.getIn(['windowValue', 'width'])) + .setIn(['defaultWindowParams', 'height'], action.getIn(['windowValue', 'height'])) + .setIn(['defaultWindowParams', 'x'], action.getIn(['windowValue', 'x'])) + .setIn(['defaultWindowParams', 'y'], action.getIn(['windowValue', 'y'])) + .setIn(['defaultWindowParams', 'maximized'], action.getIn(['windowValue', 'state']) === 'maximized') } break case windowConstants.WINDOW_SHOULD_SET_TITLE: diff --git a/app/browser/windows.js b/app/browser/windows.js index 99284906926..9cd26606ce1 100644 --- a/app/browser/windows.js +++ b/app/browser/windows.js @@ -18,6 +18,7 @@ const windowState = require('../common/state/windowState') const Immutable = require('immutable') const pinnedSitesState = require('../common/state/pinnedSitesState') const pinnedSitesUtil = require('../common/lib/pinnedSitesUtil') +const windowActions = require('../../js/actions/windowActions') // TODO(bridiver) - set window uuid let currentWindows = {} @@ -55,10 +56,11 @@ const getWindowValue = (windowId) => { } } -const updateWindow = (windowId) => { +const updateWindow = (windowId, updateDefault = false) => { const windowValue = getWindowValue(windowId) if (windowValue) { - appActions.windowUpdated(windowValue) + appActions.windowUpdated(windowValue, updateDefault) + windowActions.onWindowUpdate(windowId, windowValue) } } @@ -189,6 +191,7 @@ const api = { LocalShortcuts.register(win) appActions.windowCreated(windowValue) + windowActions.onWindowUpdate(windowId, windowValue) }) win.once('closed', () => { cleanupWindow(windowId) @@ -198,8 +201,7 @@ const api = { updateWindowDebounce(windowId) }) win.on('focus', () => { - appActions.windowFocused(windowId) - updateWindowDebounce(windowId) + updateWindowDebounce(windowId, true) }) win.on('show', () => { updateWindowDebounce(windowId) @@ -208,7 +210,7 @@ const api = { updateWindowDebounce(windowId) }) win.on('maximize', () => { - updateWindowDebounce(windowId) + updateWindowDebounce(windowId, true) }) win.on('unmaximize', () => { updateWindowDebounce(windowId) @@ -220,18 +222,10 @@ const api = { updateWindowDebounce(windowId) }) win.on('resize', () => { - updateWindowDebounce(windowId) - const size = win.getSize() - const position = win.getPosition() - // NOTE: the default window size is whatever the last window resize was - appActions.defaultWindowParamsChanged(size, position) + updateWindowDebounce(windowId, true) }) win.on('move', () => { - updateWindowMove(windowId) - const size = win.getSize() - const position = win.getPosition() - // NOTE: the default window position is whatever the last window move was - appActions.defaultWindowParamsChanged(size, position) + updateWindowMove(windowId, true) }) win.on('enter-full-screen', () => { updateWindowDebounce(windowId) diff --git a/app/renderer/components/main/main.js b/app/renderer/components/main/main.js index 14294044d7d..ca5c1daf4eb 100644 --- a/app/renderer/components/main/main.js +++ b/app/renderer/components/main/main.js @@ -434,15 +434,12 @@ class Main extends React.Component { window.addEventListener('focus', () => { windowActions.setFocusedFrame(this.props.location, this.props.tabId) - windowActions.onFocus(getCurrentWindowId()) // For whatever reason other elements are preserved but webviews are not. if (document.activeElement && document.activeElement.tagName === 'BODY') { webviewActions.setWebviewFocused() } }, { passive: true }) - windowActions.onFocus(getCurrentWindowId()) - // disable dnd by default window.addEventListener('dragover', function (event) { // allow webviews to handle dnd @@ -470,7 +467,6 @@ class Main extends React.Component { const self = this window.onblur = () => { self.resetAltMenuProcessing() - windowActions.onBlur(getCurrentWindowId()) } } diff --git a/app/renderer/components/window.js b/app/renderer/components/window.js index 0bb1aa1f1e4..bea08c4ca99 100644 --- a/app/renderer/components/window.js +++ b/app/renderer/components/window.js @@ -14,6 +14,7 @@ const appActions = require('../../../js/actions/appActions') // Utils const cx = require('../../../js/lib/classSet') const {getPlatformStyles} = require('../../common/lib/platformUtil') +const {isFocused} = require('../currentWindow') window.appActions = appActions @@ -38,10 +39,8 @@ class Window extends React.Component { } mergeProps (state, ownProps) { - const currentWindow = state.get('currentWindow') - const props = {} - props.isFocused = currentWindow.getIn(['ui', 'isFocused']) + props.isFocused = isFocused() return props } diff --git a/app/sessionStore.js b/app/sessionStore.js index 5853cabf3c8..b3ede211cce 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -67,18 +67,26 @@ module.exports.saveAppState = (immutablePayload, isShutdown) => { assert(isImmutable(immutablePayload)) return new Promise((resolve, reject) => { - // Don't persist private frames let startupModeSettingValue = getSetting(settings.STARTUP_MODE) const savePerWindowState = startupModeSettingValue == null || startupModeSettingValue === 'lastTime' - if (immutablePayload.get('perWindowState') && savePerWindowState) { - immutablePayload.get('perWindowState').forEach((immutableWndPayload, i) => { - const frames = immutableWndPayload.get('frames').filter((frame) => !frame.get('isPrivate')) - immutableWndPayload = immutableWndPayload.set('frames', frames) - immutablePayload = immutablePayload.setIn(['perWindowState', i], immutableWndPayload) - }) - } else { - immutablePayload = immutablePayload.delete('perWindowState') + + // Don't persist private frames + if (immutablePayload.get('perWindowState')) { + if (savePerWindowState) { + immutablePayload.get('perWindowState').forEach((immutableWndPayload, i) => { + const frames = immutableWndPayload.get('frames').filter((frame) => !frame.get('isPrivate')) + immutableWndPayload = immutableWndPayload.set('frames', frames) + immutablePayload = immutablePayload.setIn(['perWindowState', i], immutableWndPayload) + }) + } else { + // we still need to preserve window position/size info + immutablePayload.get('perWindowState').forEach((immutableWndPayload, i) => { + let windowInfo = Immutable.Map() + windowInfo = windowInfo.set('windowInfo', immutableWndPayload.get('windowInfo')) + immutablePayload = immutablePayload.setIn(['perWindowState', i], windowInfo) + }) + } } try { @@ -135,7 +143,6 @@ module.exports.cleanPerWindowData = (immutablePerWindowData, isShutdown) => { 'braveryPanelDetail', // Don't restore drag data and clearBrowsingDataPanel's visibility // This is no longer stored, we can remove this line eventually - ['ui', 'isFocused'], ['ui', 'mouseInTitlebar'], ['ui', 'mouseInFrame'], ['ui', 'dragging'], diff --git a/docs/state.md b/docs/state.md index 72ea14d55a2..62c6ce2c21d 100644 --- a/docs/state.md +++ b/docs/state.md @@ -677,10 +677,7 @@ WindowStore downloadsToolbar: { isVisible: boolean // whether or not the downloads toolbar is visible }, - isFocused: boolean, // true if window has focus isClearBrowsingDataPanelVisible: boolean, // true if the Clear Browsing Data panel is visible - isFullScreen: boolean, // true if window is fullscreen - isMaximized: boolean, // true if window is maximized menubar: { isVisible: boolean, // true if Menubar control is visible lastFocusedSelector: string, // selector for the last selected element (browser ui, not frame content) @@ -690,14 +687,12 @@ WindowStore noScriptInfo: { isVisible: boolean // Whether the noscript infobox is visible }, - position: array, // last known window position [x, y] releaseNotes: { isVisible: boolean // whether or not to show release notes }, siteInfo: { isVisible: boolean // whether or not to show site info like # of blocked ads }, - size: array, // last known window size [x, y] tabs: { hoverTabIndex: number, // index of the current hovered tab previewMode: boolean, // whether or not tab preview should be fired based on mouse idle time @@ -709,6 +704,15 @@ WindowStore alsoAddRememberSiteSetting: boolean, // true if an allow always rule should be added for the acitve frame as well if installed location: string, // location this dialog is for shown: boolean // true if the panel is shown + }, + windowInfo: { + focused: boolean, + height: number, + left: number, + state: string // "normal", "minimized", "maximized", or "fullscreen" + top: number, + type: string, // "normal", "popup", or "devtools" + width: number, } } ``` diff --git a/js/actions/appActions.js b/js/actions/appActions.js index 992f4ff2626..5c9e035d9ba 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -65,10 +65,11 @@ const appActions = { }) }, - windowUpdated: function (windowValue) { + windowUpdated: function (windowValue, updateDefault) { dispatch({ actionType: appConstants.APP_WINDOW_UPDATED, - windowValue + windowValue, + updateDefault }) }, @@ -304,19 +305,6 @@ const appActions = { }) }, - /** - * Sets the default window size / position - * @param {Array} size - [width, height] - * @param {Array} position - [x, y] - */ - defaultWindowParamsChanged: function (size, position) { - dispatch({ - actionType: appConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED, - size, - position - }) - }, - /** * Sets the etag value for a downloaded data file. * This is used for keeping track of when to re-download adblock and tracking @@ -637,18 +625,6 @@ const appActions = { }) }, - /** - * Dispatches a message when windowId gains focus - * - * @param {Number} windowId - the unique id of the window - */ - windowFocused: function (windowId) { - dispatch({ - actionType: appConstants.APP_WINDOW_FOCUSED, - windowId: windowId - }) - }, - /** * Saves current menubar template for use w/ Windows titlebar * @param {Object} menubarTemplate - JSON used to build the menu diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js index 4dc258fc3a2..21a001542ee 100644 --- a/js/actions/windowActions.js +++ b/js/actions/windowActions.js @@ -1075,20 +1075,6 @@ const windowActions = { }) }, - onMaximize: function (windowId) { - dispatch({ - actionType: windowConstants.WINDOW_ON_MAXIMIZE, - windowId - }) - }, - - onMinimize: function (windowId) { - dispatch({ - actionType: windowConstants.WINDOW_ON_MINIMIZE, - windowId - }) - }, - // TODO(bridiver) - refactor these as declarative shouldSetTitle: function (windowId, title) { dispatch({ @@ -1133,34 +1119,6 @@ const windowActions = { }) }, - onFocus: function (windowId) { - dispatch({ - actionType: windowConstants.WINDOW_ON_FOCUS, - windowId - }) - }, - - onBlur: function (windowId) { - dispatch({ - actionType: windowConstants.WINDOW_ON_BLUR, - windowId - }) - }, - - onEnterFullScreen: function (windowId) { - dispatch({ - actionType: windowConstants.WINDOW_ON_ENTER_FULL_SCREEN, - windowId - }) - }, - - onExitFullScreen: function (windowId) { - dispatch({ - actionType: windowConstants.WINDOW_ON_EXIT_FULL_SCREEN, - windowId - }) - }, - onLongBackHistory: function (history, left, top, partition, tabId, windowId) { dispatch({ actionType: windowConstants.WINDOW_ON_GO_BACK_LONG, @@ -1243,6 +1201,16 @@ const windowActions = { bookmarkKey, type }) + }, + + onWindowUpdate: function (windowId, windowValue) { + dispatch({ + actionType: windowConstants.WINDOW_ON_WINDOW_UPDATE, + queryInfo: { + windowId + }, + windowValue + }) } } diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 0bd091fc15d..4e1f60a52e9 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -18,7 +18,6 @@ const appConstants = { APP_REMOVE_HISTORY_SITE: _, APP_MERGE_DOWNLOAD_DETAIL: _, // Sets an individual download detail APP_CLEAR_COMPLETED_DOWNLOADS: _, // Removes all completed downloads - APP_DEFAULT_WINDOW_PARAMS_CHANGED: _, APP_SET_DATA_FILE_ETAG: _, APP_SET_DATA_FILE_LAST_CHECK: _, APP_SET_RESOURCE_ENABLED: _, @@ -48,7 +47,6 @@ const appConstants = { APP_SET_LOGIN_REQUIRED_DETAIL: _, APP_SET_LOGIN_RESPONSE_DETAIL: _, APP_WINDOW_BLURRED: _, - APP_WINDOW_FOCUSED: _, APP_IDLE_STATE_CHANGED: _, APP_NETWORK_CONNECTED: _, APP_NETWORK_DISCONNECTED: _, diff --git a/js/constants/windowConstants.js b/js/constants/windowConstants.js index 850a5a95565..1f6ce8db614 100644 --- a/js/constants/windowConstants.js +++ b/js/constants/windowConstants.js @@ -85,12 +85,6 @@ const windowConstants = { WINDOW_TAB_MOUSE_LEAVE: _, WINDOW_FRAME_MOUSE_ENTER: _, WINDOW_FRAME_MOUSE_LEAVE: _, - WINDOW_ON_MAXIMIZE: _, - WINDOW_ON_MINIMIZE: _, - WINDOW_ON_FOCUS: _, - WINDOW_ON_BLUR: _, - WINDOW_ON_ENTER_FULL_SCREEN: _, - WINDOW_ON_EXIT_FULL_SCREEN: _, WINDOW_SHOULD_SET_TITLE: _, WINDOW_SHOULD_MINIMIZE: _, WINDOW_SHOULD_MAXIMIZE: _, @@ -114,7 +108,8 @@ const windowConstants = { WINDOW_ON_BOOKMARK_ADDED: _, WINDOW_ON_ADD_BOOKMARK_FOLDER: _, WINDOW_ON_EDIT_BOOKMARK_FOLDER: _, - WINDOW_ON_BOOKMARK_FOLDER_CLOSE: _ + WINDOW_ON_BOOKMARK_FOLDER_CLOSE: _, + WINDOW_ON_WINDOW_UPDATE: _ } module.exports = mapValuesByKeys(windowConstants) diff --git a/js/contextMenus.js b/js/contextMenus.js index ed4da0306d7..db4a34b0229 100644 --- a/js/contextMenus.js +++ b/js/contextMenus.js @@ -488,7 +488,7 @@ function tabTemplateInit (frameProps) { template.push({ label: locale.translation('detach'), click: (item) => { - const browserOpts = { positionByMouseCursor: true } + const browserOpts = { positionByMouseCursor: true, checkMaximized: true } appActions.tabMoved(tabId, frameProps.toJS(), browserOpts, -1) } }) diff --git a/js/entry.js b/js/entry.js index ec4b40a8768..5256f038c61 100644 --- a/js/entry.js +++ b/js/entry.js @@ -74,7 +74,7 @@ ipc.on(messages.CLEAR_CLOSED_FRAMES, (e, location) => { windowActions.clearClosedFrames(location) }) -window.addEventListener('beforeunload', function (e) { +window.addEventListener('beforeunload', function () { ipc.send(messages.LAST_WINDOW_STATE, windowStore.getState().toJS()) }) diff --git a/js/state/frameStateUtil.js b/js/state/frameStateUtil.js index 723baab46e4..41cc48f25f1 100644 --- a/js/state/frameStateUtil.js +++ b/js/state/frameStateUtil.js @@ -393,7 +393,7 @@ function addFrame (state, frameOpts, newKey, partitionNumber, openInForeground, */ function removeFrame (state, frameProps, framePropsIndex) { const frames = state.get('frames') - let closedFrames = state.get('closedFrames') + let closedFrames = state.get('closedFrames') || Immutable.List() const newFrames = frames.splice(framePropsIndex, 1) if (isValidClosedFrame(frameProps)) { diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index 56ad7b7c691..ccf4ce0882d 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -802,24 +802,6 @@ const doAction = (action) => { case windowConstants.WINDOW_FRAME_MOUSE_LEAVE: windowState = windowState.setIn(['ui', 'mouseInFrame'], false) break - case windowConstants.WINDOW_ON_MAXIMIZE: - windowState = windowState.setIn(['ui', 'isMaximized'], true) - break - case windowConstants.WINDOW_ON_MINIMIZE: - windowState = windowState.setIn(['ui', 'isMaximized'], false) - break - case windowConstants.WINDOW_ON_FOCUS: - windowState = windowState.setIn(['ui', 'isFocused'], true) - break - case windowConstants.WINDOW_ON_BLUR: - windowState = windowState.setIn(['ui', 'isFocused'], false) - break - case windowConstants.WINDOW_ON_ENTER_FULL_SCREEN: - windowState = windowState.setIn(['ui', 'isFullScreen'], true) - break - case windowConstants.WINDOW_ON_EXIT_FULL_SCREEN: - windowState = windowState.setIn(['ui', 'isFullScreen'], false) - break case windowConstants.WINDOW_ON_CERT_ERROR: { const frame = frameStateUtil.getFrameByTabId(windowState, action.tabId) || Immutable.Map() @@ -833,6 +815,9 @@ const doAction = (action) => { } break } + case windowConstants.WINDOW_ON_WINDOW_UPDATE: + windowState = windowState.set('windowInfo', action.windowValue) + break default: break } diff --git a/test/app/sessionStoreTest.js b/test/app/sessionStoreTest.js index 7f5aa9aeee4..9d375585ac1 100644 --- a/test/app/sessionStoreTest.js +++ b/test/app/sessionStoreTest.js @@ -1,15 +1,44 @@ -/* global describe, it, before, after */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global describe, it, before, beforeEach, after, afterEach */ const Brave = require('../lib/brave') const {urlInput, navigatorBookmarked, navigatorNotBookmarked, pinnedTabsTabs, tabsTabs} = require('../lib/selectors') const siteTags = require('../../js/constants/siteTags') const settings = require('../../js/constants/settings') +const {startsWithOption} = require('../../app/common/constants/settingsEnums') describe('sessionStore test', function () { - function * setup () { + function * setup (client) { + yield client + .waitForBrowserWindow() + .waitForVisible(urlInput) + } + + function * setupBrave () { Brave.addCommands() } + function * checkWindow (client, width, height, x, y) { + yield client.app.client + .windowByIndex(0) + .browserWindow.getBounds().should.eventually.have.property('width').should.become(width) + + yield client.app.client + .windowByIndex(0) + .browserWindow.getBounds().should.eventually.have.property('height').should.become(height) + + yield client.app.client + .windowByIndex(0) + .browserWindow.getBounds().then((res) => res.x).should.eventually.be.equal(x) + + yield client.app.client + .windowByIndex(0) + .browserWindow.getBounds().then((res) => res.y).should.eventually.be.equal(y) + } + describe('state is preserved with a normal shutdown', function () { Brave.beforeAllServerSetup(this) before(function * () { @@ -20,7 +49,7 @@ describe('sessionStore test', function () { type: siteTags.BOOKMARK } yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) yield Brave.app.client .waitForBrowserWindow() .changeSetting(settings.DISABLE_TITLE_MODE, false) @@ -33,7 +62,7 @@ describe('sessionStore test', function () { .waitForExist(navigatorBookmarked) yield Brave.stopApp(false) yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) }) after(function * () { @@ -67,7 +96,7 @@ describe('sessionStore test', function () { type: siteTags.BOOKMARK } yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) yield Brave.app.client .waitForBrowserWindow() .changeSetting(settings.DISABLE_TITLE_MODE, false) @@ -81,7 +110,7 @@ describe('sessionStore test', function () { yield Brave.stopApp(false) yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) yield Brave.app.client .windowByUrl(Brave.browserWindowUrl) @@ -95,7 +124,7 @@ describe('sessionStore test', function () { yield Brave.stopApp(false, 10000) yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) }) after(function * () { @@ -132,7 +161,7 @@ describe('sessionStore test', function () { this.page2Url = Brave.server.url('page2.html') this.activeTabSelector = '.frameWrapper.isActive webview[data-frame-key="1"][src="' + this.page1Url + '"]' yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) yield Brave.app.client .waitForBrowserWindow() .waitForUrl(Brave.newTabUrl) @@ -153,7 +182,7 @@ describe('sessionStore test', function () { .waitForExist(this.activeTabSelector) yield Brave.stopApp(false) yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) }) after(function * () { @@ -176,7 +205,7 @@ describe('sessionStore test', function () { this.page2Url = Brave.server.url('page2.html') this.activeTabSelector = '.frameWrapper.isActive webview[data-frame-key="2"][src="' + this.page2Url + '"]' yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) yield Brave.app.client .waitForBrowserWindow() .waitForUrl(Brave.newTabUrl) @@ -192,7 +221,7 @@ describe('sessionStore test', function () { .waitForExist(this.activeTabSelector) yield Brave.stopApp(false) yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) }) after(function * () { @@ -213,7 +242,7 @@ describe('sessionStore test', function () { Brave.beforeAllServerSetup(this) before(function * () { yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) }) after(function * () { @@ -238,7 +267,7 @@ describe('sessionStore test', function () { yield Brave.stopApp(false) yield Brave.startApp() - yield setup(Brave.app.client) + yield setupBrave(Brave.app.client) yield Brave.app.client .waitForUrl(Brave.newTabUrl) .waitForBrowserWindow() @@ -249,4 +278,71 @@ describe('sessionStore test', function () { }) }) }) + + describe('window position and size are restored correctly', function () { + Brave.beforeAllServerSetup(this) + const width = 600 + const height = 700 + const x = 100 + const y = 200 + + beforeEach(function * () { + yield Brave.startApp() + yield setupBrave(Brave.app.client) + yield setup(Brave.app.client) + + yield Brave.app.client + .waitForUrl(Brave.newTabUrl) + .waitForBrowserWindow() + .unmaximize() + .resizeWindow(width, height) + .setWindowPosition(x, y) + }) + + afterEach(function * () { + yield Brave.stopApp() + }) + + it('brave starts with windows from last time', function * () { + yield Brave.app.client + .waitForUrl(Brave.newTabUrl) + .waitForBrowserWindow() + .changeSetting(settings.STARTUP_MODE, startsWithOption.WINDOWS_TABS_FROM_LAST_TIME) + + yield Brave.stopApp(false) + yield Brave.startApp() + yield setupBrave(Brave.app.client) + yield setup(Brave.app.client) + + yield checkWindow(Brave, width, height, x, y) + }) + + it('brave starts with home page', function * () { + yield Brave.app.client + .waitForUrl(Brave.newTabUrl) + .waitForBrowserWindow() + .changeSetting(settings.STARTUP_MODE, startsWithOption.HOMEPAGE) + + yield Brave.stopApp(false) + yield Brave.startApp() + yield setupBrave(Brave.app.client) + yield setup(Brave.app.client) + + yield checkWindow(Brave, width, height, x, y) + }) + + it('brave starts with new tab page', function * () { + yield Brave.app.client + .waitForUrl(Brave.newTabUrl) + .waitForBrowserWindow() + .changeSetting(settings.STARTUP_MODE, startsWithOption.NEW_TAB_PAGE) + + yield Brave.stopApp(false) + yield Brave.startApp() + yield setupBrave(Brave.app.client) + yield setup(Brave.app.client) + + yield checkWindow(Brave, width, height, x, y) + }) + }) }) diff --git a/test/lib/brave.js b/test/lib/brave.js index babc0f7c4bc..1ac6094d6dd 100644 --- a/test/lib/brave.js +++ b/test/lib/brave.js @@ -906,6 +906,13 @@ var exports = { }, width, height).then((response) => response.value) }) + this.app.client.addCommand('setWindowPosition', function (x, y) { + logVerbose('setWindowPosition("' + x + '", "' + y + '")') + return this.execute(function (x, y) { + return devTools('electron').remote.getCurrentWindow().setPosition(x, y) + }, x, y).then((response) => response.value) + }) + this.app.client.addCommand('windowParentByUrl', function (url, childSelector = 'webview') { logVerbose('windowParentByUrl("' + url + '", "' + childSelector + '")') var context = this diff --git a/test/misc-components/windowTest.js b/test/misc-components/windowTest.js index 5b31feeac93..fab48b247a4 100644 --- a/test/misc-components/windowTest.js +++ b/test/misc-components/windowTest.js @@ -40,6 +40,7 @@ describe('application window', function () { describe('appActions.newWindow', function () { describe('default', function () { + const isLinux = process.platform === 'linux' Brave.beforeAll(this) before(function * () { @@ -71,24 +72,53 @@ describe('application window', function () { yield this.app.client .windowByIndex(1).browserWindow.getBounds().should.eventually.have.property('height').should.eventually.be.getDefaultWindowHeight() }) + + it('is maximized', function * () { + if (!isLinux) { + this.skip() + return + } + + yield this.app.client + .waitForBrowserWindow() + .waitUntil(function () { + return this.getWindowState().then((val) => { + return val && + val.value && + val.value.windowInfo && + val.value.windowInfo.state === 'maximized' + }) + }) + }) }) describe('after resize', function () { Brave.beforeAll(this) + const width = 600 + const height = 700 before(function * () { yield this.app.client .waitForUrl(Brave.newTabUrl) .waitForBrowserWindow() .unmaximize() - .resizeWindow(600, 700) + .resizeWindow(width, height) .waitUntil(function () { return this.getAppState().then((val) => { return val && val.value && val.value.defaultWindowParams && - val.value.defaultWindowParams.width === 600 && - val.value.defaultWindowParams.height === 700 + val.value.defaultWindowParams.width === width && + val.value.defaultWindowParams.height === height + }) + }) + .waitUntil(function () { + return this.getWindowState().then((val) => { + return val && + val.value && + val.value.windowInfo && + val.value.windowInfo.width === width && + val.value.windowInfo.height === height }) }) .newWindowAction() @@ -111,8 +141,31 @@ describe('application window', function () { it('has the width and height of the last window resize', function * () { yield this.app.client - .windowByIndex(1).browserWindow.getBounds().should.eventually.have.property('width').should.become(600) - .windowByIndex(1).browserWindow.getBounds().should.eventually.have.property('height').should.become(700) + .windowByIndex(1).browserWindow.getBounds().should.eventually.have.property('width').should.become(width) + .windowByIndex(1).browserWindow.getBounds().should.eventually.have.property('height').should.become(height) + }) + + it('check if new window has the same state data', function * () { + yield this.app.client + .waitForBrowserWindow() + .waitUntil(function () { + return this.getAppState().then((val) => { + return val && + val.value && + val.value.defaultWindowParams && + val.value.defaultWindowParams.width === width && + val.value.defaultWindowParams.height === height + }) + }) + .waitUntil(function () { + return this.getWindowState().then((val) => { + return val && + val.value && + val.value.windowInfo && + val.value.windowInfo.width === width && + val.value.windowInfo.height === height + }) + }) }) }) diff --git a/test/unit/app/browser/reducers/tabsReducerTest.js b/test/unit/app/browser/reducers/tabsReducerTest.js index e42432ea37b..667478a9f3a 100644 --- a/test/unit/app/browser/reducers/tabsReducerTest.js +++ b/test/unit/app/browser/reducers/tabsReducerTest.js @@ -715,6 +715,7 @@ describe('tabsReducer unit tests', function () { }) // Passes browser options for position by mouse cursor assert.deepEqual(args[3], { + checkMaximized: true, positionByMouseCursor: true }) // Dropping on window ID is -1 diff --git a/test/unit/app/browser/reducers/windowsReducerTest.js b/test/unit/app/browser/reducers/windowsReducerTest.js new file mode 100644 index 00000000000..1809eb50925 --- /dev/null +++ b/test/unit/app/browser/reducers/windowsReducerTest.js @@ -0,0 +1,93 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global describe, it, before, after, afterEach */ +const mockery = require('mockery') +const sinon = require('sinon') +const Immutable = require('immutable') +const assert = require('assert') +const fakeAdBlock = require('../../../lib/fakeAdBlock') + +const appConstants = require('../../../../../js/constants/appConstants') +require('../../../braveUnit') + +describe('windowsReducer unit test', function () { + let windowsReducer + const fakeElectron = Object.assign({}, require('../../../lib/fakeElectron')) + + const fakeWindowState = { + maybeCreateWindow: (state, action) => state + } + + const state = Immutable.fromJS({ + windows: [], + defaultWindowParams: {} + }) + + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + mockery.registerMock('electron', fakeElectron) + mockery.registerMock('ad-block', fakeAdBlock) + mockery.registerMock('../../common/state/windowState', fakeWindowState) + windowsReducer = require('../../../../../app/browser/reducers/windowsReducer') + }) + + after(function () { + mockery.disable() + }) + + describe('APP_WINDOW_UPDATED', function () { + let spy + + afterEach(function () { + spy.restore() + }) + + it('null case', function () { + spy = sinon.spy(fakeWindowState, 'maybeCreateWindow') + const newState = windowsReducer(state, { + actionType: appConstants.APP_WINDOW_UPDATED + }) + assert.equal(spy.calledOnce, true) + assert.deepEqual(state.getIn(['defaultWindowParams']).toJS(), newState.getIn(['defaultWindowParams']).toJS()) + }) + + it('updateDefault is false (we shouldnt update it)', function () { + spy = sinon.spy(fakeWindowState, 'maybeCreateWindow') + const newState = windowsReducer(state, { + actionType: appConstants.APP_WINDOW_UPDATED, + updateDefault: false + }) + assert.equal(spy.calledOnce, true) + assert.deepEqual(state.getIn(['defaultWindowParams']).toJS(), newState.getIn(['defaultWindowParams']).toJS()) + }) + + it('updateDefault is true', function () { + spy = sinon.spy(fakeWindowState, 'maybeCreateWindow') + const newState = windowsReducer(state, { + actionType: appConstants.APP_WINDOW_UPDATED, + updateDefault: true, + windowValue: { + width: 1, + height: 2, + x: 3, + y: 4, + state: 'maximized' + } + }) + assert.equal(spy.calledOnce, true) + assert.deepEqual({ + width: 1, + height: 2, + x: 3, + y: 4, + maximized: true + }, newState.getIn(['defaultWindowParams']).toJS()) + }) + }) +})