diff --git a/app/index.js b/app/index.js index 07b72cad..596328a6 100644 --- a/app/index.js +++ b/app/index.js @@ -139,7 +139,7 @@ app.on('ready', () => installDevExtensions(isDev).then(() => { backgroundColor: toElectronBackgroundColor(cfg.backgroundColor || '#000'), // we want to go frameless on windows and linux frame: process.platform === 'darwin', - transparent: true, + transparent: process.platform === 'darwin', icon: resolve(__dirname, 'static/icon.png'), // we only want to show when the prompt is ready for user input // HYPERTERM_DEBUG for backwards compatibility with hyperterm @@ -346,6 +346,13 @@ app.on('ready', () => installDevExtensions(isDev).then(() => { pluginsUnsubscribe(); }); + // Same deal as above, grabbing the window titlebar when the window + // is maximized on Windows results in unmaximize, without hitting any + // app buttons + for (const ev of ['maximize', 'unmaximize', 'minimize', 'restore']) { + win.on(ev, () => rpc.emit('windowGeometry change')); + } + win.on('closed', () => { if (process.platform !== 'darwin' && windowSet.size === 0) { app.quit(); diff --git a/assets/icons.svg b/assets/icons.svg index 71a7b8e0..02dc8152 100644 --- a/assets/icons.svg +++ b/assets/icons.svg @@ -34,6 +34,19 @@ + + restore window + + + + + + + + + + close window diff --git a/lib/actions/ui.js b/lib/actions/ui.js index 8c32cd0d..f9b46c28 100644 --- a/lib/actions/ui.js +++ b/lib/actions/ui.js @@ -24,6 +24,7 @@ import { UI_MOVE_NEXT_PANE, UI_MOVE_PREV_PANE, UI_SHOW_PREFERENCES, + UI_WINDOW_GEOMETRY_CHANGED, UI_WINDOW_MOVE, UI_OPEN_FILE } from '../constants/ui'; @@ -88,6 +89,12 @@ export function setFontSmoothing() { }; } +export function windowGeometryUpdated() { + return { + type: UI_WINDOW_GEOMETRY_CHANGED + }; +} + // Find all sessions that are below the given // termGroup uid in the hierarchy: const findChildSessions = (termGroups, uid) => { @@ -246,6 +253,17 @@ export function windowMove() { }; } +export function windowGeometryChange() { + return dispatch => { + dispatch({ + type: UI_WINDOW_MOVE, + effect() { + dispatch(setFontSmoothing()); + } + }); + }; +} + export function openFile(path) { return dispatch => { dispatch({ diff --git a/lib/components/header.js b/lib/components/header.js index 35a39548..dd6f0448 100644 --- a/lib/components/header.js +++ b/lib/components/header.js @@ -12,7 +12,6 @@ export default class Header extends Component { constructor() { super(); this.onChangeIntent = this.onChangeIntent.bind(this); - this.handleHeaderClick = this.handleHeaderClick.bind(this); this.handleHeaderMouseDown = this.handleHeaderMouseDown.bind(this); this.handleHamburgerMenuClick = this.handleHamburgerMenuClick.bind(this); this.handleMaximizeClick = this.handleMaximizeClick.bind(this); @@ -43,35 +42,6 @@ export default class Header extends Component { this.headerMouseDownWindowY = window.screenY; } - handleHeaderClick(event) { - this.clicks = this.clicks || 0; - - // Reset clicks if mouse moved between clicks - if (this.headerClickPointerX !== event.clientX || - this.headerClickPointerY !== event.clientY) { - this.clicks = 0; - clearTimeout(this.clickTimer); - - this.headerClickPointerX = event.clientX; - this.headerClickPointerY = event.clientY; - } - if (++this.clicks === 2) { - if (this.props.maximized) { - this.props.unmaximize(); - } else { - this.props.maximize(); - } - this.clicks = 0; - clearTimeout(this.clickTimer); - } else { - // http://www.quirksmode.org/dom/events/click.html - // https://en.wikipedia.org/wiki/Double-click - this.clickTimer = setTimeout(() => { - this.clicks = 0; - }, 500); - } - } - handleHamburgerMenuClick(event) { let {right: x, bottom: y} = event.currentTarget.getBoundingClientRect(); x -= 15; // to compensate padding @@ -135,9 +105,12 @@ export default class Header extends Component { } const {hambMenu, winCtrls} = this.getWindowHeaderConfig(); const left = winCtrls === 'left'; + const maxButtonHref = this.props.maximized ? + './dist/assets/icons.svg#restore-window' : + './dist/assets/icons.svg#maximize-window'; + return ( { @@ -169,7 +142,7 @@ export default class Header extends Component { className={css('shape', left && 'maximizeWindowLeft')} onClick={this.handleMaximizeClick} > - + @@ -139,7 +142,8 @@ const HyperContainer = connect( customCSS: state.ui.css, borderColor: state.ui.borderColor, activeSession: state.sessions.activeUid, - backgroundColor: state.ui.backgroundColor + backgroundColor: state.ui.backgroundColor, + maximized: state.ui.maximized }; }, dispatch => { diff --git a/lib/index.js b/lib/index.js index b251c5ea..ca00cb58 100644 --- a/lib/index.js +++ b/lib/index.js @@ -120,6 +120,10 @@ rpc.on('move', () => { store_.dispatch(uiActions.windowMove()); }); +rpc.on('windowGeometry change', () => { + store_.dispatch(uiActions.windowGeometryUpdated()); +}); + rpc.on('add notification', ({text, url, dismissable}) => { store_.dispatch(addNotificationMessage(text, url, dismissable)); }); diff --git a/lib/reducers/ui.js b/lib/reducers/ui.js index 4084dfb9..cfe5daee 100644 --- a/lib/reducers/ui.js +++ b/lib/reducers/ui.js @@ -1,3 +1,4 @@ +import {remote} from 'electron'; import Immutable from 'seamless-immutable'; import {decorateUIReducer} from '../utils/plugins'; import {CONFIG_LOAD, CONFIG_RELOAD} from '../constants/config'; @@ -6,7 +7,8 @@ import { UI_FONT_SIZE_RESET, UI_FONT_SMOOTHING_SET, UI_WINDOW_MAXIMIZE, - UI_WINDOW_UNMAXIMIZE + UI_WINDOW_UNMAXIMIZE, + UI_WINDOW_GEOMETRY_CHANGED } from '../constants/ui'; import {NOTIFICATION_MESSAGE, NOTIFICATION_DISMISS} from '../constants/notifications'; import { @@ -86,8 +88,11 @@ const initial = Immutable({ showWindowControls: '' }); +const currentWindow = remote.getCurrentWindow(); + const reducer = (state = initial, action) => { let state_ = state; + let isMax; switch (action.type) { // eslint-disable-line default-case case CONFIG_LOAD: @@ -284,6 +289,14 @@ const reducer = (state = initial, action) => { state_ = state.set('maximized', false); break; + case UI_WINDOW_GEOMETRY_CHANGED: + isMax = currentWindow.isMaximized(); + if (state.maximized !== isMax) { + state_ = state.set('maximized', isMax); + } + + break; + case NOTIFICATION_DISMISS: state_ = state.merge({ notifications: {