diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-03-05 19:15:22 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-03-07 11:51:30 +0100 |
| commit | 2de1c162aeb0214e6afd95c42655d0653ac28bff (patch) | |
| tree | 01528270053780e3b2afc7fec41468c511f2077d /app | |
| parent | 2bcd8c49e2ed3f59e3988540102f7cd58236a5a7 (diff) | |
| download | mullvadvpn-2de1c162aeb0214e6afd95c42655d0653ac28bff.tar.xz mullvadvpn-2de1c162aeb0214e6afd95c42655d0653ac28bff.zip | |
Compute window position based on taskbar placement
Diffstat (limited to 'app')
| -rw-r--r-- | app/main.js | 144 |
1 files changed, 109 insertions, 35 deletions
diff --git a/app/main.js b/app/main.js index f097521c87..4d7dcd408a 100644 --- a/app/main.js +++ b/app/main.js @@ -3,7 +3,7 @@ import path from 'path'; import fs from 'fs'; import mkdirp from 'mkdirp'; import { log } from './lib/platform'; -import { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage } from 'electron'; +import electron, { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage } from 'electron'; import TrayIconManager from './lib/tray-icon-manager'; import ElectronSudo from 'electron-sudo'; import shellescape from 'shell-escape'; @@ -18,7 +18,6 @@ import uuid from 'uuid'; import type { TrayIconType } from './lib/tray-icon-manager'; const isDevelopment = (process.env.NODE_ENV === 'development'); -const isMacOS = (process.platform === 'darwin'); // The name for application directory used for // scoping logs and user data in platform special folders @@ -73,13 +72,15 @@ const appDelegate = { // 1. https://github.com/electron/electron/issues/10118 // 2. https://github.com/electron/electron/pull/10191 _getLogsDirectory: () => { - // macOS: ~/Library/Logs/{appname} - if(isMacOS) { + switch(process.platform) { + case 'darwin': + // macOS: ~/Library/Logs/{appname} return path.join(app.getPath('home'), 'Library/Logs', appDirectoryName); + default: + // Linux: ~/.config/{appname}/logs + // Windows: ~\AppData\Roaming\{appname}\logs + return path.join(app.getPath('userData'), 'logs'); } - // Linux: ~/.config/{appname}/logs - // Windows: ~\AppData\Roaming\{appname}\logs - return path.join(app.getPath('userData'), 'logs'); }, onReady: async () => { @@ -90,9 +91,8 @@ const appDelegate = { appDelegate._pollForConnectionInfoFile(); }); - ipcMain.on('show-window', () => { - appDelegate._showWindow(window, appDelegate._tray); - }); + ipcMain.on('show-window', () => appDelegate._showWindow(window, appDelegate._tray)); + ipcMain.on('hide-window', () => window.hide()); window.loadURL('file://' + path.join(__dirname, 'index.html')); window.on('close', () => { @@ -138,13 +138,8 @@ const appDelegate = { }); }); - // create tray icon on macOS - if(isMacOS) { - appDelegate._tray = appDelegate._createTray(window); - } else { - appDelegate._showWindow(window, null); - } - + // create tray icon + appDelegate._tray = appDelegate._createTray(window); appDelegate._setAppMenu(); appDelegate._addContextMenu(window); @@ -301,17 +296,32 @@ const appDelegate = { } }; - // setup window flags to mimic popover on macOS - if(isMacOS) { - const win = new BrowserWindow({ + switch(process.platform) { + case 'darwin': { + // setup window flags to mimic popover on macOS + const appWindow = new BrowserWindow({ ...options, - height: contentHeight + 12, // 12 is the size of transparent area around arrow + // 12 is the size of transparent area around arrow + height: contentHeight + 12, frame: false, transparent: true }); - win.setVisibleOnAllWorkspaces(true); - return win; - } else { + + // make the window visible on all workspaces + appWindow.setVisibleOnAllWorkspaces(true); + + return appWindow; + } + + case 'win32': + // setup window flags to mimic an overlay window + return new BrowserWindow({ + ...options, + frame: false, + transparent: true + }); + + default: return new BrowserWindow(options); } }, @@ -395,17 +405,77 @@ const appDelegate = { window.focus(); }, + _getTrayPlacement: () => { + switch(process.platform) { + case 'darwin': + // macOS has menubar always placed at the top + return 'top'; + + case 'win32': { + // taskbar occupies some part of the screen excluded from work area + const primaryDisplay = electron.screen.getPrimaryDisplay(); + const displaySize = primaryDisplay.size; + const workArea = primaryDisplay.workArea; + + if(workArea.width < displaySize.width) { + return workArea.x > 0 ? 'left' : 'right'; + } else if(workArea.height < displaySize.height) { + return workArea.y > 0 ? 'top' : 'bottom'; + } else { + return 'none'; + } + } + + default: + return 'none'; + } + }, + _getWindowPosition: (window: BrowserWindow, tray: Tray): { x: number, y: number } => { const windowBounds = window.getBounds(); const trayBounds = tray.getBounds(); - // center window horizontally below the tray icon - const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2)); + const primaryDisplay = electron.screen.getPrimaryDisplay(); + const workArea = primaryDisplay.workArea; + const placement = appDelegate._getTrayPlacement(); + const maxX = workArea.x + workArea.width - windowBounds.width; + const maxY = workArea.y + workArea.height - windowBounds.height; - // position window vertically below the tray icon - const y = Math.round(trayBounds.y + trayBounds.height); + let x = 0, y = 0; + switch(placement) { + case 'top': + x = trayBounds.x + (trayBounds.width - windowBounds.width) * 0.5; + y = trayBounds.y + trayBounds.height; + break; - return { x, y }; + case 'bottom': + x = trayBounds.x + (trayBounds.width - windowBounds.width) * 0.5; + y = trayBounds.y - windowBounds.height; + break; + + case 'left': + x = trayBounds.x + trayBounds.width; + y = trayBounds.y + (trayBounds.height - windowBounds.height) * 0.5; + break; + + case 'right': + x = trayBounds.x - windowBounds.width; + y = trayBounds.y + (trayBounds.height - windowBounds.height) * 0.5; + break; + + case 'none': + x = workArea.x + (workArea.width - windowBounds.width) * 0.5; + y = workArea.y + (workArea.height - windowBounds.height) * 0.5; + break; + } + + x = Math.min(Math.max(x, workArea.x), maxX); + y = Math.min(Math.max(y, workArea.y), maxY); + + return { + x: Math.round(x), + y: Math.round(y) + }; }, _createTray: (window: BrowserWindow): Tray => { @@ -413,20 +483,24 @@ const appDelegate = { tray.setHighlightMode('never'); tray.on('click', () => appDelegate._toggleWindow(window, tray)); + const trayIconManager = new TrayIconManager(tray, 'unsecured'); + // setup NSEvent monitor to fix inconsistent window.blur // see https://github.com/electron/electron/issues/8689 // $FlowFixMe: this module is only available on macOS - const { NSEventMonitor, NSEventMask } = require('nseventmonitor'); - const trayIconManager = new TrayIconManager(tray, 'unsecured'); - const macEventMonitor = new NSEventMonitor(); - const eventMask = NSEventMask.leftMouseDown | NSEventMask.rightMouseDown; + if(process.platform === 'darwin') { + const { NSEventMonitor, NSEventMask } = require('nseventmonitor'); + const macEventMonitor = new NSEventMonitor(); + const eventMask = NSEventMask.leftMouseDown | NSEventMask.rightMouseDown; + + window.on('show', () => macEventMonitor.start(eventMask, () => window.hide())); + window.on('hide', () => macEventMonitor.stop()); + } // add IPC handler to change tray icon from renderer ipcMain.on('changeTrayIcon', (_: Event, type: TrayIconType) => trayIconManager.iconType = type); // setup event handlers - window.on('show', () => macEventMonitor.start(eventMask, () => window.hide())); - window.on('hide', () => macEventMonitor.stop()); window.on('close', () => window.closeDevTools()); window.on('blur', () => !window.isDevToolsOpened() && window.hide()); |
