diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-09-03 13:25:25 +0300 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-09-03 13:25:25 +0300 |
| commit | a23afed45caa953cb9765991a4692b66b3a39329 (patch) | |
| tree | c593125ccc65f6f5ad2efcf964740a2d45e27737 | |
| parent | 912c0b8d18c63e27cdd0f3863529ee9c3f8bd854 (diff) | |
| parent | d363f33140d57c1f6f5154bf21075df5393922dc (diff) | |
| download | mullvadvpn-a23afed45caa953cb9765991a4692b66b3a39329.tar.xz mullvadvpn-a23afed45caa953cb9765991a4692b66b3a39329.zip | |
Merge branch 'arrow-position'
| -rw-r--r-- | CHANGELOG.md | 9 | ||||
| -rw-r--r-- | gui/packages/desktop/src/main/window-controller.js | 28 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/app.js | 11 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/components/PlatformWindow.js | 32 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/containers/PlatformWindowContainer.js | 18 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/redux/store.js | 34 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/redux/window/actions.js | 17 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/redux/window/reducers.js | 22 | ||||
| -rw-r--r-- | gui/packages/desktop/src/renderer/routes.js | 6 |
9 files changed, 148 insertions, 29 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 37a0a438db..a38cf03320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,13 +27,19 @@ Line wrap the file at 100 chars. Th - Add option to enable or disable IPv6 on the tunnel interface. - Log panics in the daemon to the log file. - Warn in the Settings screen if a new version is available. + #### Windows - Extend uninstaller to also remove logs, cache and optionally settings. ### Fixed +- Fix incorrect window position when using external display. + #### Linux - The app window is now shown in its previous location, instead of at the center of the screen. +#### macOS +- Fix edge cases when window's arrow appeared misaligned and pointed to the wrong menubar item. + ### Changed - The "Buy more credit" button is changed to open a dedicated account login page instead of one having a create account form first. @@ -43,9 +49,6 @@ Line wrap the file at 100 chars. Th of the socket can be controlled with `MULLVAD_RPC_SOCKET_PATH`. - Update the relay list if it's out of date when the daemon starts. -### Fixed -- Fix incorrect window position when using external display. - ## [2018.2] - 2018-08-13 This release is identical to 2018.2-beta3 diff --git a/gui/packages/desktop/src/main/window-controller.js b/gui/packages/desktop/src/main/window-controller.js index dc6165c5f3..704f9bae3e 100644 --- a/gui/packages/desktop/src/main/window-controller.js +++ b/gui/packages/desktop/src/main/window-controller.js @@ -5,8 +5,13 @@ import type { BrowserWindow, Tray, Display } from 'electron'; type Position = { x: number, y: number }; +export type WindowShapeParameters = { + arrowPosition?: number, +}; + interface WindowPositioning { getPosition(window: BrowserWindow): Position; + getWindowShapeParameters(window: BrowserWindow): WindowShapeParameters; } class StandaloneWindowPositioning implements WindowPositioning { @@ -23,6 +28,10 @@ class StandaloneWindowPositioning implements WindowPositioning { return { x, y }; } + + getWindowShapeParameters(_window: BrowserWindow): WindowShapeParameters { + return {}; + } } class AttachedToTrayWindowPositioning implements WindowPositioning { @@ -83,6 +92,15 @@ class AttachedToTrayWindowPositioning implements WindowPositioning { }; } + getWindowShapeParameters(window: BrowserWindow): WindowShapeParameters { + const trayBounds = this._tray.getBounds(); + const windowBounds = window.getBounds(); + const arrowPosition = trayBounds.x - windowBounds.x + trayBounds.width * 0.5; + return { + arrowPosition, + }; + } + _getTrayPlacement() { switch (process.platform) { case 'darwin': @@ -156,6 +174,7 @@ export default class WindowController { const window = this._window; this._updatePosition(); + this._notifyUpdateWindowShape(); window.show(); window.focus(); @@ -166,7 +185,13 @@ export default class WindowController { this._window.setPosition(x, y, false); } - // Installs display event handlers to update the window position on any changes in the display or workarea dimensions. + _notifyUpdateWindowShape() { + const shapeParameters = this._windowPositioning.getWindowShapeParameters(this._window); + this._window.webContents.send('update-window-shape', shapeParameters); + } + + // Installs display event handlers to update the window position on any changes in the display or + // workarea dimensions. _installDisplayMetricsHandler() { screen.addListener('display-metrics-changed', this._onDisplayMetricsChanged); this._window.once('closed', () => { @@ -177,6 +202,7 @@ export default class WindowController { _onDisplayMetricsChanged = (_event: any, _display: Display, changedMetrics: Array<string>) => { if (changedMetrics.includes('workArea') && this._window.isVisible()) { this._updatePosition(); + this._notifyUpdateWindowShape(); } }; diff --git a/gui/packages/desktop/src/renderer/app.js b/gui/packages/desktop/src/renderer/app.js index 03fae931dd..e88d3d619c 100644 --- a/gui/packages/desktop/src/renderer/app.js +++ b/gui/packages/desktop/src/renderer/app.js @@ -1,6 +1,7 @@ // @flow import log from 'electron-log'; +import { remote, webFrame, ipcRenderer } from 'electron'; import * as React from 'react'; import { bindActionCreators } from 'redux'; import { Provider } from 'react-redux'; @@ -10,7 +11,6 @@ import { replace as replaceHistory, } from 'connected-react-router'; import { createMemoryHistory } from 'history'; -import { remote, webFrame, ipcRenderer } from 'electron'; import makeRoutes from './routes'; import ReconnectionBackoff from './lib/reconnection-backoff'; @@ -25,7 +25,9 @@ import connectionActions from './redux/connection/actions'; import settingsActions from './redux/settings/actions'; import versionActions from './redux/version/actions'; import daemonActions from './redux/daemon/actions'; +import windowActions from './redux/window/actions'; +import type { WindowShapeParameters } from '../main/window-controller'; import type { DaemonRpcProtocol, AccountData, @@ -58,6 +60,7 @@ export default class AppRenderer { settings: bindActionCreators(settingsActions, dispatch), version: bindActionCreators(versionActions, dispatch), daemon: bindActionCreators(daemonActions, dispatch), + window: bindActionCreators(windowActions, dispatch), history: bindActionCreators( { push: pushHistory, @@ -85,6 +88,12 @@ export default class AppRenderer { } }); + ipcRenderer.on('update-window-shape', (_event, shapeParams: WindowShapeParameters) => { + if (typeof shapeParams.arrowPosition === 'number') { + this._reduxActions.window.updateWindowArrowPosition(shapeParams.arrowPosition); + } + }); + // disable pinch to zoom webFrame.setVisualZoomLevelLimits(1, 1); } diff --git a/gui/packages/desktop/src/renderer/components/PlatformWindow.js b/gui/packages/desktop/src/renderer/components/PlatformWindow.js index 6c2c85e023..f143c3d381 100644 --- a/gui/packages/desktop/src/renderer/components/PlatformWindow.js +++ b/gui/packages/desktop/src/renderer/components/PlatformWindow.js @@ -3,16 +3,32 @@ import * as React from 'react'; import { Component, View, Styles } from 'reactxp'; -const styles = { - darwin: Styles.createViewStyle({ - WebkitMask: ` - url(../assets/images/app-triangle.svg) 50% 0% no-repeat, - url(../assets/images/app-header-backdrop.svg) no-repeat`, - }), +type Props = { + arrowPosition?: number, }; -export default class PlatformWindow extends Component { +export default class PlatformWindow extends Component<Props> { render() { - return <View style={styles[process.platform]}>{this.props.children}</View>; + let style = undefined; + + if (process.platform === 'darwin') { + const arrowPosition = this.props.arrowPosition; + let arrowPositionCss = '50%'; + + if (typeof arrowPosition === 'number') { + const arrowWidth = 30; + const adjustedArrowPosition = arrowPosition - arrowWidth * 0.5; + arrowPositionCss = `${adjustedArrowPosition}px`; + } + + const webkitMask = [ + `url(../assets/images/app-triangle.svg) ${arrowPositionCss} 0% no-repeat`, + `url(../assets/images/app-header-backdrop.svg) no-repeat`, + ]; + + style = Styles.createViewStyle({ WebkitMask: webkitMask.join(',') }, false); + } + + return <View style={style}>{this.props.children}</View>; } } diff --git a/gui/packages/desktop/src/renderer/containers/PlatformWindowContainer.js b/gui/packages/desktop/src/renderer/containers/PlatformWindowContainer.js new file mode 100644 index 0000000000..4d48b60a95 --- /dev/null +++ b/gui/packages/desktop/src/renderer/containers/PlatformWindowContainer.js @@ -0,0 +1,18 @@ +// @flow + +import { connect } from 'react-redux'; +import PlatformWindow from '../components/PlatformWindow'; + +import type { ReduxState, ReduxDispatch } from '../redux/store'; +import type { SharedRouteProps } from '../routes'; + +const mapStateToProps = (state: ReduxState) => ({ + arrowPosition: state.window.arrowPosition, +}); + +const mapDispatchToProps = (_dispatch: ReduxDispatch, _props: SharedRouteProps) => ({}); + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(PlatformWindow); diff --git a/gui/packages/desktop/src/renderer/redux/store.js b/gui/packages/desktop/src/renderer/redux/store.js index 58c6645a45..133402e590 100644 --- a/gui/packages/desktop/src/renderer/redux/store.js +++ b/gui/packages/desktop/src/renderer/redux/store.js @@ -3,18 +3,20 @@ import { createStore, applyMiddleware, combineReducers, compose } from 'redux'; import { routerMiddleware, connectRouter, push, replace } from 'connected-react-router'; -import account from './account/reducers'; +import accountReducer from './account/reducers'; import accountActions from './account/actions'; -import connection from './connection/reducers'; +import connectionReducer from './connection/reducers'; import connectionActions from './connection/actions'; -import settings from './settings/reducers'; +import settingsReducer from './settings/reducers'; import settingsActions from './settings/actions'; -import support from './support/reducers'; +import supportReducer from './support/reducers'; import supportActions from './support/actions'; -import version from './version/reducers'; +import versionReducer from './version/reducers'; import versionActions from './version/actions'; -import daemon from './daemon/reducers'; +import daemonReducer from './daemon/reducers'; import daemonActions from './daemon/actions'; +import windowReducer from './window/reducers'; +import windowActions from './window/actions'; import type { Store, StoreEnhancer } from 'redux'; import type { History } from 'history'; @@ -24,6 +26,7 @@ import type { SettingsReduxState } from './settings/reducers'; import type { SupportReduxState } from './support/reducers'; import type { VersionReduxState } from './version/reducers'; import type { DaemonReduxState } from './daemon/reducers'; +import type { WindowReduxState } from './window/reducers'; import type { AccountAction } from './account/actions'; import type { ConnectionAction } from './connection/actions'; @@ -31,6 +34,7 @@ import type { SettingsAction } from './settings/actions'; import type { SupportAction } from './support/actions'; import type { VersionAction } from './version/actions'; import type { DaemonAction } from './daemon/actions'; +import type { WindowAction } from './window/actions'; export type ReduxState = { account: AccountReduxState, @@ -39,6 +43,7 @@ export type ReduxState = { support: SupportReduxState, version: VersionReduxState, daemon: DaemonReduxState, + window: WindowReduxState, }; export type ReduxAction = @@ -47,7 +52,8 @@ export type ReduxAction = | SettingsAction | SupportAction | VersionAction - | DaemonAction; + | DaemonAction + | WindowAction; export type ReduxStore = Store<ReduxState, ReduxAction, ReduxDispatch>; export type ReduxGetState = () => ReduxState; export type ReduxDispatch = (action: ReduxAction) => any; @@ -65,17 +71,19 @@ export default function configureStore( ...supportActions, ...versionActions, ...daemonActions, + ...windowActions, pushRoute: (route) => push(route), replaceRoute: (route) => replace(route), }; const reducers = { - account, - connection, - settings, - support, - version, - daemon, + account: accountReducer, + connection: connectionReducer, + settings: settingsReducer, + support: supportReducer, + version: versionReducer, + daemon: daemonReducer, + window: windowReducer, }; const middlewares = [router]; diff --git a/gui/packages/desktop/src/renderer/redux/window/actions.js b/gui/packages/desktop/src/renderer/redux/window/actions.js new file mode 100644 index 0000000000..3da45e6c65 --- /dev/null +++ b/gui/packages/desktop/src/renderer/redux/window/actions.js @@ -0,0 +1,17 @@ +// @flow + +export type UpdateWindowArrowPositionAction = { + type: 'UPDATE_WINDOW_ARROW_POSITION', + arrowPosition: number, +}; + +export type WindowAction = UpdateWindowArrowPositionAction; + +function updateWindowArrowPosition(arrowPosition: number): UpdateWindowArrowPositionAction { + return { + type: 'UPDATE_WINDOW_ARROW_POSITION', + arrowPosition, + }; +} + +export default { updateWindowArrowPosition }; diff --git a/gui/packages/desktop/src/renderer/redux/window/reducers.js b/gui/packages/desktop/src/renderer/redux/window/reducers.js new file mode 100644 index 0000000000..91fcfeadd9 --- /dev/null +++ b/gui/packages/desktop/src/renderer/redux/window/reducers.js @@ -0,0 +1,22 @@ +// @flow + +import type { ReduxAction } from '../store'; + +export type WindowReduxState = { + arrowPosition?: number, +}; + +const initialState: WindowReduxState = {}; + +export default function( + state: WindowReduxState = initialState, + action: ReduxAction, +): WindowReduxState { + switch (action.type) { + case 'UPDATE_WINDOW_ARROW_POSITION': + return { ...state, arrowPosition: action.arrowPosition }; + + default: + return state; + } +} diff --git a/gui/packages/desktop/src/renderer/routes.js b/gui/packages/desktop/src/renderer/routes.js index 107ee616be..9a93a76936 100644 --- a/gui/packages/desktop/src/renderer/routes.js +++ b/gui/packages/desktop/src/renderer/routes.js @@ -3,7 +3,7 @@ import * as React from 'react'; import { Switch, Route, Redirect } from 'react-router'; import TransitionContainer from './components/TransitionContainer'; -import PlatformWindow from './components/PlatformWindow'; +import PlatformWindowContainer from './containers/PlatformWindowContainer'; import LaunchPage from './containers/LaunchPage'; import LoginPage from './containers/LoginPage'; import ConnectPage from './containers/ConnectPage'; @@ -120,7 +120,7 @@ export default function makeRoutes( previousRoute = toRoute; return ( - <PlatformWindow> + <PlatformWindowContainer> <TransitionContainer {...transitionProps}> <Switch key={location.key} location={location}> <LaunchRoute exact path="/" component={LaunchPage} /> @@ -134,7 +134,7 @@ export default function makeRoutes( <PrivateRoute exact path="/select-location" component={SelectLocationPage} /> </Switch> </TransitionContainer> - </PlatformWindow> + </PlatformWindowContainer> ); }} /> |
